PR c++/60095 - partial specialization of variable templates
authorJason Merrill <jason@redhat.com>
Tue, 31 May 2016 19:49:16 +0000 (15:49 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 31 May 2016 19:49:16 +0000 (15:49 -0400)
PR c++/69515
PR c++/69009
* pt.c (instantiate_template_1): Don't put the partial
specialization in DECL_TI_TEMPLATE.
(partial_specialization_p, impartial_args): Remove.
(regenerate_decl_from_template): Add args parm.
(instantiate_decl): Look up the partial specialization again.

From-SVN: r236946

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp1y/var-templ39.C
gcc/testsuite/g++.dg/cpp1y/var-templ39a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/var-templ51.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/var-templ52.C [new file with mode: 0644]

index 35042bc262d4afc035405215a78fc044cf87b006..dabf2ec8d897c5858e5a3b51c2eb74d6c30ea62b 100644 (file)
@@ -1,5 +1,14 @@
 2016-05-31  Jason Merrill  <jason@redhat.com>
 
+       PR c++/60095
+       PR c++/69515
+       PR c++/69009
+       * pt.c (instantiate_template_1): Don't put the partial
+       specialization in DECL_TI_TEMPLATE.
+       (partial_specialization_p, impartial_args): Remove.
+       (regenerate_decl_from_template): Add args parm.
+       (instantiate_decl): Look up the partial specialization again.
+
        PR c++/71227
        * pt.c (check_explicit_specialization): Give better diagnostic about
        specializing a hidden friend.
index af37586177252162b27e0c9037616112f46101de..b25cd13659e31af13f3e8c16c1557d5e812ccde4 100644 (file)
@@ -182,7 +182,6 @@ static tree copy_template_args (tree);
 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_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);
@@ -17398,6 +17397,7 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
 
   tree pattern = DECL_TEMPLATE_RESULT (gen_tmpl);
 
+  fndecl = NULL_TREE;
   if (VAR_P (pattern))
     {
       /* We need to determine if we're using a partial or explicit
@@ -17409,14 +17409,16 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
        pattern = error_mark_node;
       else if (elt)
        {
-         tmpl = TREE_VALUE (elt);
-         pattern = DECL_TEMPLATE_RESULT (tmpl);
-         targ_ptr = TREE_PURPOSE (elt);
+         tree partial_tmpl = TREE_VALUE (elt);
+         tree partial_args = TREE_PURPOSE (elt);
+         tree partial_pat = DECL_TEMPLATE_RESULT (partial_tmpl);
+         fndecl = tsubst (partial_pat, partial_args, complain, gen_tmpl);
        }
     }
 
   /* Substitute template parameters to obtain the specialization.  */
-  fndecl = tsubst (pattern, targ_ptr, complain, gen_tmpl);
+  if (fndecl == NULL_TREE)
+    fndecl = tsubst (pattern, targ_ptr, complain, gen_tmpl);
   if (DECL_CLASS_SCOPE_P (gen_tmpl))
     pop_nested_class ();
   pop_from_top_level ();
@@ -20888,36 +20890,6 @@ most_general_template (tree decl)
   return decl;
 }
 
-/* True iff the TEMPLATE_DECL tmpl is a partial specialization.  */
-
-static bool
-partial_specialization_p (tree tmpl)
-{
-  /* Any specialization has DECL_TEMPLATE_SPECIALIZATION.  */
-  if (!DECL_TEMPLATE_SPECIALIZATION (tmpl))
-    return false;
-  tree t = DECL_TI_TEMPLATE (tmpl);
-  /* A specialization that fully specializes one of the containing classes is
-     not a partial specialization.  */
-  return (list_length (DECL_TEMPLATE_PARMS (tmpl))
-         == list_length (DECL_TEMPLATE_PARMS (t)));
-}
-
-/* If TMPL is a partial specialization, return the arguments for its primary
-   template.  */
-
-static tree
-impartial_args (tree tmpl, tree args)
-{
-  if (!partial_specialization_p (tmpl))
-    return args;
-
-  /* If TMPL is a partial specialization, we need to substitute to get
-     the args for the primary template.  */
-  return tsubst_template_args (DECL_TI_ARGS (tmpl), args,
-                              tf_warning_or_error, tmpl);
-}
-
 /* 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
@@ -21419,14 +21391,12 @@ do_type_instantiation (tree t, tree storage, tsubst_flags_t complain)
    to instantiate the DECL, we regenerate it.  */
 
 static void
