diff mbox

C++ PATCH to support non-constexpr variable templates

Message ID 53FB305E.1040901@redhat.com
State New
Headers show

Commit Message

Jason Merrill Aug. 25, 2014, 12:47 p.m. UTC
On 08/25/2014 05:24 AM, Ville Voutilainen wrote:
> Well, it's a bit premature to add tests when the implementation itself is not
> quite complete, I guess. :) Having ICEs makes it hard to add tests, too. :P

But tests are how you verify that the implementation is complete.

Anyway, here's a fix for your recent test.

Comments

Ville Voutilainen Aug. 25, 2014, 2:08 p.m. UTC | #1
On Mon Aug 25 2014 15:47:26 GMT+0300 (EEST), Jason Merrill wrote:
> On 08/25/2014 05:24 AM, Ville Voutilainen wrote:

> > Well, it's a bit premature to add tests when the implementation itself is not

> > quite complete, I guess. :) Having ICEs makes it hard to add tests, too. :P

> 

> But tests are how you verify that the implementation is complete.

> 

> Anyway, here's a fix for your recent test.

 
Thanks, I'll take a look at the tests and will send a patch if something seems missing; static member variable templates of a class template and explicit specializations thereof are the likely starting point.
Ville Voutilainen Aug. 25, 2014, 7:15 p.m. UTC | #2
On 25 August 2014 17:08,  <ville.voutilainen@gmail.com> wrote:
>> Anyway, here's a fix for your recent test.
>
> Thanks, I'll take a look at the tests and will send a patch if something seems missing; static member variable templates of a class template and explicit specializations thereof are the likely starting point.

Another ICE (should we just add these test-for-valid cases as new
tests? Or should they become
bug reports instead? Please advise how to best handle these.):

template <class T>
struct Y
{
  template <class U> static U x;
};

template <class T>
template <class U>
U Y<T>::x = U();

int main()
{
  int y = Y<int>::x<int>;
}

variable-template.cpp:9:3: warning: too many template headers for
Y<T>::x (should be 1)
 U Y<T>::x = U();
   ^
variable-template.cpp: In instantiation of ‘int Y<int>::x’:
variable-template.cpp:13:19:   required from here
variable-template.cpp:13:19: internal compiler error: in
template_for_substitution, at cp/pt.c:19714
   int y = Y<int>::x<int>;
                   ^
0x5c4bf9 template_for_substitution(tree_node*)
    ../../gcc/cp/pt.c:19714
0x5d0874 instantiate_decl(tree_node*, int, bool)
    ../../gcc/cp/pt.c:19891
0x6521c2 mark_used(tree_node*, int)
    ../../gcc/cp/decl2.c:5035
0x707f5b finish_id_expression(tree_node*, tree_node*, tree_node*,
cp_id_kind*, bool, bool, bool*, bool, bool, bool, bool, char const**,
unsigned int)
    ../../gcc/cp/semantics.c:3515
0x67f13b cp_parser_primary_expression
    ../../gcc/cp/parser.c:4654
0x6804e7 cp_parser_postfix_expression
    ../../gcc/cp/parser.c:6008
0x6832b9 cp_parser_unary_expression
    ../../gcc/cp/parser.c:7285
0x683ef4 cp_parser_binary_expression
    ../../gcc/cp/parser.c:8028
0x68449b cp_parser_assignment_expression
    ../../gcc/cp/parser.c:8270
0x684935 cp_parser_assignment_expression
    ../../gcc/cp/parser.c:8320
0x684935 cp_parser_constant_expression
    ../../gcc/cp/parser.c:8524
0x69557e cp_parser_init_declarator
    ../../gcc/cp/parser.c:16996
0x696b65 cp_parser_simple_declaration
    ../../gcc/cp/parser.c:11406
0x67a6a3 cp_parser_block_declaration
    ../../gcc/cp/parser.c:11287
0x67b821 cp_parser_declaration_statement
    ../../gcc/cp/parser.c:10934
0x67bf0b cp_parser_statement
    ../../gcc/cp/parser.c:9649
0x67cd39 cp_parser_statement_seq_opt
    ../../gcc/cp/parser.c:9927
0x67cea6 cp_parser_compound_statement
    ../../gcc/cp/parser.c:9881
0x68e11b cp_parser_function_body
    ../../gcc/cp/parser.c:18952
0x68e11b cp_parser_ctor_initializer_opt_and_function_body
    ../../gcc/cp/parser.c:18988
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.
Jason Merrill Aug. 26, 2014, 12:10 a.m. UTC | #3
On 08/25/2014 03:15 PM, Ville Voutilainen wrote:
> should we just add these test-for-valid cases as new
> tests? Or should they become
> bug reports instead? Please advise how to best handle these.

Bug reports, please.  Or perhaps multiple testcases on one bug report, 
for now.  :)

Jason
diff mbox

Patch

