diff mbox

Patch for constexpr variable templates

Message ID 53DA0E03.20300@maniacsvault.net
State New
Headers show

Commit Message

Braden Obrzut July 31, 2014, 9:36 a.m. UTC
Here's an updated patch with cp_parser_id_expression instantiating the 
variable templates if this is indeed what we want to do.

The previous implementation did seem to make the distinction between 
static template class member variables and variable templates a bit more 
obvious.  See the first change to check_explicit_specialization.  
Related to that, grokvardecl might be using build_lang_decl more often 
than it did previously.  I might be able to narrow that down a little, 
but I'm not sure.

- Braden Obrzut

2014-07-31  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 (make_id_declarator): Accept VAR_DECL for variable 
templates.
     (cp_parser_template_id): Handle variable templates and return a
     VAR_DECL.
     (cp_parser_lookup_name): May now be passed a VAR_DECL which is already
     resolved.
     * 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 variable templates.
     (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.

2014-07-31  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.
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..c9c36d8 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) == VAR_DECL)))
     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
@@ -8950,6 +8962,12 @@  grokdeclarator (const cp_declarator *declarator,
 		}
 		/* Fall through.  */
 
+	      // Variable templates will pass a VAR_DECL here.
+	      case VAR_DECL:
+	        if (TREE_CODE (decl) != TEMPLATE_ID_EXPR)
+	          dname = DECL_NAME (decl);
+	        /* Fall through.  */
+
 	      case IDENTIFIER_NODE:
 		if (identifier_p (decl))
 		  dname = decl;
@@ -9491,6 +9509,7 @@  grokdeclarator (const cp_declarator *declarator,
 
 	case IDENTIFIER_NODE:
 	case TEMPLATE_ID_EXPR:
+	case VAR_DECL:
 	  break;
 
 	default:
@@ -9986,7 +10005,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 +10896,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..866d589 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1378,7 +1378,8 @@  make_id_declarator (tree qualifying_scope, tree unqualified_name,
 
   gcc_assert (identifier_p (unqualified_name)
 	      || TREE_CODE (unqualified_name) == BIT_NOT_EXPR
-	      || TREE_CODE (unqualified_name) == TEMPLATE_ID_EXPR);
+	      || TREE_CODE (unqualified_name) == TEMPLATE_ID_EXPR
+	      || TREE_CODE (unqualified_name) == VAR_DECL);
 
   declarator = make_declarator (cdk_id);
   declarator->u.id.qualifying_scope = qualifying_scope;
@@ -13404,7 +13405,8 @@  cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
    `template' keyword.  In this case, a TEMPLATE_ID_EXPR will be
    returned.  Otherwise, if the template-name names a function, or set
    of functions, returns a TEMPLATE_ID_EXPR.  If the template-name
-   names a class, returns a TYPE_DECL for the specialization.
+   names a class, returns a TYPE_DECL for the specialization.  If the
+   template-name names a variable, returns a VAR_DECL.
 
    If CHECK_DEPENDENCY_P is FALSE, names are looked up in
    uninstantiated templates.  */
@@ -13558,6 +13560,11 @@  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);
+      template_id = finish_template_variable (template_id);
+    }
   else
     {
       /* If it's not a class-template or a template-template, it should be
@@ -22311,8 +22318,9 @@  cp_parser_lookup_name (cp_parser *parser, tree name,
     return error_mark_node;
 
   /* A template-id has already been resolved; there is no lookup to
-     do.  */
-  if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+     do.  Likewise, variable templates are resolved.  */
+  if (TREE_CODE (name) == TEMPLATE_ID_EXPR
+      || TREE_CODE (name) == VAR_DECL)
     return name;
   if (BASELINK_P (name))
     {
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7b79280..c1ddd5d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -1868,8 +1868,16 @@  determine_specialization (tree template_id,
       return error_mark_node;
     }
 
-  fns = TREE_OPERAND (template_id, 0);
-  explicit_targs = TREE_OPERAND (template_id, 1);
+  if (VAR_P (template_id))
+    {
+      fns = DECL_TI_TEMPLATE (template_id);
+      explicit_targs = DECL_TI_ARGS (template_id);
+    }
+  else
+    {
+      fns = TREE_OPERAND (template_id, 0);
+      explicit_targs = TREE_OPERAND (template_id, 1);
+    }
 
   if (fns == error_mark_node)
     return error_mark_node;
@@ -1878,11 +1886,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 +1905,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 +2326,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 +2467,13 @@  check_explicit_specialization (tree declarator,
 
       /* Fall through.  */
     case tsk_expl_spec:
+      if (VAR_P (decl) && identifier_p (declarator))
+        {
+           // 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 +2513,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))
@@ -2498,8 +2533,9 @@  check_explicit_specialization (tree declarator,
       tree tmpl = NULL_TREE;
       tree targs = NULL_TREE;
 
-      /* Make sure that the declarator is a TEMPLATE_ID_EXPR.  */
-      if (TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
+      /* Make sure that the declarator is a TEMPLATE_ID_EXPR or VAR_DECL.  */
+      if (TREE_CODE (declarator) != TEMPLATE_ID_EXPR
+          && TREE_CODE (declarator) != VAR_DECL)
 	{
 	  tree fns;
 
@@ -2566,6 +2602,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 +2731,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 +2766,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 +2836,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 +4781,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 +7950,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 +10525,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 +19205,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 +19238,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 +19948,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 +19965,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 +20063,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..8fd510c 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.)  */
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