Allow partial specialization of variable templates.
authorJason Merrill <jason@redhat.com>
Wed, 26 Nov 2014 21:58:38 +0000 (16:58 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 26 Nov 2014 21:58:38 +0000 (16:58 -0500)
* cp-tree.h (TINFO_USED_TEMPLATE_ID): New.
* decl.c (duplicate_decls): Copy it.
* error.c (dump_decl) [TEMPLATE_ID_EXPR]: Handle variables.
* parser.c (cp_parser_decltype_expr): Do call finish_id_expression
on template-ids.
* pt.c (register_specialization): Remember variable template insts.
(instantiate_template_1): Find the matching partial specialization.
(check_explicit_specialization): Allow variable partial specialization.
(process_partial_specialization): Likewise.
(push_template_decl_real): Likewise.
(more_specialized_partial_spec): Rename from more_specialized_class.
(most_specialized_partial_spec): Rename from most_specialized_class.
(get_partial_spec_bindings): Rename from get_class_bindings.

From-SVN: r218104

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/error.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp0x/variadic20.C
gcc/testsuite/g++.dg/cpp1y/var-templ16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/var-templ18.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/var-templ19.C [new file with mode: 0644]

index 756c8d8b5d1ac30ad48d710f5febbd1f14b4f9e3..9c6427963e77c9db850ee41c4e8fa32504d4ab00 100644 (file)
@@ -1,3 +1,20 @@
+2014-11-26  Jason Merrill  <jason@redhat.com>
+
+       Allow partial specialization of variable templates.
+       * cp-tree.h (TINFO_USED_TEMPLATE_ID): New.
+       * decl.c (duplicate_decls): Copy it.
+       * error.c (dump_decl) [TEMPLATE_ID_EXPR]: Handle variables.
+       * parser.c (cp_parser_decltype_expr): Do call finish_id_expression
+       on template-ids.
+       * pt.c (register_specialization): Remember variable template insts.
+       (instantiate_template_1): Find the matching partial specialization.
+       (check_explicit_specialization): Allow variable partial specialization.
+       (process_partial_specialization): Likewise.
+       (push_template_decl_real): Likewise.
+       (more_specialized_partial_spec): Rename from more_specialized_class.
+       (most_specialized_partial_spec): Rename from most_specialized_class.
+       (get_partial_spec_bindings): Rename from get_class_bindings.
+
 2014-11-26  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/63757
index f1064e9ae24ba58664df6608ca5ab955a53c313a..edd1d5d8443188f7874ca1e088998f3cb2e29e41 100644 (file)
@@ -99,6 +99,7 @@ c-common.h, not after.
       QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF)
       DECLTYPE_FOR_INIT_CAPTURE (in DECLTYPE_TYPE)
       CONSTRUCTOR_NO_IMPLICIT_ZERO (in CONSTRUCTOR)
+      TINFO_USED_TEMPLATE_ID (in TEMPLATE_INFO)
    2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE)
       ICS_THIS_FLAG (in _CONV)
       DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
@@ -801,6 +802,12 @@ typedef struct qualified_typedef_usage_s qualified_typedef_usage_t;
 #define FNDECL_HAS_ACCESS_ERRORS(NODE) \
   (TINFO_HAS_ACCESS_ERRORS (DECL_TEMPLATE_INFO (NODE)))
 
