Commit 1f032c53 by Jason Merrill Committed by Jason Merrill

PR c++/60095 - partial specialization of variable templates

	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
parent f795360d
2016-05-31 Jason Merrill <jason@redhat.com> 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 PR c++/71227
* pt.c (check_explicit_specialization): Give better diagnostic about * pt.c (check_explicit_specialization): Give better diagnostic about
specializing a hidden friend. specializing a hidden friend.
......
...@@ -182,7 +182,6 @@ static tree copy_template_args (tree); ...@@ -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_arg (tree, tree, tsubst_flags_t, tree);
static tree tsubst_template_args (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 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 most_specialized_partial_spec (tree, tsubst_flags_t);
static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int); 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_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) ...@@ -17398,6 +17397,7 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
tree pattern = DECL_TEMPLATE_RESULT (gen_tmpl); tree pattern = DECL_TEMPLATE_RESULT (gen_tmpl);
fndecl = NULL_TREE;
if (VAR_P (pattern)) if (VAR_P (pattern))
{ {
/* We need to determine if we're using a partial or explicit /* 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) ...@@ -17409,14 +17409,16 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
pattern = error_mark_node; pattern = error_mark_node;
else if (elt) else if (elt)
{ {
tmpl = TREE_VALUE (elt); tree partial_tmpl = TREE_VALUE (elt);
pattern = DECL_TEMPLATE_RESULT (tmpl); tree partial_args = TREE_PURPOSE (elt);
targ_ptr = 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. */ /* 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)) if (DECL_CLASS_SCOPE_P (gen_tmpl))
pop_nested_class (); pop_nested_class ();
pop_from_top_level (); pop_from_top_level ();
...@@ -20888,36 +20890,6 @@ most_general_template (tree decl) ...@@ -20888,36 +20890,6 @@ most_general_template (tree decl)
return 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 /* Return the most specialized of the template partial specializations
which can produce TARGET, a specialization of some class or variable which can produce TARGET, a specialization of some class or variable
template. The value returned is actually a TREE_LIST; the TREE_VALUE is 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) ...@@ -21419,14 +21391,12 @@ do_type_instantiation (tree t, tree storage, tsubst_flags_t complain)
to instantiate the DECL, we regenerate it. */ to instantiate the DECL, we regenerate it. */
static void 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 /* The arguments used to instantiate DECL, from the most general
template. */ template. */
tree args;
tree code_pattern; tree code_pattern;
args = DECL_TI_ARGS (decl);
code_pattern = DECL_TEMPLATE_RESULT (tmpl); code_pattern = DECL_TEMPLATE_RESULT (tmpl);
/* Make sure that we can see identifiers, and compute access /* Make sure that we can see identifiers, and compute access
...@@ -21742,7 +21712,7 @@ instantiate_decl (tree d, int defer_ok, ...@@ -21742,7 +21712,7 @@ instantiate_decl (tree d, int defer_ok,
return d; return d;
gen_tmpl = most_general_template (tmpl); 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) if (tmpl != gen_tmpl)
/* We should already have the extra args. */ /* We should already have the extra args. */
...@@ -21761,6 +21731,20 @@ instantiate_decl (tree d, int defer_ok, ...@@ -21761,6 +21731,20 @@ instantiate_decl (tree d, int defer_ok,
/* Set TD to the template whose DECL_TEMPLATE_RESULT is the pattern /* Set TD to the template whose DECL_TEMPLATE_RESULT is the pattern
for the instantiation. */ for the instantiation. */
td = template_for_substitution (d); 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); code_pattern = DECL_TEMPLATE_RESULT (td);
/* We should never be trying to instantiate a member of a class /* We should never be trying to instantiate a member of a class
...@@ -21773,9 +21757,7 @@ instantiate_decl (tree d, int defer_ok, ...@@ -21773,9 +21757,7 @@ instantiate_decl (tree d, int defer_ok,
outside the class, we may have too many arguments. Drop the outside the class, we may have too many arguments. Drop the
ones we don't need. The same is true for specializations. */ ones we don't need. The same is true for specializations. */
args = get_innermost_template_args args = get_innermost_template_args
(gen_args, TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (td))); (args, TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (td)));
else
args = gen_args;
if (TREE_CODE (d) == FUNCTION_DECL) if (TREE_CODE (d) == FUNCTION_DECL)
{ {
...@@ -21941,7 +21923,7 @@ instantiate_decl (tree d, int defer_ok, ...@@ -21941,7 +21923,7 @@ instantiate_decl (tree d, int defer_ok,
/* Regenerate the declaration in case the template has been modified /* Regenerate the declaration in case the template has been modified
by a subsequent redeclaration. */ 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 /* We already set the file and line above. Reset them now in case
they changed as a result of calling regenerate_decl_from_template. */ they changed as a result of calling regenerate_decl_from_template. */
......
// PR c++/66260 // PR c++/66260
// { dg-do compile { target c++14 } } // { dg-do assemble { target c++14 } }
template <class> template <class>
constexpr bool foo = false; constexpr bool foo = false;
......
// 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]>);
}
// 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*>;
}
// 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() {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment