diff mbox

Patch for constexpr variable templates

Message ID 53DB6A37.3040703@maniacsvault.net
State New
Headers show

Commit Message

Braden Obrzut Aug. 1, 2014, 10:21 a.m. UTC
On 07/31/2014 08:53 AM, Jason Merrill wrote:
> In the original mail you mentioned doing it in cp_parser_template_id; 
> I agree that we probably don't want to do it there because of the 
> complications you are seeing.  I was thinking about doing it when we 
> normally resolve an id-expression that refers to a variable, once we 
> know we're looking at an expression and not a declarator-id.  But I 
> think my suggestion of cp_parser_id_expression was wrong, and it would 
> be better in finish_id_expression.
>
> Jason
>
Ahh sorry, I misread the function name you gave. finish_id_expression 
works just fine and doesn't require any extra work.  How does this patch 
look?

- Braden Obrzut

2014-08-01  Braden Obrzut  <admin@maniacsvault.net>

     * decl.c (grokvardecl): Handle specializations of variable templates.
     (grokdeclarator): Handle variable template id expressions and NULL_TREE
     return from grokvardecl.
     * decl2.c (check_member_template): Allow declaration of template member
     variables.
     * parser.c (cp_parser_template_id): Build a TEMPLATE_ID_EXPR for
     variable templates.
     * pt.c (determine_specialization): Accept variable templates.
     (check_template_variable): Fixed wanted template header count and
     change non static data member error to variable template warning.
     (check_explicit_specialization): Handle and check for malformed
     variable template specializations.
     (lookup_template_variable): New.
     (tsubst_decl): Handle variable template specializations.
     (do_decl_instantiation): Handle template variables.
     (instantiate_decl): Handle template variables.
     * semantics.c (finish_template_variable): New.
     (finish_id_expression): Instantiate variable templates.

2014-08-01  Braden Obrzut  <admin@maniacsvault.net>

     * g++.dg/cpp1y/var-templ1.C: New.
     * g++.dg/cpp1y/var-templ2.C: New.
     * g++.dg/cpp1y/var-templ3.C: New.
     * g++.dg/cpp1y/var-templ4.C: New.
     * g++.dg/cpp1y/var-templ5.C: New.
     * g++.dg/cpp1y/pr59638.C: Marked xfail for template variables as
     function pointers taking auto are considered templates at the moment.
     * g++.dg/parse/error50.C: Malformed statements look like variable 
templ.
     * g++.dg/template/crash71.C: Looks like variable templ.
     * g++.old-deja/g++.oliva/template10.C: Looks like variable templ.
     * g++.old-deja/g++.pt/var1.C: Non-constexpr variable templ.

2013-03-29  Gabriel Dos Reis  <gdr@integrable-solutions.net>

     * cp-tree.h (variable_template_p): Do not check scope.
     * pt.c (check_template_variable): Fix thinko from previous change.
     (push_template_decl_real): Fix formatting.


2013-03-29  Gabriel Dos Reis  <gdr@integrable-solutions.net>

     * cp-tree.h (variable_template_p): New.
     * pt.c (check_template_variable): Accept variable temploids at
     non-class scope.
     (push_template_decl_real): The current instantiation of a template
     can be a VAR_DECL.

Comments

Jason Merrill Aug. 5, 2014, 6:26 p.m. UTC | #1
Applied with a few formatting/comment tweaks, thanks!

Jason
Paolo Carlini Aug. 5, 2014, 8:06 p.m. UTC | #2
Hi,

On 08/05/2014 08:26 PM, Jason Merrill wrote:
> Applied with a few formatting/comment tweaks, thanks!
Great. I will double check but var-templ4.C fails for me with an ICE. 
Can anybody reproduce?

Thanks!
Paolo.

////////////////

/.../gcc/testsuite/g++.dg/cpp1y/var-templ4.C:8:17: internal compiler 
error: tree check: expected function_decl, have var_decl in 
check_explicit_specialization, at cp/pt.c:2822
0xde05a4 tree_check_failed(tree_node const*, char const*, int, char 
const*, ...)
     ../../trunk/gcc/tree.c:9174