+/* Non-zero if this variable template specialization was specified using a
+   template-id, so it's a partial or full specialization and not a definition
+   of the member template of a particular class specialization.  */
+#define TINFO_USED_TEMPLATE_ID(NODE) \
+  (TREE_LANG_FLAG_1 (TEMPLATE_INFO_CHECK (NODE)))
+
 struct GTY(()) tree_template_info {
   struct tree_common common;
   vec<qualified_typedef_usage_t, va_gc> *typedefs_needing_access_checking;
index 4ce4645679e617525fd067fe5525b712d0862745..455097e1182bb1a70a8fad41298eda97477f6c7d 100644 (file)
@@ -2137,7 +2137,14 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
          DECL_LANG_SPECIFIC (newdecl)->u.min.u2 =
            DECL_LANG_SPECIFIC (olddecl)->u.min.u2;
          if (DECL_TEMPLATE_INFO (newdecl))
-           new_template_info = DECL_TEMPLATE_INFO (newdecl);
+           {
+             new_template_info = DECL_TEMPLATE_INFO (newdecl);
+             if (DECL_TEMPLATE_INSTANTIATION (olddecl)
+                 && DECL_TEMPLATE_SPECIALIZATION (newdecl))
+               /* Remember the presence of explicit specialization args.  */
+               TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (olddecl))
+                 = TINFO_USED_TEMPLATE_ID (new_template_info);
+           }
          DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
        }
       /* Only functions have these fields.  */
index 7d79771ec267fcf948bc7d289da38124ce5cdae4..5dcc149e1854b6133c5a417000744afdf8b19d79 100644 (file)
@@ -1212,7 +1212,9 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
        tree args = TREE_OPERAND (t, 1);
 
        if (is_overloaded_fn (name))
-         name = DECL_NAME (get_first_fn (name));
+         name = get_first_fn (name);
+       if (DECL_P (name))
+         name = DECL_NAME (name);
        dump_decl (pp, name, flags);
        pp_cxx_begin_template_argument_list (pp);
        if (args == error_mark_node)
index b8e182af5d765985ffe0ac002dbae255611a492e..d1cd63f1ca62e53809129d7933cde3ce1f452dca 100644 (file)
@@ -12175,7 +12175,6 @@ cp_parser_decltype_expr (cp_parser *parser,
 
       if (expr
           && expr != error_mark_node
-          && TREE_CODE (expr) != TEMPLATE_ID_EXPR
           && TREE_CODE (expr) != TYPE_DECL
          && (TREE_CODE (expr) != BIT_NOT_EXPR
              || !TYPE_P (TREE_OPERAND (expr, 0)))
index 29fb2e1117e799dba0a762d07acc51fb10cd1b9c..8e71fcb7cfca8a38ee96125d2c172286a4a872c1 100644 (file)
@@ -129,7 +129,7 @@ static int unify (tree, tree, tree, tree, int, bool);
 static void add_pending_template (tree);
 static tree reopen_tinst_level (struct tinst_level *);
 static tree tsubst_initializer_list (tree, tree);
-static tree get_class_bindings (tree, tree, tree, tree);
+static tree get_partial_spec_bindings (tree, tree, tree, tree);
 static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t,
                                   bool, bool);
 static tree coerce_innermost_template_parms (tree, tree, tree, tsubst_flags_t,
@@ -173,7 +173,7 @@ static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
 static void regenerate_decl_from_template (tree, tree);
-static tree most_specialized_class (tree, tsubst_flags_t);
+static tree most_specialized_partial_spec (tree, tsubst_flags_t);
 static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int);
 static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree);
 static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
@@ -1485,12 +1485,17 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
       gcc_assert (tmpl && args && spec);
       *entry = elt;
       *slot = entry;
-      if (TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec)
-         && PRIMARY_TEMPLATE_P (tmpl)
-         && DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE)
-       /* TMPL is a forward declaration of a template function; keep a list
+      if ((TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec)
+          && PRIMARY_TEMPLATE_P (tmpl)
+          && DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE)
+         || variable_template_p (tmpl))
+       /* If TMPL is a forward declaration of a template function, keep a list
           of all specializations in case we need to reassign them to a friend
-          template later in tsubst_friend_function.  */
+          template later in tsubst_friend_function.
+
+          Also keep a list of all variable template instantiations so that
+          process_partial_specialization can check whether a later partial
+          specialization would have used it.  */
        DECL_TEMPLATE_INSTANTIATIONS (tmpl)
          = tree_cons (args, spec, DECL_TEMPLATE_INSTANTIATIONS (tmpl));
     }