commit e79c51a68ae5ace45a191bf95350a68c7ce386d3
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Aug 25 00:17:55 2014 -0400

    	* decl.c (start_decl): Look through member variable template.
    	* pt.c (tsubst_decl) [VAR_DECL]: Handle member variable templates.
    	* decl2.c (grokfield): Set DECL_CONTEXT earlier on
    	variables.

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index e83192a..80696dd 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4650,13 +4650,37 @@  start_decl (const cp_declarator *declarator,
 
   if (TYPE_P (context) && COMPLETE_TYPE_P (complete_type (context)))
     {
+      bool this_tmpl = (processing_template_decl
+			> template_class_depth (context));
       if (VAR_P (decl))
 	{
 	  tree field = lookup_field (context, DECL_NAME (decl), 0, false);
-	  if (field == NULL_TREE || !VAR_P (field))
-	    error ("%q#D is not a static member of %q#T", decl, context);
+	  if (field == NULL_TREE
+	      || !(VAR_P (field) || variable_template_p (field)))
+	    error ("%q+#D is not a static data member of %q#T", decl, context);
 	  else
 	    {
+	      if (variable_template_p (field))
+		{
+		  if (!this_tmpl)
+		    {
+		      error_at (DECL_SOURCE_LOCATION (decl),
+				"non-member-template declaration of %qD", decl);
+		      inform (DECL_SOURCE_LOCATION (field), "does not match "
+			      "member template declaration here");
+		      return error_mark_node;
+		    }
+		  field = DECL_TEMPLATE_RESULT (field);
+		}
+	      else if (this_tmpl)
+		{
+		  error_at (DECL_SOURCE_LOCATION (decl),
+			    "member template declaration of %qD", decl);
+		  inform (DECL_SOURCE_LOCATION (field), "does not match "
+			  "non-member-template declaration here");
+		  return error_mark_node;
+		}
+
 	      if (DECL_CONTEXT (field) != context)
 		{
 		  if (!same_type_p (DECL_CONTEXT (field), context))
@@ -4683,8 +4707,7 @@  start_decl (const cp_declarator *declarator,
       else
 	{
 	  tree field = check_classfn (context, decl,
-				      (processing_template_decl
-				       > template_class_depth (context))
+				      this_tmpl
 				      ? current_template_parms
 				      : NULL_TREE);
 	  if (field && field != error_mark_node
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 74a10fb..5b1313e 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -994,6 +994,10 @@  grokfield (const cp_declarator *declarator,
       && DECL_CONTEXT (value) != current_class_type)
     return value;
 
+  /* Need to set this before push_template_decl.  */
+  if (TREE_CODE (value) == VAR_DECL)
+    DECL_CONTEXT (value) = current_class_type;
+
   if (processing_template_decl && VAR_OR_FUNCTION_DECL_P (value))
     {
       value = push_template_decl (value);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index a40f9d2..3e6d777 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11127,13 +11127,12 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 		   same_type_p, because DECL_CONTEXT is always
 		   canonical...  */
 		if (ctx == DECL_CONTEXT (t)
-		    && (TREE_CODE (t) != TYPE_DECL
-			/* ... unless T is a member template; in which
-			   case our caller can be willing to create a
-			   specialization of that template represented
-			   by T.  */
-			|| !(DECL_TI_TEMPLATE (t)
-			     && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (t)))))
+		    /* ... unless T is a member template; in which
+		       case our caller can be willing to create a
+		       specialization of that template represented
+		       by T.  */
+		    && !(DECL_TI_TEMPLATE (t)
+			 && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (t))))
 		  spec = t;
 	      }
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr60626.C b/gcc/testsuite/g++.dg/cpp1y/pr60626.C
index 686db73..3114644 100644
--- a/gcc/testsuite/g++.dg/cpp1y/pr60626.C
+++ b/gcc/testsuite/g++.dg/cpp1y/pr60626.C
@@ -4,4 +4,4 @@ 
 
 struct A {};
 
-void (*A::p)(auto) = 0;  // { dg-error "static member|template" }
+void (*A::p)(auto) = 0;  // { dg-error "static data member|template" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ8.C b/gcc/testsuite/g++.dg/cpp1y/var-templ8.C
new file mode 100644
index 0000000..8e3d34a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ8.C
@@ -0,0 +1,15 @@ 
+// { dg-do compile { target c++14 } }
+// { dg-final { scan-assembler "_ZN1X1xIiEE" } }
+
+struct X
+{
+  template <class T> static T x;
+};
+
+template <class T>
+T X::x = T();
+
+int main()
+{
+  int x = X::x<int>;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ9.C b/gcc/testsuite/g++.dg/cpp1y/var-templ9.C
new file mode 100644
index 0000000..2ffb007
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ9.C
@@ -0,0 +1,15 @@ 
+// { dg-do compile { target c++14 } }
+
+struct X
+{
+  template <class T> static int x;
+};
+
+int X::x = 42;			// { dg-error "template" }
+
+struct Y
+{
+  static int y;
+};
+
+template <class T> int Y::y = 42; // { dg-error "template" }