0x5f9dd9 tree_check(tree_node*, char const*, int, char const*, tree_code)
     ../../trunk/gcc/tree.h:2729
0x5f9dd9 check_explicit_specialization(tree_node*, tree_node*, int, int)
     ../../trunk/gcc/cp/pt.c:2822
0x5af6e1 grokvardecl
     ../../trunk/gcc/cp/decl.c:8079
0x5af6e1 grokdeclarator(cp_declarator const*, cp_decl_specifier_seq*, 
decl_context, int, tree_node**)
     ../../trunk/gcc/cp/decl.c:10918
0x5b24b4 start_decl(cp_declarator const*, cp_decl_specifier_seq*, int, 
tree_node*, tree_node*, tree_node**)
     ../../trunk/gcc/cp/decl.c:4572
0x68ff5f cp_parser_init_declarator
     ../../trunk/gcc/cp/parser.c:16920
0x690b0a cp_parser_single_declaration
     ../../trunk/gcc/cp/parser.c:23494
0x69160d cp_parser_explicit_specialization
     ../../trunk/gcc/cp/parser.c:14418
0x69bfaf cp_parser_declaration
     ../../trunk/gcc/cp/parser.c:11152
0x69ab18 cp_parser_declaration_seq_opt
     ../../trunk/gcc/cp/parser.c:11085
0x69c3b3 cp_parser_translation_unit
     ../../trunk/gcc/cp/parser.c:4061
0x69c3b3 c_parse_file()
     ../../trunk/gcc/cp/parser.c:31954
0x7c0712 c_common_parse_file()
     ../../trunk/gcc/c-family/c-opts.c:1115
Braden Obrzut Aug. 6, 2014, 4:41 a.m. UTC | #3
I can confirm that this is caused by a change to pt.c that happened, I 
think, the day before my last patch.

This can be fixed by first checking that the template is a function 
template at that line in pt.c.  Since variable templates can't be 
friends, it might also be suitable to skip that entire block if it is a 
function template.

Should I submit that as a patch?

- Braden Obrzut

On 08/05/2014 04:06 PM, Paolo Carlini wrote:
> Hi,
>
> On 08/05/2014 08:26 PM, Jason Merrill wrote:
>> Applied with a few formatting/comment tweaks, thanks!
> Great. I will double check but var-templ4.C fails for me with an ICE. 
> Can anybody reproduce?
>
> Thanks!
> Paolo.
>
> ////////////////
>
> /.../gcc/testsuite/g++.dg/cpp1y/var-templ4.C:8:17: internal compiler 
> error: tree check: expected function_decl, have var_decl in 
> check_explicit_specialization, at cp/pt.c:2822
> 0xde05a4 tree_check_failed(tree_node const*, char const*, int, char 
> const*, ...)
>     ../../trunk/gcc/tree.c:9174
> 0x5f9dd9 tree_check(tree_node*, char const*, int, char const*, tree_code)
>     ../../trunk/gcc/tree.h:2729
> 0x5f9dd9 check_explicit_specialization(tree_node*, tree_node*, int, int)
>     ../../trunk/gcc/cp/pt.c:2822
> 0x5af6e1 grokvardecl
>     ../../trunk/gcc/cp/decl.c:8079
> 0x5af6e1 grokdeclarator(cp_declarator const*, cp_decl_specifier_seq*, 
> decl_context, int, tree_node**)
>     ../../trunk/gcc/cp/decl.c:10918
> 0x5b24b4 start_decl(cp_declarator const*, cp_decl_specifier_seq*, int, 
> tree_node*, tree_node*, tree_node**)
>     ../../trunk/gcc/cp/decl.c:4572
> 0x68ff5f cp_parser_init_declarator
>     ../../trunk/gcc/cp/parser.c:16920
> 0x690b0a cp_parser_single_declaration
>     ../../trunk/gcc/cp/parser.c:23494
> 0x69160d cp_parser_explicit_specialization
>     ../../trunk/gcc/cp/parser.c:14418
> 0x69bfaf cp_parser_declaration
>     ../../trunk/gcc/cp/parser.c:11152
> 0x69ab18 cp_parser_declaration_seq_opt
>     ../../trunk/gcc/cp/parser.c:11085
> 0x69c3b3 cp_parser_translation_unit
>     ../../trunk/gcc/cp/parser.c:4061
> 0x69c3b3 c_parse_file()
>     ../../trunk/gcc/cp/parser.c:31954
> 0x7c0712 c_common_parse_file()
>     ../../trunk/gcc/c-family/c-opts.c:1115
Paolo Carlini Aug. 6, 2014, 7:04 a.m. UTC | #4
Hi,