@@ -2471,13 +2476,24 @@ check_explicit_specialization (tree declarator,
          /* This case handles bogus declarations like template <>
             template <class T> void f<int>(); */
 
-         if (uses_template_parms (declarator))
+         if (!uses_template_parms (declarator))
+           error ("template-id %qD in declaration of primary template",
+                  declarator);
+         else if (variable_template_p (TREE_OPERAND (declarator, 0)))
+           {
+             /* Partial specialization of variable template.  */
+             SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+             specialization = 1;
+             goto ok;
+           }
+         else if (cxx_dialect < cxx14)
            error ("non-type partial specialization %qD "
                   "is not allowed", declarator);
          else
-           error ("template-id %qD in declaration of primary template",
-                  declarator);
+           error ("non-class, non-variable partial specialization %qD "
+                  "is not allowed", declarator);
          return decl;
+       ok:;
        }
 
       if (ctype && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype))
@@ -2516,9 +2532,10 @@ check_explicit_specialization (tree declarator,
     {
       tree tmpl = NULL_TREE;
       tree targs = NULL_TREE;
+      bool was_template_id = (TREE_CODE (declarator) == TEMPLATE_ID_EXPR);
 
       /* Make sure that the declarator is a TEMPLATE_ID_EXPR.  */
-      if (TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
+      if (!was_template_id)
        {
          tree fns;
 
@@ -2585,7 +2602,7 @@ check_explicit_specialization (tree declarator,
       else if (ctype != NULL_TREE
               && (identifier_p (TREE_OPERAND (declarator, 0))))
        {
-         // Ignore variable templates.
+         // We'll match variable templates in start_decl.
          if (VAR_P (decl))
            return decl;
 
@@ -2722,7 +2739,7 @@ check_explicit_specialization (tree declarator,
          /* If this is a specialization of a member template of a
             template class, we want to return the TEMPLATE_DECL, not
             the specialization of it.  */
-         if (tsk == tsk_template)
+         if (tsk == tsk_template && !was_template_id)
            {
              tree result = DECL_TEMPLATE_RESULT (tmpl);
              SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
@@ -2747,6 +2764,9 @@ check_explicit_specialization (tree declarator,
          /* Set up the DECL_TEMPLATE_INFO for DECL.  */
          DECL_TEMPLATE_INFO (decl) = build_template_info (tmpl, targs);
 
+         if (was_template_id)
+           TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (decl)) = true;
+
          /* Inherit default function arguments from the template
             DECL is specializing.  */
          if (DECL_FUNCTION_TEMPLATE_P (tmpl))
@@ -4087,8 +4107,9 @@ static tree
 process_partial_specialization (tree decl)
 {
   tree type = TREE_TYPE (decl);
-  tree maintmpl = CLASSTYPE_TI_TEMPLATE (type);
-  tree specargs = CLASSTYPE_TI_ARGS (type);
+  tree tinfo = get_template_info (decl);
+  tree maintmpl = TI_TEMPLATE (tinfo);
+  tree specargs = TI_ARGS (tinfo);
   tree inner_args = INNERMOST_TEMPLATE_ARGS (specargs);
   tree main_inner_parms = DECL_INNERMOST_TEMPLATE_PARMS (maintmpl);
   tree inner_parms;
@@ -4173,11 +4194,11 @@ process_partial_specialization (tree decl)
 
      The argument list of the specialization shall not be identical to
      the implicit argument list of the primary template.  */
-  if (comp_template_args
-      (inner_args,
-       INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (TREE_TYPE
-                                                  (maintmpl)))))
-    error ("partial specialization %qT does not specialize any template arguments", type);
+  tree main_args
+    = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (maintmpl)));
+  if (comp_template_args (inner_args, INNERMOST_TEMPLATE_ARGS (main_args)))
+    error ("partial specialization %qD does not specialize "
+          "any template arguments", decl);
 
   /* A partial specialization that replaces multiple parameters of the
      primary template with a pack expansion is less specialized for those
@@ -4317,7 +4338,8 @@ process_partial_specialization (tree decl)
     }
 
   /* We should only get here once.  */
-  gcc_assert (!COMPLETE_TYPE_P (type));
+  if (TREE_CODE (decl) == TYPE_DECL)
+    gcc_assert (!COMPLETE_TYPE_P (type));
 
   tree tmpl = build_template_decl (decl, current_template_parms,
                                   DECL_MEMBER_TEMPLATE_P (maintmpl));
@@ -4335,15 +4357,21 @@ process_partial_specialization (tree decl)
   for (inst = DECL_TEMPLATE_INSTANTIATIONS (maintmpl); inst;
        inst = TREE_CHAIN (inst))
     {
-      tree inst_type = TREE_VALUE (inst);
-      if (COMPLETE_TYPE_P (inst_type)
-         && CLASSTYPE_IMPLICIT_INSTANTIATION (inst_type))
+      tree instance = TREE_VALUE (inst);
+      if (TYPE_P (instance)
+         ? (COMPLETE_TYPE_P (instance)
+            && CLASSTYPE_IMPLICIT_INSTANTIATION (instance))
+         : DECL_TEMPLATE_INSTANTIATION (instance))
        {
-         tree spec = most_specialized_class (inst_type, tf_none);
-         if (spec && TREE_TYPE (spec) == type)
-           permerror (input_location,
-                      "partial specialization of %qT after instantiation "
-                      "of %qT", type, inst_type);
+         tree spec = most_specialized_partial_spec (instance, tf_none);
+         if (spec && TREE_VALUE (spec) == tmpl)
+           {
+             tree inst_decl = (DECL_P (instance)
+                               ? instance : TYPE_NAME (instance));
+             permerror (input_location,
+                        "partial specialization of %qD after instantiation "
+                        "of %qD", decl, inst_decl);
+           }
        }
     }
 
@@ -4692,9 +4720,13 @@ push_template_decl_real (tree decl, bool is_friend)
     return error_mark_node;
 
   /* See if this is a partial specialization.  */
-  is_partial = (DECL_IMPLICIT_TYPEDEF_P (decl)
-               && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
-               && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)));
+  is_partial = ((DECL_IMPLICIT_TYPEDEF_P (decl)
+                && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
+                && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
+               || (TREE_CODE (decl) == VAR_DECL
+                   && DECL_LANG_SPECIFIC (decl)
+                   && DECL_TEMPLATE_SPECIALIZATION (decl)
+                   && TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (decl))));
 
   if (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl))
     is_friend = true;
@@ -9057,7 +9089,7 @@ instantiate_class_template_1 (tree type)
 
   /* Determine what specialization of the original template to
      instantiate.  */
-  t = most_specialized_class (type, tf_warning_or_error);
+  t = most_specialized_partial_spec (type, tf_warning_or_error);
   if (t == error_mark_node)
     {
       TYPE_BEING_DEFINED (type) = 1;
@@ -10519,7 +10551,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
            if (new_type == error_mark_node)
              RETURN (error_mark_node);
            /* If we get a real template back, return it.  This can happen in
-              the context of most_specialized_class.  */
+              the context of most_specialized_partial_spec.  */
            if (TREE_CODE (new_type) == TEMPLATE_DECL)
              return new_type;
 
@@ -15878,9 +15910,28 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
                                   complain, gen_tmpl, true);
       push_nested_class (ctx);
     }
+
+  tree pattern = DECL_TEMPLATE_RESULT (gen_tmpl);
+
+  if (VAR_P (pattern))
+    {
+      /* We need to determine if we're using a partial or explicit
+        specialization now, because the type of the variable could be
+        different.  */
+      tree tid = lookup_template_variable (gen_tmpl, targ_ptr);
+      tree elt = most_specialized_partial_spec (tid, complain);
+      if (elt == error_mark_node)
+       pattern = error_mark_node;
+      else if (elt)
+       {
+         tmpl = TREE_VALUE (elt);
+         pattern = DECL_TEMPLATE_RESULT (tmpl);
+         targ_ptr = TREE_PURPOSE (elt);
+       }
+    }
+
   /* Substitute template parameters to obtain the specialization.  */
-  fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl),
-                  targ_ptr, complain, gen_tmpl);
+  fndecl = tsubst (pattern, targ_ptr, complain, gen_tmpl);
   if (DECL_CLASS_SCOPE_P (gen_tmpl))
     pop_nested_class ();
   pop_from_top_level ();