-regenerate_decl_from_template (tree decl, tree tmpl)
+regenerate_decl_from_template (tree decl, tree tmpl, tree args)
 {
   /* The arguments used to instantiate DECL, from the most general
      template.  */
-  tree args;
   tree code_pattern;
 
-  args = DECL_TI_ARGS (decl);
   code_pattern = DECL_TEMPLATE_RESULT (tmpl);
 
   /* Make sure that we can see identifiers, and compute access
@@ -21742,7 +21712,7 @@ instantiate_decl (tree d, int defer_ok,
     return d;
 
   gen_tmpl = most_general_template (tmpl);
-  gen_args = impartial_args (tmpl, DECL_TI_ARGS (d));
+  gen_args = DECL_TI_ARGS (d);
 
   if (tmpl != gen_tmpl)
     /* We should already have the extra args.  */
@@ -21761,6 +21731,20 @@ instantiate_decl (tree d, int defer_ok,
   /* Set TD to the template whose DECL_TEMPLATE_RESULT is the pattern
      for the instantiation.  */
   td = template_for_substitution (d);
+  args = gen_args;
+
+  if (VAR_P (d))
+    {
+      /* Look up an explicit specialization, if any.  */
+      tree tid = lookup_template_variable (gen_tmpl, gen_args);
+      tree elt = most_specialized_partial_spec (tid, tf_warning_or_error);
+      if (elt && elt != error_mark_node)
+       {
+         td = TREE_VALUE (elt);
+         args = TREE_PURPOSE (elt);
+       }
+    }
+
   code_pattern = DECL_TEMPLATE_RESULT (td);
 
   /* We should never be trying to instantiate a member of a class
@@ -21773,9 +21757,7 @@ instantiate_decl (tree d, int defer_ok,
        outside the class, we may have too many arguments.  Drop the
        ones we don't need.  The same is true for specializations.  */
     args = get_innermost_template_args
-      (gen_args, TMPL_PARMS_DEPTH  (DECL_TEMPLATE_PARMS (td)));
-  else
-    args = gen_args;
+      (args, TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (td)));
 
   if (TREE_CODE (d) == FUNCTION_DECL)
     {
@@ -21941,7 +21923,7 @@ instantiate_decl (tree d, int defer_ok,
 
   /* Regenerate the declaration in case the template has been modified
      by a subsequent redeclaration.  */
-  regenerate_decl_from_template (d, td);
+  regenerate_decl_from_template (d, td, args);
 
   /* We already set the file and line above.  Reset them now in case
      they changed as a result of calling regenerate_decl_from_template.  */
index e06519d5482cfa1c8e5e5643023abe30ba6bfd77..5170a5bda52f27175f214bd0ef85780e09f0e61e 100644 (file)
@@ -1,5 +1,5 @@
 // PR c++/66260
-// { dg-do compile { target c++14 } }
+// { dg-do assemble { target c++14 } }
 
 template <class>
 constexpr bool foo = false;
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ39a.C b/gcc/testsuite/g++.dg/cpp1y/var-templ39a.C
new file mode 100644 (file)
index 0000000..5ba1b9d
--- /dev/null
@@ -0,0 +1,27 @@
+// PR c++/66260
+// { dg-do compile { target c++14 } }
+
+template <class>
+bool foo = false;
+template <>
+bool foo<int> = true;
+template <class T, int N>
+bool foo<T[N]> = foo<T>;
+
+#define assert(X) if (!(X)) __builtin_abort();
+
+int main()
+{
+  // { dg-final { scan-assembler "_Z3fooIiE" } }
+  assert(foo<int>);
+  // { dg-final { scan-assembler "_Z3fooIdE" } }
+  assert(!foo<double>);
+  // { dg-final { scan-assembler "_Z3fooIA3_iE" } }
+  assert(foo<int[3]>);
+  // { dg-final { scan-assembler "_Z3fooIA3_dE" } }
+  assert(!foo<double[3]>);
+  // { dg-final { scan-assembler "_Z3fooIA2_A5_A3_iE" } }
+  assert(foo<int[2][5][3]>);
+  // { dg-final { scan-assembler "_Z3fooIA2_A5_A3_dE" } }
+  assert(!foo<double[2][5][3]>);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ51.C b/gcc/testsuite/g++.dg/cpp1y/var-templ51.C
new file mode 100644 (file)
index 0000000..f85ef9c
--- /dev/null
@@ -0,0 +1,11 @@
+// PR c++/60095
+// { dg-do link { target c++14 } }
+
+template <class>
+constexpr bool b = false;
+template<typename T>
+constexpr bool b<T*> = true;
+int main() {
+    b<int*>;
+    b<double*>;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ52.C b/gcc/testsuite/g++.dg/cpp1y/var-templ52.C
new file mode 100644 (file)
index 0000000..61fd19e
--- /dev/null
@@ -0,0 +1,14 @@
+// PR c++/69515
+// { dg-do link { target c++14 } }
+
+struct A { A(int = 0) {} };
+
+template<class...> class meow;
+
+template<typename T> A foo;
+template<typename... Ts> A foo<meow<Ts...>> = 1;
+
+auto&& a = foo<meow<int>>;
+auto&& b = foo<meow<int, int>>;
+
+int main() {}