On 08/06/2014 06:41 AM, Braden Obrzut wrote:
> I can confirm that this is caused by a change to pt.c that happened, I 
> think, the day before my last patch.
>
> This can be fixed by first checking that the template is a function 
> template at that line in pt.c.  Since variable templates can't be 
> friends, it might also be suitable to skip that entire block if it is 
> a function template.
Patch looks simple, then.
> Should I submit that as a patch?
I suppose Jason would be glad to review and apply it!

Thanks,
Paolo.
diff mbox

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 4a5cb98..caaaa6c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5027,6 +5027,17 @@  class_of_this_parm (const_tree fntype)
   return TREE_TYPE (type_of_this_parm (fntype));
 }
 
+/* True if T designates a variable template declaration.  */
+inline bool
+variable_template_p (tree t)
+{
+  if (TREE_CODE (t) != TEMPLATE_DECL)
+    return false;
+  if (tree r = DECL_TEMPLATE_RESULT (t))
+    return VAR_P (r);
+  return false;
+}
+
 /* A parameter list indicating for a function with no parameters,
    e.g  "int f(void)".  */
 extern cp_parameter_declarator *no_parameters;
@@ -5554,6 +5565,7 @@  extern bool redeclare_class_template		(tree, tree);
 extern tree lookup_template_class		(tree, tree, tree, tree,
 						 int, tsubst_flags_t);
 extern tree lookup_template_function		(tree, tree);
+extern tree lookup_template_variable		(tree, tree);
 extern int uses_template_parms			(tree);
 extern int uses_template_parms_level		(tree, int);
 extern bool in_template_function		(void);
@@ -5816,6 +5828,7 @@  extern tree perform_koenig_lookup		(tree, vec<tree, va_gc> *,
 						 tsubst_flags_t);
 extern tree finish_call_expr			(tree, vec<tree, va_gc> **, bool,
 						 bool, tsubst_flags_t);
+extern tree finish_template_variable	(tree);
 extern tree finish_increment_expr		(tree, enum tree_code);
 extern tree finish_this_expr			(void);
 extern tree finish_pseudo_destructor_expr       (tree, tree, tree, location_t);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index dae85c2..2ac0472 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -80,8 +80,8 @@  static int ambi_op_p (enum tree_code);
 static int unary_op_p (enum tree_code);
 static void push_local_name (tree);
 static tree grok_reference_init (tree, tree, tree, int);
-static tree grokvardecl (tree, tree, const cp_decl_specifier_seq *,
-			 int, int, tree);
+static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *,
+			 int, int, int, tree);
 static int check_static_variable_definition (tree, tree);
 static void record_unknown_type (tree, const char *);
 static tree builtin_function_1 (tree, tree, bool);
@@ -7943,9 +7943,11 @@  set_linkage_for_static_data_member (tree decl)
 static tree
 grokvardecl (tree type,
 	     tree name,
+	     tree orig_declarator,
 	     const cp_decl_specifier_seq *declspecs,
 	     int initialized,
 	     int constp,
+	     int template_count,
 	     tree scope)
 {
   tree decl;
@@ -7975,7 +7977,10 @@  grokvardecl (tree type,
 	  || (TREE_CODE (scope) == NAMESPACE_DECL
 	      && current_lang_name != lang_name_cplusplus)
 	  /* Similarly for static data members.  */
-	  || TYPE_P (scope)))
+	  || TYPE_P (scope)
+	  /* Similarly for explicit specializations.  */
+	  || (orig_declarator
+	      && TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR)))
     decl = build_lang_decl (VAR_DECL, name, type);
   else
     decl = build_decl (input_location, VAR_DECL, name, type);
