From 1f41df916c2d6d7598cb5e67cdaebdc86910e902 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 27 Nov 2019 17:05:47 -0500 Subject: [PATCH] Fix constrained alias template transparency. A constrained alias template can't be treated as equivalent to its underlying template/type for much the same reason that an alias template like void_t can't; we're relying on checking during substitution. * cxx-pretty-print.c (pp_cxx_unqualified_id): Handle alias template-id. * pt.c (complex_alias_template_p): True if constraints. (get_underlying_template, tsubst): Check alias constraints. (push_template_decl_real): Set alias constraints here. * parser.c (cp_parser_alias_declaration): Not here. * constraint.cc (get_constraints): Take const_tree. From-SVN: r278785 --- gcc/cp/ChangeLog | 10 ++++ gcc/cp/constraint.cc | 15 +++++- gcc/cp/cp-tree.h | 4 +- gcc/cp/cxx-pretty-print.c | 6 +-- gcc/cp/parser.c | 8 --- gcc/cp/pt.c | 53 +++++++++++++++++--- gcc/testsuite/g++.dg/cpp2a/concepts-alias.C | 9 +--- gcc/testsuite/g++.dg/cpp2a/concepts-alias3.C | 10 ++++ gcc/testsuite/g++.dg/cpp2a/concepts-alias4.C | 10 ++++ 9 files changed, 97 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-alias3.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-alias4.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0f26009b2be..9dbc61c2151 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2019-11-16 Jason Merrill + + * cxx-pretty-print.c (pp_cxx_unqualified_id): Handle alias + template-id. + * pt.c (complex_alias_template_p): True if constraints. + (get_underlying_template, tsubst): Check alias constraints. + (push_template_decl_real): Set alias constraints here. + * parser.c (cp_parser_alias_declaration): Not here. + * constraint.cc (get_constraints): Take const_tree. + 2019-11-12 Jason Merrill PR c++/92206 - ICE with typedef to dependent alias. diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index fadbe7c8ac0..0d1c27a6d16 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -1124,7 +1124,7 @@ static GTY ((cache)) decl_tree_cache_map *decl_constraints; constrained, return NULL_TREE. Note that T must be non-null. */ tree -get_constraints (tree t) +get_constraints (const_tree t) { if (!flag_concepts) return NULL_TREE; @@ -1134,7 +1134,7 @@ get_constraints (tree t) gcc_assert (DECL_P (t)); if (TREE_CODE (t) == TEMPLATE_DECL) t = DECL_TEMPLATE_RESULT (t); - tree* found = decl_constraints->get (t); + tree* found = decl_constraints->get (CONST_CAST_TREE (t)); if (found) return *found; else @@ -2966,6 +2966,17 @@ more_constrained (tree d1, tree d2) return winner; } +/* Return whether D1 is at least as constrained as D2. */ + +bool +at_least_as_constrained (tree d1, tree d2) +{ + tree n1 = get_normalized_constraints_from_decl (d1); + tree n2 = get_normalized_constraints_from_decl (d2); + + return subsumes (n1, n2); +} + /*--------------------------------------------------------------------------- Constraint diagnostics ---------------------------------------------------------------------------*/ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d8e12e99ba3..fd3be60d407 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7772,7 +7772,8 @@ extern cp_expr finish_constraint_and_expr (location_t, cp_expr, cp_expr); extern cp_expr finish_constraint_primary_expr (cp_expr); extern tree finish_concept_definition (cp_expr, tree); extern tree combine_constraint_expressions (tree, tree); -extern tree get_constraints (tree); +extern tree append_constraint (tree, tree); +extern tree get_constraints (const_tree); extern void set_constraints (tree, tree); extern void remove_constraints (tree); extern tree current_template_constraints (void); @@ -7834,6 +7835,7 @@ extern bool subsumes_constraints (tree, tree); extern bool strictly_subsumes (tree, tree, tree); extern bool weakly_subsumes (tree, tree, tree); extern int more_constrained (tree, tree); +extern bool at_least_as_constrained (tree, tree); extern bool constraints_equivalent_p (tree, tree); extern bool atomic_constraints_identical_p (tree, tree); extern hashval_t iterative_hash_constraint (tree, hashval_t); diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 8ece11d276e..909b2a4ef1d 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -172,11 +172,11 @@ pp_cxx_unqualified_id (cxx_pretty_printer *pp, tree t) case TYPENAME_TYPE: case UNBOUND_CLASS_TEMPLATE: pp_cxx_unqualified_id (pp, TYPE_NAME (t)); - if (CLASS_TYPE_P (t) && CLASSTYPE_USE_TEMPLATE (t)) + if (tree ti = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (t)) { pp_cxx_begin_template_argument_list (pp); - pp_cxx_template_argument_list (pp, INNERMOST_TEMPLATE_ARGS - (CLASSTYPE_TI_ARGS (t))); + tree args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (ti)); + pp_cxx_template_argument_list (pp, args); pp_cxx_end_template_argument_list (pp); } break; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 27318d3aeed..c08b7b32a32 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -19901,14 +19901,6 @@ cp_parser_alias_declaration (cp_parser* parser) if (decl == error_mark_node) return decl; - /* Attach constraints to the alias declaration. */ - if (flag_concepts && current_template_parms) - { - tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); - tree constr = build_constraints (reqs, NULL_TREE); - set_constraints (decl, constr); - } - cp_finish_decl (decl, NULL_TREE, 0, NULL_TREE, 0); if (pushed_scope) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 244eb7d4ff3..6e712bdb4e1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -215,6 +215,7 @@ static tree listify_autos (tree, tree); static tree tsubst_template_parm (tree, tree, tsubst_flags_t); static tree instantiate_alias_template (tree, tree, tsubst_flags_t); static bool complex_alias_template_p (const_tree tmpl); +static tree get_underlying_template (tree); static tree tsubst_attributes (tree, tree, tsubst_flags_t, tree); static tree canonicalize_expr_argument (tree, tsubst_flags_t); static tree make_argument_pack (tree); @@ -5989,9 +5990,18 @@ push_template_decl_real (tree decl, bool is_friend) } if (TREE_CODE (decl) == TYPE_DECL - && TYPE_DECL_ALIAS_P (decl) - && complex_alias_template_p (tmpl)) - TEMPLATE_DECL_COMPLEX_ALIAS_P (tmpl) = true; + && TYPE_DECL_ALIAS_P (decl)) + { + if (tree constr + = TEMPLATE_PARMS_CONSTRAINTS (DECL_TEMPLATE_PARMS (tmpl))) + { + /* ??? Why don't we do this here for all templates? */ + constr = build_constraints (constr, NULL_TREE); + set_constraints (decl, constr); + } + if (complex_alias_template_p (tmpl)) + TEMPLATE_DECL_COMPLEX_ALIAS_P (tmpl) = true; + } } /* The DECL_TI_ARGS of DECL contains full set of arguments referring @@ -6350,6 +6360,14 @@ uses_all_template_parms_r (tree t, void *data_) static bool complex_alias_template_p (const_tree tmpl) { + /* A renaming alias isn't complex. */ + if (get_underlying_template (CONST_CAST_TREE (tmpl)) != tmpl) + return false; + + /* Any other constrained alias is complex. */ + if (get_constraints (tmpl)) + return true; + struct uses_all_template_parms_data data; tree pat = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl)); tree parms = DECL_TEMPLATE_PARMS (tmpl); @@ -6395,7 +6413,7 @@ dependent_alias_template_spec_p (const_tree t, bool transparent_typedefs) /* Return the number of innermost template parameters in TMPL. */ static int -num_innermost_template_parms (tree tmpl) +num_innermost_template_parms (const_tree tmpl) { tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl)); return TREE_VEC_LENGTH (parms); @@ -6430,6 +6448,11 @@ get_underlying_template (tree tmpl) if (!comp_template_args (TI_ARGS (tinfo), alias_args)) break; + /* If TMPL adds or changes any constraints, it isn't equivalent. I think + it's appropriate to treat a less-constrained alias as equivalent. */ + if (!at_least_as_constrained (underlying, tmpl)) + break; + /* Alias is equivalent. Strip it and repeat. */ tmpl = underlying; } @@ -9679,7 +9702,9 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, Note that the check is deferred until after the hash lookup. This prevents redundant checks on previously instantiated specializations. */ - if (flag_concepts && !constraints_satisfied_p (gen_tmpl, arglist)) + if (flag_concepts + && !DECL_ALIAS_TEMPLATE_P (gen_tmpl) + && !constraints_satisfied_p (gen_tmpl, arglist)) { if (complain & tf_error) { @@ -20499,8 +20524,6 @@ instantiate_alias_template (tree tmpl, tree args, tsubst_flags_t complain) { if (tmpl == error_mark_node || args == error_mark_node) return error_mark_node; - if (!push_tinst_level (tmpl, args)) - return error_mark_node; args = coerce_innermost_template_parms (DECL_TEMPLATE_PARMS (tmpl), @@ -20508,6 +20531,22 @@ instantiate_alias_template (tree tmpl, tree args, tsubst_flags_t complain) /*require_all_args=*/true, /*use_default_args=*/true); + /* FIXME check for satisfaction in check_instantiated_args. */ + if (flag_concepts + && !any_dependent_template_arguments_p (args) + && !constraints_satisfied_p (tmpl, args)) + { + if (complain & tf_error) + { + auto_diagnostic_group d; + error ("template constraint failure for %qD", tmpl); + diagnose_constraints (input_location, tmpl, args); + } + return error_mark_node; + } + + if (!push_tinst_level (tmpl, args)) + return error_mark_node; tree r = instantiate_template (tmpl, args, complain); pop_tinst_level (); diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-alias.C b/gcc/testsuite/g++.dg/cpp2a/concepts-alias.C index 6b2ab0d8046..862879169fb 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-alias.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-alias.C @@ -7,12 +7,8 @@ template requires Class using X = T*; -// BUG: Alias templates are expanded at the point of use, regardless -// of whether or not they are dependent. This causes T* to be substituted -// without acutally checking the constraints. See the declaration of y1 -// below. template -using Y = X; +using Y = X; // { dg-error "constraint" } template using Z = T*; @@ -20,6 +16,5 @@ struct S { }; X x1; // OK X x2; // { dg-error "template constraint failure" } -Y y1; // { dg-error "" "" { xfail *-*-* } } +Y y1; // { dg-message "" } Z z1; // ok - diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-alias3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-alias3.C new file mode 100644 index 00000000000..02e960ad40a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-alias3.C @@ -0,0 +1,10 @@ +// { dg-do compile { target c++2a } } + +template struct A { }; +template concept int_type = __is_same_as (T, int); +template using intA = A; + +template