@@ -18881,8 +18932,8 @@ more_specialized_fn (tree pat1, tree pat2, int len)
 /* Determine which of two partial specializations of TMPL is more
    specialized.
 
-   PAT1 is a TREE_LIST whose TREE_TYPE is the _TYPE node corresponding
-   to the first partial specialization.  The TREE_VALUE is the
+   PAT1 is a TREE_LIST whose TREE_VALUE is the TEMPLATE_DECL corresponding
+   to the first partial specialization.  The TREE_PURPOSE is the
    innermost set of template parameters for the partial
    specialization.  PAT2 is similar, but for the second template.
 
@@ -18894,33 +18945,32 @@ more_specialized_fn (tree pat1, tree pat2, int len)
    two templates is more specialized.  */
 
 static int
-more_specialized_class (tree tmpl, tree pat1, tree pat2)
+more_specialized_partial_spec (tree tmpl, tree pat1, tree pat2)
 {
   tree targs;
-  tree tmpl1, tmpl2;
   int winner = 0;
   bool any_deductions = false;
 
-  tmpl1 = TREE_TYPE (pat1);
-  tmpl2 = TREE_TYPE (pat2);
+  tree tmpl1 = TREE_VALUE (pat1);
+  tree tmpl2 = TREE_VALUE (pat2);
+  tree parms1 = DECL_INNERMOST_TEMPLATE_PARMS (tmpl1);
+  tree parms2 = DECL_INNERMOST_TEMPLATE_PARMS (tmpl2);
+  tree specargs1 = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (tmpl1)));
+  tree specargs2 = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (tmpl2)));
 
   /* Just like what happens for functions, if we are ordering between
-     different class template specializations, we may encounter dependent
+     different template specializations, we may encounter dependent
      types in the arguments, and we need our dependency check functions
      to behave correctly.  */
   ++processing_template_decl;