@@ -8043,7 +8048,14 @@  grokvardecl (tree type,
   else
     DECL_INTERFACE_KNOWN (decl) = 1;
 
-  return decl;
+  // Handle explicit specializations and instantiations of variable templates.
+  if (orig_declarator)
+    {
+      decl = check_explicit_specialization (orig_declarator, decl,
+                                            template_count, 0);
+    }
+
+  return decl != error_mark_node ? decl : NULL_TREE;
 }
 
 /* Create and return a canonical pointer to member function type, for
@@ -8944,8 +8956,13 @@  grokdeclarator (const cp_declarator *declarator,
 		  dname = fns;
 		  if (!identifier_p (dname))
 		    {
-		      gcc_assert (is_overloaded_fn (dname));
-		      dname = DECL_NAME (get_first_fn (dname));
+		      if (variable_template_p (dname))
+		          dname = DECL_NAME (dname);
+		      else
+		        {
+		          gcc_assert (is_overloaded_fn (dname));
+		          dname = DECL_NAME (get_first_fn (dname));
+		        }
 		    }
 		}
 		/* Fall through.  */
@@ -9986,7 +10003,8 @@  grokdeclarator (const cp_declarator *declarator,
 
   if (unqualified_id && TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR
       && TREE_CODE (type) != FUNCTION_TYPE
-      && TREE_CODE (type) != METHOD_TYPE)
+      && TREE_CODE (type) != METHOD_TYPE
+      && !variable_template_p (TREE_OPERAND (unqualified_id, 0)))
     {
       error ("template-id %qD used as a declarator",
 	     unqualified_id);
@@ -10876,11 +10894,15 @@  grokdeclarator (const cp_declarator *declarator,
 	/* It's a variable.  */
 
 	/* An uninitialized decl with `extern' is a reference.  */
-	decl = grokvardecl (type, unqualified_id,
+	decl = grokvardecl (type, dname, unqualified_id,
 			    declspecs,
 			    initialized,
 			    (type_quals & TYPE_QUAL_CONST) != 0,
+			    template_count,
 			    ctype ? ctype : in_namespace);
+	if (decl == NULL_TREE)
+	  return error_mark_node;
+
 	bad_specifiers (decl, BSP_VAR, virtualp,
 			memfn_quals != TYPE_UNQUALIFIED,
 			inlinep, friendp, raises != NULL_TREE);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 0926dbc..5f4a644 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -529,6 +529,8 @@  check_member_template (tree tmpl)
 	 with member templates.  */
       DECL_IGNORED_P (tmpl) = 1;
     }
+  else if (variable_template_p (tmpl))
+    /* OK */;
   else
     error ("template declaration of %q#D", decl);
 }
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 72f987e..2551e06 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -13558,6 +13558,10 @@  cp_parser_template_id (cp_parser *parser,
       template_id
 	= finish_template_type (templ, arguments, entering_scope);
     }
+  else if (variable_template_p (templ))
+    {
+      template_id = lookup_template_variable (templ, arguments);
+    }
   else
     {
       /* If it's not a class-template or a template-template, it should be
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7b79280..2d8a689 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -1878,11 +1878,16 @@  determine_specialization (tree template_id,
   if (BASELINK_P (fns))
     fns = BASELINK_FUNCTIONS (fns);
 
-  if (!is_overloaded_fn (fns))
+  if (TREE_CODE (decl) == FUNCTION_DECL && !is_overloaded_fn (fns))
     {
       error ("%qD is not a function template", fns);
       return error_mark_node;
     }
+  else if (VAR_P (decl) && !variable_template_p (fns))
+    {
+      error ("%qD is not a variable template", fns);
+      return error_mark_node;
+    }
 
   /* Count the number of template headers specified for this
      specialization.  */
@@ -1892,7 +1897,12 @@  determine_specialization (tree template_id,
        b = b->level_chain)
     ++header_count;
 
-  for (; fns; fns = OVL_NEXT (fns))
+  if (variable_template_p (fns))
+    {
+      templates = tree_cons (explicit_targs, fns, templates);
+    }
+  else
+    for (; fns; fns = OVL_NEXT (fns))
     {
       tree fn = OVL_CURRENT (fns);
 
@@ -2308,9 +2318,16 @@  check_template_variable (tree decl)
   tree ctx = CP_DECL_CONTEXT (decl);
   int wanted = num_template_headers_for_class (ctx);
   if (!TYPE_P (ctx) || !CLASSTYPE_TEMPLATE_INFO (ctx))
-    permerror (DECL_SOURCE_LOCATION (decl),
-	       "%qD is not a static data member of a class template", decl);
-  else if (template_header_count > wanted)
+    {
+      if (cxx_dialect < cxx1y)
+        pedwarn (DECL_SOURCE_LOCATION (decl), 0,
+                 "variable templates only available with "
+                 "-std=c++1y or -std=gnu++1y");
+
+      // Namespace-scope variable templates should have a template header.
+      ++wanted;
+    }
+  if (template_header_count > wanted)
     {
       bool warned = pedwarn (DECL_SOURCE_LOCATION (decl), 0,
 			     "too many template headers for %D (should be %d)",
@@ -2442,6 +2459,13 @@  check_explicit_specialization (tree declarator,
 
       /* Fall through.  */
     case tsk_expl_spec:
+      if (VAR_P (decl) && TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
+        {
+           // In cases like template<> constexpr bool v = true;
+           error ("%qD is not a template variable", dname);
+           break;
+        }
+
       SET_DECL_TEMPLATE_SPECIALIZATION (decl);
       if (ctype)
 	member_specialization = 1;
@@ -2481,7 +2505,10 @@  check_explicit_specialization (tree declarator,
       gcc_unreachable ();
     }
 
-  if (specialization || member_specialization)
+  if ((specialization || member_specialization)
+      /* Variable templates don't apply.  */
+      && (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE
+          || TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE))
     {
       tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
       for (; t; t = TREE_CHAIN (t))
@@ -2566,6 +2593,10 @@  check_explicit_specialization (tree declarator,
       else if (ctype != NULL_TREE
 	       && (identifier_p (TREE_OPERAND (declarator, 0))))
 	{
+	  // Ignore variable templates
+	  if (VAR_P (decl))
+	    return decl;
+
 	  /* Find the list of functions in ctype that have the same
 	     name as the declared function.  */
 	  tree name = TREE_OPERAND (declarator, 0);
@@ -2691,7 +2722,8 @@  check_explicit_specialization (tree declarator,
 	  /* If we thought that the DECL was a member function, but it
 	     turns out to be specializing a static member function,
 	     make DECL a static member function as well.  */
-	  if (DECL_STATIC_FUNCTION_P (tmpl)
+	  if (DECL_FUNCTION_TEMPLATE_P (tmpl)
+	      && DECL_STATIC_FUNCTION_P (tmpl)
 	      && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
 	    revert_static_member_fn (decl);
 
@@ -2725,7 +2757,8 @@  check_explicit_specialization (tree declarator,
 
 	  /* Inherit default function arguments from the template
 	     DECL is specializing.  */
-	  copy_default_args_to_explicit_spec (decl);
+	  if (DECL_FUNCTION_TEMPLATE_P (tmpl))
+	    copy_default_args_to_explicit_spec (decl);
 
 	  /* This specialization has the same protection as the
 	     template it specializes.  */
@@ -2794,6 +2827,7 @@  check_explicit_specialization (tree declarator,
 
 	  /* A 'structor should already have clones.  */
 	  gcc_assert (decl == error_mark_node
+		      || variable_template_p (tmpl)
 		      || !(DECL_CONSTRUCTOR_P (decl)
 			   || DECL_DESTRUCTOR_P (decl))
 		      || DECL_CLONED_FUNCTION_P (DECL_CHAIN (decl)));
@@ -4738,6 +4772,14 @@  push_template_decl_real (tree decl, bool is_friend)
 	       && TYPE_DECL_ALIAS_P (decl))
 	/* alias-declaration */
 	gcc_assert (!DECL_ARTIFICIAL (decl));
+      else if (VAR_P (decl))
+        {
+          if (!DECL_DECLARED_CONSTEXPR_P (decl))
+            {
+              sorry ("template declaration of non-constexpr variable %qD", decl);
+              return error_mark_node;
+            }
+        }
       else
 	{
 	  error ("template declaration of %q#D", decl);
@@ -7899,6 +7941,14 @@  lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
   timevar_pop (TV_TEMPLATE_INST);
   return ret;
 }
+
+/* Return a TEMPLATE_ID_EXPR for the given variable template and ARGLIST. */
+
+tree
+lookup_template_variable (tree templ, tree arglist)
+{
+  return build2 (TEMPLATE_ID_EXPR, TREE_TYPE (templ), templ, arglist);
+}
 
 struct pair_fn_data
 {
@@ -10466,7 +10516,7 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	if (PRIMARY_TEMPLATE_P (t))
 	  DECL_PRIMARY_TEMPLATE (r) = r;
 
-	if (TREE_CODE (decl) != TYPE_DECL)
+	if (TREE_CODE (decl) != TYPE_DECL && TREE_CODE (decl) != VAR_DECL)
 	  /* Record this non-type partial instantiation.  */
 	  register_specialization (r, t,
 				   DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),
@@ -19146,7 +19196,11 @@  do_decl_instantiation (tree decl, tree storage)
       error ("explicit instantiation of non-template %q#D", decl);
       return;
     }
-  else if (VAR_P (decl))
+
+  bool var_templ = (DECL_TEMPLATE_INFO (decl)
+                    && variable_template_p (DECL_TI_TEMPLATE (decl)));
+
+  if (VAR_P (decl) && !var_templ)
     {
       /* There is an asymmetry here in the way VAR_DECLs and
 	 FUNCTION_DECLs are handled by grokdeclarator.  In the case of
@@ -19175,7 +19229,7 @@  do_decl_instantiation (tree decl, tree storage)
 	  return;
 	}
     }
-  else if (TREE_CODE (decl) != FUNCTION_DECL)
+  else if (TREE_CODE (decl) != FUNCTION_DECL && !var_templ)
     {
       error ("explicit instantiation of %q#D", decl);
       return;
@@ -19885,10 +19939,12 @@  instantiate_decl (tree d, int defer_ok,
 	  tree ns;
 	  tree init;
 	  bool const_init = false;
+	  bool enter_context = DECL_CLASS_SCOPE_P (d);
 
 	  ns = decl_namespace_context (d);
 	  push_nested_namespace (ns);
-	  push_nested_class (DECL_CONTEXT (d));
+	  if (enter_context)
+	    push_nested_class (DECL_CONTEXT (d));
 	  init = tsubst_expr (DECL_INITIAL (code_pattern),
 			      args,
 			      tf_warning_or_error, NULL_TREE,
@@ -19900,7 +19956,8 @@  instantiate_decl (tree d, int defer_ok,
 	  cp_finish_decl (d, init, /*init_const_expr_p=*/const_init,
 			  /*asmspec_tree=*/NULL_TREE,
 			  LOOKUP_ONLYCONVERTING);
-	  pop_nested_class ();
+	  if (enter_context)
+	    pop_nested_class ();
 	  pop_nested_namespace (ns);
 	}
 
@@ -19997,10 +20054,15 @@  instantiate_decl (tree d, int defer_ok,
       DECL_EXTERNAL (d) = 0;
 
       /* Enter the scope of D so that access-checking works correctly.  */
-      push_nested_class (DECL_CONTEXT (d));
+      bool enter_context = DECL_CLASS_SCOPE_P (d);
+      if (enter_context)
+        push_nested_class (DECL_CONTEXT (d));
+
       const_init = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (code_pattern);
       cp_finish_decl (d, init, const_init, NULL_TREE, 0);
-      pop_nested_class ();
+
+      if (enter_context)
+        pop_nested_class ();
     }
   else if (TREE_CODE (d) == FUNCTION_DECL && DECL_DEFAULTED_FN (code_pattern))
     synthesize_method (d);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index a6d941b..5438608 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2418,6 +2418,15 @@  finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
   return result;
 }
 
+/* Instantiate a variable declaration from a TEMPLATE_ID_EXPR for use. */
+
+tree
+finish_template_variable (tree var)
+{
+  return instantiate_template (TREE_OPERAND (var, 0), TREE_OPERAND (var, 1),
+                               tf_error);
+}
+
 /* Finish a call to a postfix increment or decrement or EXPR.  (Which
    is indicated by CODE, which should be POSTINCREMENT_EXPR or
    POSTDECREMENT_EXPR.)  */
@@ -3500,6 +3509,11 @@  finish_id_expression (tree id_expression,
 	     a call to its wrapper.  */
 	  decl = build_cxx_call (wrap, 0, NULL, tf_warning_or_error);
 	}
+      else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
+	       && variable_template_p (TREE_OPERAND (decl, 0)))
+	{
+	  decl = finish_template_variable (decl);
+	}
       else if (scope)
 	{
 	  decl = (adjust_result_of_qualified_name_lookup
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr59638.C b/gcc/testsuite/g++.dg/cpp1y/pr59638.C
index 0125bdc..a4c63ac 100644
--- a/gcc/testsuite/g++.dg/cpp1y/pr59638.C
+++ b/gcc/testsuite/g++.dg/cpp1y/pr59638.C
@@ -1,10 +1,11 @@ 
 // PR c++/59638
 // { dg-do compile { target c++1y } }
 // { dg-options "" }
+// { dg-excess-errors "sorry" }
 
-void (*a)(auto);         // { dg-error "template declaration" }
+void (*a)(auto);         // { dg-error "" "" { xfail *-*-* } }
 
-void (*b)(auto) = 0;     // { dg-error "template declaration" }
+void (*b)(auto) = 0;     // { dg-error "" "" { xfail *-*-* } }
 
 typedef void (*f)(auto); // { dg-error "template declaration" }
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ1.C b/gcc/testsuite/g++.dg/cpp1y/var-templ1.C
new file mode 100644
index 0000000..9219303
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ1.C
@@ -0,0 +1,22 @@ 
+// { dg-do run }
+// { dg-options "-std=c++1y" }
+
+template<int A, int B>
+  struct S1
+  {
+    static constexpr int a = A;
+    static constexpr int b = B;
+  };
+
+template<typename T>
+  constexpr int var = T::a + T::b;
+
+int main ()
+{
+  int v = var<S1<199, 23>>/2;
+  return !(
+       var<S1<11, 100>> == v
+    && var<S1<50, 120>> == var<S1<150, var<S1<10, 10>>>>
+    && var<S1<53, 23>> != 222
+  );
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ2.C b/gcc/testsuite/g++.dg/cpp1y/var-templ2.C
new file mode 100644
index 0000000..315ac3e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ2.C
@@ -0,0 +1,34 @@ 
+// { dg-do compile }
+// { dg-options "-std=c++1y" }
+
+// Template variables and static member variables of template classes are
+// often confused.
+
+template<typename T>
+  struct S1
+  {
+    static int n;
+    static int arr[];
+  };
+
+template<typename T>
+  constexpr int var = sizeof (T);
+
+template<typename T>
+  int S1<T>::n = sizeof (T);
+
+template<typename T>
+  int S1<T>::arr[sizeof (T)];
+
+template<>
+  int S1<int>::n = 8;
+
+template<>
+  int S1<int>::arr[8];
+
+int main ()
+{
+  S1<int> v1;
+  var<S1<int>>;
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ3.C b/gcc/testsuite/g++.dg/cpp1y/var-templ3.C
new file mode 100644
index 0000000..d3fbad4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ3.C
@@ -0,0 +1,19 @@ 
+// { dg-do run }
+// { dg-options "-std=c++1y" }
+
+template<typename T>
+ constexpr int var = sizeof (T);
+
+template<typename T>
+  struct S1
+  {
+    template<typename U>
+    static constexpr int a = sizeof (U) + sizeof (T);
+  };
+
+int main ()
+{
+  return !(
+    var<int> + var<char> == S1<int>::a<char>
+  );
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ4.C b/gcc/testsuite/g++.dg/cpp1y/var-templ4.C
new file mode 100644
index 0000000..1d6cf1d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ4.C
@@ -0,0 +1,16 @@ 
+// { dg-do run }
+// { dg-options "-std=c++1y" }
+
+template<typename T>
+  constexpr int var = sizeof (T);
+
+template<>
+  constexpr int var<int> = 100000;
+
+int main ()
+{
+  return !(
+       var<int> == 100000
+    && var<char> == sizeof(char)
+  );
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ5.C b/gcc/testsuite/g++.dg/cpp1y/var-templ5.C
new file mode 100644
index 0000000..32d0ee1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ5.C
@@ -0,0 +1,23 @@ 
+// { dg-do run }
+// { dg-options "-std=c++1y" }
+
+template<int A, int B>
+  struct S1
+  {
+    static constexpr int a = A;
+    static constexpr int b = B;
+  };
+
+template<class T>
+  constexpr int var = T::a + T::b;
+
+template<template<int,int> class T, int A>
+  constexpr int var2 = var<T<A, A>> + A;
+
+int main ()
+{
+  return !(
+    var2<S1, 40> == 120
+  );
+}
+ 
diff --git a/gcc/testsuite/g++.dg/parse/error50.C b/gcc/testsuite/g++.dg/parse/error50.C
index dbd8958..f9c42dd 100644
--- a/gcc/testsuite/g++.dg/parse/error50.C
+++ b/gcc/testsuite/g++.dg/parse/error50.C
@@ -15,4 +15,4 @@  struct B
   static T i;
 };
 
-template<> template <> int B<int>::i; // { dg-error "should be 1" }
+template<> template <> int B<int>::i; // { dg-error "template|should be 1" }
diff --git a/gcc/testsuite/g++.dg/template/crash71.C b/gcc/testsuite/g++.dg/template/crash71.C
index 86aa152..3ac862e 100644
--- a/gcc/testsuite/g++.dg/template/crash71.C
+++ b/gcc/testsuite/g++.dg/template/crash71.C
@@ -1,3 +1,3 @@ 
 // PR c++/30659
 
-extern "C" template A<char> foo(); // { dg-error "forbids|static data|expected" }
+extern "C" template A<char> foo(); // { dg-error "forbids|static data|expected|template" }
diff --git a/gcc/testsuite/g++.old-deja/g++.oliva/template10.C b/gcc/testsuite/g++.old-deja/g++.oliva/template10.C
index 5c1204b..168a003 100644
--- a/gcc/testsuite/g++.old-deja/g++.oliva/template10.C
+++ b/gcc/testsuite/g++.old-deja/g++.oliva/template10.C
@@ -19,4 +19,4 @@  template<> struct A<int> {
 };
 
 bool A<int>::a = true; // ok
-template<> bool A<int>::b = false; // { dg-error "template header" } 
+template<> bool A<int>::b = false; // { dg-error "template (header|variable)" } 
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/var1.C b/gcc/testsuite/g++.old-deja/g++.pt/var1.C
index a15743d..ec91bc4 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/var1.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/var1.C
@@ -1,4 +1,5 @@ 
 // { dg-do assemble  }
 // Origin: Jason Merrill <jason@cygnus.com>
+// { dg-excess-errors "sorry" }
 
-template <class T> T t; // { dg-error "" } template declaration of t
+template <class T> T t; // template declaration of t