From: Jason Merrill Date: Tue, 31 May 2016 19:49:16 +0000 (-0400) Subject: PR c++/60095 - partial specialization of variable templates X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=1f032c533faf596b4627444a2a0f9f68f05f3ef0;p=gcc.git 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 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 35042bc262d..dabf2ec8d89 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,14 @@ 2016-05-31 Jason Merrill + 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. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index af375861772..b25cd13659e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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. */ diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ39.C b/gcc/testsuite/g++.dg/cpp1y/var-templ39.C index e06519d5482..5170a5bda52 100644 --- a/gcc/testsuite/g++.dg/cpp1y/var-templ39.C +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ39.C @@ -1,5 +1,5 @@ // PR c++/66260 -// { dg-do compile { target c++14 } } +// { dg-do assemble { target c++14 } } template 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 index 00000000000..5ba1b9d4579 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ39a.C @@ -0,0 +1,27 @@ +// PR c++/66260 +// { dg-do compile { target c++14 } } + +template +bool foo = false; +template <> +bool foo = true; +template +bool foo = foo; + +#define assert(X) if (!(X)) __builtin_abort(); + +int main() +{ + // { dg-final { scan-assembler "_Z3fooIiE" } } + assert(foo); + // { dg-final { scan-assembler "_Z3fooIdE" } } + assert(!foo); + // { dg-final { scan-assembler "_Z3fooIA3_iE" } } + assert(foo); + // { dg-final { scan-assembler "_Z3fooIA3_dE" } } + assert(!foo); + // { dg-final { scan-assembler "_Z3fooIA2_A5_A3_iE" } } + assert(foo); + // { dg-final { scan-assembler "_Z3fooIA2_A5_A3_dE" } } + assert(!foo); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ51.C b/gcc/testsuite/g++.dg/cpp1y/var-templ51.C new file mode 100644 index 00000000000..f85ef9c1177 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ51.C @@ -0,0 +1,11 @@ +// PR c++/60095 +// { dg-do link { target c++14 } } + +template +constexpr bool b = false; +template +constexpr bool b = true; +int main() { + b; + b; +} diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ52.C b/gcc/testsuite/g++.dg/cpp1y/var-templ52.C new file mode 100644 index 00000000000..61fd19e44ce --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ52.C @@ -0,0 +1,14 @@ +// PR c++/69515 +// { dg-do link { target c++14 } } + +struct A { A(int = 0) {} }; + +template class meow; + +template A foo; +template A foo> = 1; + +auto&& a = foo>; +auto&& b = foo>; + +int main() {}