-  targs = get_class_bindings (tmpl, TREE_VALUE (pat1),
-                             CLASSTYPE_TI_ARGS (tmpl1),
-                             CLASSTYPE_TI_ARGS (tmpl2));
+  targs = get_partial_spec_bindings (tmpl, parms1, specargs1, specargs2);
   if (targs)
     {
       --winner;
       any_deductions = true;
     }
 
-  targs = get_class_bindings (tmpl, TREE_VALUE (pat2),
-                             CLASSTYPE_TI_ARGS (tmpl2),
-                             CLASSTYPE_TI_ARGS (tmpl1));
+  targs = get_partial_spec_bindings (tmpl, parms2, specargs2, specargs1);
   if (targs)
     {
       ++winner;
@@ -18928,7 +18978,7 @@ more_specialized_class (tree tmpl, tree pat1, tree pat2)
     }
   --processing_template_decl;
 
-  /* In the case of a tie where at least one of the class templates
+  /* In the case of a tie where at least one of the templates
      has a parameter pack at the end, the template with the most
      non-packed parameters wins.  */
   if (winner == 0
@@ -19014,7 +19064,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
    is bound to `double'.  */
 
 static tree
-get_class_bindings (tree tmpl, tree tparms, tree spec_args, tree args)
+get_partial_spec_bindings (tree tmpl, tree tparms, tree spec_args, tree args)
 {
   int i, ntparms = TREE_VEC_LENGTH (tparms);
   tree deduced_args;
@@ -19197,20 +19247,20 @@ most_general_template (tree decl)
   return decl;
 }
 
-/* Return the most specialized of the class template partial
-   specializations which can produce TYPE, a specialization of some class
-   template.  The value returned is actually a TREE_LIST; the TREE_TYPE is
-   a _TYPE node corresponding to the partial specialization, while the
-   TREE_PURPOSE is the set of template arguments that must be
-   substituted into the TREE_TYPE in order to generate TYPE.
+/* Return the most specialized of the template partial specializations
+   which can produce TARGET, a specialization of some class or variable
+   template.  The value returned is actually a TREE_LIST; the TREE_VALUE is
+   a TEMPLATE_DECL node corresponding to the partial specialization, while
+   the TREE_PURPOSE is the set of template arguments that must be
+   substituted into the template pattern in order to generate TARGET.
 
    If the choice of partial specialization is ambiguous, a diagnostic
    is issued, and the error_mark_node is returned.  If there are no
-   partial specializations matching TYPE, then NULL_TREE is
+   partial specializations matching TARGET, then NULL_TREE is
    returned, indicating that the primary template should be used.  */
 
 static tree
-most_specialized_class (tree type, tsubst_flags_t complain)
+most_specialized_partial_spec (tree target, tsubst_flags_t complain)
 {
   tree list = NULL_TREE;
   tree t;
@@ -19218,10 +19268,29 @@ most_specialized_class (tree type, tsubst_flags_t complain)
   int fate;
   bool ambiguous_p;
   tree outer_args = NULL_TREE;
+  tree tmpl, args;
+
+  if (TYPE_P (target))
+    {
+      tree tinfo = CLASSTYPE_TEMPLATE_INFO (target);
+      tmpl = TI_TEMPLATE (tinfo);
+      args = TI_ARGS (tinfo);
+    }
+  else if (TREE_CODE (target) == TEMPLATE_ID_EXPR)
+    {
+      tmpl = TREE_OPERAND (target, 0);
+      args = TREE_OPERAND (target, 1);
+    }
+  else if (VAR_P (target))
+    {
+      tree tinfo = DECL_TEMPLATE_INFO (target);
+      tmpl = TI_TEMPLATE (tinfo);
+      args = TI_ARGS (tinfo);
+    }
+  else
+    gcc_unreachable ();
 
-  tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
   tree main_tmpl = most_general_template (tmpl);
-  tree args = CLASSTYPE_TI_ARGS (type);
 
   /* For determining which partial specialization to use, only the
      innermost args are interesting.  */
@@ -19236,9 +19305,8 @@ most_specialized_class (tree type, tsubst_flags_t complain)
       tree partial_spec_args;
       tree spec_args;
       tree spec_tmpl = TREE_VALUE (t);
-      tree orig_parms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl);
 
-      partial_spec_args = CLASSTYPE_TI_ARGS (TREE_TYPE (t));
+      partial_spec_args = TREE_PURPOSE (t);
 
       ++processing_template_decl;
 
@@ -19269,14 +19337,14 @@ most_specialized_class (tree type, tsubst_flags_t complain)
        return error_mark_node;
 
       tree parms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl);
-      spec_args = get_class_bindings (tmpl, parms,
+      spec_args = get_partial_spec_bindings (tmpl, parms,
                                      partial_spec_args,
                                      args);
       if (spec_args)
        {
          if (outer_args)
            spec_args = add_to_template_args (outer_args, spec_args);
-         list = tree_cons (spec_args, orig_parms, list);
+         list = tree_cons (spec_args, TREE_VALUE (t), list);
          TREE_TYPE (list) = TREE_TYPE (t);
        }
     }
@@ -19290,7 +19358,7 @@ most_specialized_class (tree type, tsubst_flags_t complain)
   t = TREE_CHAIN (t);
   for (; t; t = TREE_CHAIN (t))
     {
-      fate = more_specialized_class (tmpl, champ, t);
+      fate = more_specialized_partial_spec (tmpl, champ, t);
       if (fate == 1)
        ;
       else
@@ -19311,7 +19379,7 @@ most_specialized_class (tree type, tsubst_flags_t complain)
   if (!ambiguous_p)
     for (t = list; t && t != champ; t = TREE_CHAIN (t))
       {
-       fate = more_specialized_class (tmpl, champ, t);
+       fate = more_specialized_partial_spec (tmpl, champ, t);
        if (fate != 1)
          {
            ambiguous_p = true;
@@ -19325,11 +19393,16 @@ most_specialized_class (tree type, tsubst_flags_t complain)
       char *spaces = NULL;
       if (!(complain & tf_error))
        return error_mark_node;
-      error ("ambiguous class template instantiation for %q#T", type);
+      if (TYPE_P (target))
+       error ("ambiguous template instantiation for %q#T", target);
+      else
+       error ("ambiguous template instantiation for %q#D", target);
       str = ngettext ("candidate is:", "candidates are:", list_length (list));
       for (t = list; t; t = TREE_CHAIN (t))
         {
-          error ("%s %+#T", spaces ? spaces : str, TREE_TYPE (t));
+         tree subst = build_tree_list (TREE_VALUE (t), TREE_PURPOSE (t));
+          inform (DECL_SOURCE_LOCATION (TREE_VALUE (t)),
+                 "%s %#S", spaces ? spaces : str, subst);
           spaces = spaces ? spaces : get_spaces (str);
         }
       free (spaces);
index 5b5a234642432e3c98b1d54cee1dd4ff73c0f17c..4932e66be1eacf5ff1ed087dfa2ea907dd853336 100644 (file)
@@ -13,25 +13,25 @@ struct metatuple<add_pointer> {
 };
 
 template<template<class T> class Meta>
-struct metatuple<Meta, Meta> { // { dg-error "candidates" }
+struct metatuple<Meta, Meta> { // { dg-message "candidates" }
   static const int value = 2;
 };
 
 template<template<class T> class... Metafunctions>
-struct metatuple<add_pointer, Metafunctions...> { // { dg-error "" }
+struct metatuple<add_pointer, Metafunctions...> { // { dg-message "" }
   static const int value = 3;
 };
 
 template<template<class T> class First,
          template<class T> class... Metafunctions>
-struct metatuple<First, Metafunctions...> { // { dg-error "struct" }
+struct metatuple<First, Metafunctions...> { // { dg-message "struct" }
   static const int value = 4;
 };
 
 template<template<class T> class First,
          template<class T> class Second,
          template<class T> class... Metafunctions>
-struct metatuple<First, Second, Metafunctions...> { // { dg-error "struct" }
+struct metatuple<First, Second, Metafunctions...> { // { dg-message "struct" }
   static const int value = 5;
 };
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ16.C b/gcc/testsuite/g++.dg/cpp1y/var-templ16.C
new file mode 100644 (file)
index 0000000..9fd5608
--- /dev/null
@@ -0,0 +1,6 @@
+// { dg-do compile { target c++14 } }
+
+template <class T> T t = 42;
+template <class T> T* t<T*> = nullptr;
+
+void *p = t<void*>;
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ18.C b/gcc/testsuite/g++.dg/cpp1y/var-templ18.C
new file mode 100644 (file)
index 0000000..415a7d5
--- /dev/null
@@ -0,0 +1,9 @@
+// DR 1727: a specialization doesn't need to have the same type
+// { dg-do compile { target c++14 } }
+
+template <class T> T t = 42;
+template <class T> int t<T*> = 0;
+
+template<class T, class U> struct same;
+template<class T> struct same<T,T> {};
+same<int,decltype(t<void*>)> s;
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ19.C b/gcc/testsuite/g++.dg/cpp1y/var-templ19.C
new file mode 100644 (file)
index 0000000..862752a
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++14 } }
+
+template <class T> T t1 = 42;
+template <class T> T* t1<T> = nullptr; // { dg-error "partial" }
+
+template <class T> T t2 = 42;
+template <class T> T* t2<T*> = nullptr;
+template <class T> T* t2<T*> = nullptr; // { dg-error "redefinition" }
+
+template <class T, class U> T t3 = U();
+template <class T> T t3<T,int> = 42;
+template <class U> int t3<int,U> = U();
+
+int i = t3<int,int>;           // { dg-error "ambiguous" }
+
+template <class T> T t4 = T();
+void *p = t4<void*>;
+template <class T> T* t4<T*> = nullptr; // { dg-error "after instantiation" }