From 636b25c1536d7b914750c2df9fce9d9fdeba69b5 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 6 Nov 2015 11:21:29 -0500 Subject: [PATCH] Support non-type constrained-type-specifiers. * parser.c (check_type_concept): Remove. (cp_parser_maybe_constrained_type_specifier): Don't call it. (synthesize_implicit_template_parm): Handle non-type and template template parameters. Also compare extra args. Return the decl. (cp_parser_template_argument): Handle constrained-type-specifiers for non-type template parameters. (finish_constrained_template_template_parm): Split out from cp_parser_constrained_template_template_parm. (cp_parser_nonclass_name): Move some logic into cp_parser_maybe_concept_name. (cp_parser_init_declarator): Fix error recovery. (get_concept_from_constraint): Remove. (cp_parser_simple_type_specifier): Adjust for synthesize_implicit_template_parm returning the decl. * constraint.cc (placeholder_extract_concept_and_args) (equivalent_placeholder_constraints): Also handle TYPE_DECL constrained parms. From-SVN: r229860 --- gcc/cp/ChangeLog | 19 +++ gcc/cp/constraint.cc | 37 +++-- gcc/cp/parser.c | 128 +++++++++--------- .../g++.dg/concepts/generic-fn-err.C | 4 +- gcc/testsuite/g++.dg/concepts/placeholder6.C | 10 ++ 5 files changed, 123 insertions(+), 75 deletions(-) create mode 100644 gcc/testsuite/g++.dg/concepts/placeholder6.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fbbb6cb8d0d..ce8a81f6a1e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,24 @@ 2015-11-06 Jason Merrill + Support non-type constrained-type-specifiers. + * parser.c (check_type_concept): Remove. + (cp_parser_maybe_constrained_type_specifier): Don't call it. + (synthesize_implicit_template_parm): Handle non-type and template + template parameters. Also compare extra args. Return the decl. + (cp_parser_template_argument): Handle constrained-type-specifiers for + non-type template parameters. + (finish_constrained_template_template_parm): Split out from + cp_parser_constrained_template_template_parm. + (cp_parser_nonclass_name): Move some logic into + cp_parser_maybe_concept_name. + (cp_parser_init_declarator): Fix error recovery. + (get_concept_from_constraint): Remove. + (cp_parser_simple_type_specifier): Adjust for + synthesize_implicit_template_parm returning the decl. + * constraint.cc (placeholder_extract_concept_and_args) + (equivalent_placeholder_constraints): Also handle TYPE_DECL + constrained parms. + * pt.c (push_inline_template_parms_recursive): Don't recreate the CONST_DECL. diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index a1fbf174ee8..c6eaf754606 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -1379,12 +1379,21 @@ make_constrained_auto (tree con, tree args) return decl; } -/* Given the predicate constraint T from a placeholder type, extract its - TMPL and ARGS. */ +/* Given the predicate constraint T from a constrained-type-specifier, extract + its TMPL and ARGS. FIXME why do we need two different forms of + constrained-type-specifier? */ void placeholder_extract_concept_and_args (tree t, tree &tmpl, tree &args) { + if (TREE_CODE (t) == TYPE_DECL) + { + /* A constrained parameter. */ + tmpl = DECL_TI_TEMPLATE (CONSTRAINED_PARM_CONCEPT (t)); + args = CONSTRAINED_PARM_EXTRA_ARGS (t); + return; + } + gcc_assert (TREE_CODE (t) == PRED_CONSTR); t = PRED_CONSTR_EXPR (t); gcc_assert (TREE_CODE (t) == CALL_EXPR @@ -1418,9 +1427,10 @@ placeholder_extract_concept_and_args (tree t, tree &tmpl, tree &args) bool equivalent_placeholder_constraints (tree c1, tree c2) { - if (TREE_CODE (c1) == TEMPLATE_TYPE_PARM) + if (c1 && TREE_CODE (c1) == TEMPLATE_TYPE_PARM) + /* A constrained auto. */ c1 = PLACEHOLDER_TYPE_CONSTRAINTS (c1); - if (TREE_CODE (c2) == TEMPLATE_TYPE_PARM) + if (c2 && TREE_CODE (c2) == TEMPLATE_TYPE_PARM) c2 = PLACEHOLDER_TYPE_CONSTRAINTS (c2); if (c1 == c2) @@ -1434,14 +1444,21 @@ equivalent_placeholder_constraints (tree c1, tree c2) if (t1 != t2) return false; - int len = TREE_VEC_LENGTH (a1); - if (len != TREE_VEC_LENGTH (a2)) - return false; + /* Skip the first argument to avoid infinite recursion on the placeholder auto itself. */ - for (int i = len-1; i > 0; --i) - if (!cp_tree_equal (TREE_VEC_ELT (a1, i), - TREE_VEC_ELT (a2, i))) + bool skip1 = (TREE_CODE (c1) == PRED_CONSTR); + bool skip2 = (TREE_CODE (c2) == PRED_CONSTR); + + int len1 = (a1 ? TREE_VEC_LENGTH (a1) : 0) - skip1; + int len2 = (a2 ? TREE_VEC_LENGTH (a2) : 0) - skip2; + + if (len1 != len2) + return false; + + for (int i = 0; i < len1; ++i) + if (!cp_tree_equal (TREE_VEC_ELT (a1, i + skip1), + TREE_VEC_ELT (a2, i + skip2))) return false; return true; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c6f57297e72..d1f4970f1eb 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -13871,18 +13871,9 @@ cp_parser_constrained_type_template_parm (cp_parser *parser, return error_mark_node; } -/* Finish parsing/processing a template template parameter by borrowing - the template parameter list from the prototype parameter. */ - static tree -cp_parser_constrained_template_template_parm (cp_parser *parser, - tree proto, - tree id, - cp_parameter_declarator *parmdecl) +finish_constrained_template_template_parm (tree proto, tree id) { - if (!cp_parser_check_constrained_type_parm (parser, parmdecl)) - return error_mark_node; - /* FIXME: This should probably be copied, and we may need to adjust the template parameter depths. */ tree saved_parms = current_template_parms; @@ -13896,6 +13887,20 @@ cp_parser_constrained_template_template_parm (cp_parser *parser, return parm; } +/* Finish parsing/processing a template template parameter by borrowing + the template parameter list from the prototype parameter. */ + +static tree +cp_parser_constrained_template_template_parm (cp_parser *parser, + tree proto, + tree id, + cp_parameter_declarator *parmdecl) +{ + if (!cp_parser_check_constrained_type_parm (parser, parmdecl)) + return error_mark_node; + return finish_constrained_template_template_parm (proto, id); +} + /* Create a new non-type template parameter from the given PARM declarator. */ @@ -14950,8 +14955,12 @@ cp_parser_template_argument (cp_parser* parser) /*check_dependency=*/true, /*ambiguous_decls=*/NULL, argument_start_token->location); - if (TREE_CODE (argument) != TEMPLATE_DECL - && TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE) + /* Handle a constrained-type-specifier for a non-type template + parameter. */ + if (tree decl = cp_parser_maybe_concept_name (parser, argument)) + argument = decl; + else if (TREE_CODE (argument) != TEMPLATE_DECL + && TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE) cp_parser_error (parser, "expected template-name"); } if (cp_parser_parse_definitely (parser)) @@ -15630,7 +15639,10 @@ cp_parser_simple_type_specifier (cp_parser* parser, } if (cxx_dialect >= cxx14) - type = synthesize_implicit_template_parm (parser, NULL_TREE); + { + type = synthesize_implicit_template_parm (parser, NULL_TREE); + type = TREE_TYPE (type); + } else type = error_mark_node; @@ -15949,19 +15961,6 @@ cp_parser_type_name (cp_parser* parser, bool typename_keyword_p) return type_decl; } -/* Returns true if proto is a type parameter, but not a template - template parameter. */ -static bool -check_type_concept (tree fn, tree proto) -{ - if (TREE_CODE (proto) != TYPE_DECL) - { - error ("invalid use of non-type concept %qD", fn); - return false; - } - return true; -} - /* Check if DECL and ARGS can form a constrained-type-specifier. If ARGS is non-null, we try to form a concept check of the form DECL where ? is a wildcard that matches any @@ -16009,13 +16008,6 @@ cp_parser_maybe_constrained_type_specifier (cp_parser *parser, if (processing_template_parmlist) return build_constrained_parameter (conc, proto, args); - /* In any other context, a concept must be a type concept. - - FIXME: A constrained-type-specifier can be a placeholder - of any kind. */ - if (!check_type_concept (conc, proto)) - return error_mark_node; - /* In a parameter-declaration-clause, constrained-type specifiers result in invented template parameters. */ if (parser->auto_is_implicit_function_template_parm_p) @@ -16046,7 +16038,13 @@ cp_parser_maybe_constrained_type_specifier (cp_parser *parser, static tree cp_parser_maybe_concept_name (cp_parser* parser, tree decl) { - return cp_parser_maybe_constrained_type_specifier (parser, decl, NULL_TREE); + if (flag_concepts + && (TREE_CODE (decl) == OVERLOAD + || BASELINK_P (decl) + || variable_concept_p (decl))) + return cp_parser_maybe_constrained_type_specifier (parser, decl, NULL_TREE); + else + return NULL_TREE; } /* Check if DECL and ARGS form a partial-concept-id. If so, @@ -16093,15 +16091,8 @@ cp_parser_nonclass_name (cp_parser* parser) type_decl = strip_using_decl (type_decl); /* If we found an overload set, then it may refer to a concept-name. */ - if (flag_concepts - && (TREE_CODE (type_decl) == OVERLOAD - || BASELINK_P (type_decl) - || variable_concept_p (type_decl))) - { - /* Determine whether the overload refers to a concept. */ - if (tree decl = cp_parser_maybe_concept_name (parser, type_decl)) - return decl; - } + if (tree decl = cp_parser_maybe_concept_name (parser, type_decl)) + type_decl = decl; if (TREE_CODE (type_decl) != TYPE_DECL && (objc_is_id (identifier) || objc_is_class_name (identifier))) @@ -18183,7 +18174,7 @@ cp_parser_init_declarator (cp_parser* parser, "attributes after parenthesized initializer ignored"); /* And now complain about a non-function implicit template. */ - if (bogus_implicit_tmpl) + if (bogus_implicit_tmpl && decl != error_mark_node) error_at (DECL_SOURCE_LOCATION (decl), "non-function %qD declared as implicit template", decl); @@ -36681,17 +36672,6 @@ tree_type_is_auto_or_concept (const_tree t) return TREE_TYPE (t) && is_auto_or_concept (TREE_TYPE (t)); } -/* Returns the template declaration being called or evaluated as - part of the constraint check. Note that T must be a predicate - constraint (it can't be any other kind of constraint). */ -static tree -get_concept_from_constraint (tree t) -{ - tree tmpl, args; - placeholder_extract_concept_and_args (t, tmpl, args); - return DECL_TEMPLATE_RESULT (tmpl); -} - /* Add an implicit template type parameter to the CURRENT_TEMPLATE_PARMS (creating a new template parameter list if necessary). Returns the newly created template type parm. */ @@ -36711,9 +36691,14 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr) tree t = parser->implicit_template_parms; while (t) { - tree c = get_concept_from_constraint (TREE_TYPE (t)); - if (c == CONSTRAINED_PARM_CONCEPT (constr)) - return TREE_VALUE (t); + if (equivalent_placeholder_constraints (TREE_TYPE (t), constr)) + { + tree d = TREE_VALUE (t); + if (TREE_CODE (d) == PARM_DECL) + /* Return the TEMPLATE_PARM_INDEX. */ + d = DECL_INITIAL (d); + return d; + } t = TREE_CHAIN (t); } } @@ -36823,9 +36808,23 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr) /* Synthesize a new template parameter and track the current template parameter chain with implicit_template_parms. */ + tree proto = constr ? DECL_INITIAL (constr) : NULL_TREE; tree synth_id = make_generic_type_name (); - tree synth_tmpl_parm = finish_template_type_parm (class_type_node, - synth_id); + tree synth_tmpl_parm; + bool non_type = false; + + if (proto == NULL_TREE || TREE_CODE (proto) == TYPE_DECL) + synth_tmpl_parm + = finish_template_type_parm (class_type_node, synth_id); + else if (TREE_CODE (proto) == TEMPLATE_DECL) + synth_tmpl_parm + = finish_constrained_template_template_parm (proto, synth_id); + else + { + synth_tmpl_parm = copy_decl (proto); + DECL_NAME (synth_tmpl_parm) = synth_id; + non_type = true; + } // Attach the constraint to the parm before processing. tree node = build_tree_list (NULL_TREE, synth_tmpl_parm); @@ -36834,7 +36833,7 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr) = process_template_parm (parser->implicit_template_parms, input_location, node, - /*non_type=*/false, + /*non_type=*/non_type, /*param_pack=*/false); // Chain the new parameter to the list of implicit parameters. @@ -36844,7 +36843,10 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr) else parser->implicit_template_parms = new_parm; - tree new_type = TREE_TYPE (getdecls ()); + tree new_decl = getdecls (); + if (non_type) + /* Return the TEMPLATE_PARM_INDEX, not the PARM_DECL. */ + new_decl = DECL_INITIAL (new_decl); /* If creating a fully implicit function template, start the new implicit template parameter list with this synthesized type, otherwise grow the @@ -36878,7 +36880,7 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr) current_binding_level = entry_scope; - return new_type; + return new_decl; } /* Finish the declaration of a fully implicit function template. Such a diff --git a/gcc/testsuite/g++.dg/concepts/generic-fn-err.C b/gcc/testsuite/g++.dg/concepts/generic-fn-err.C index c6b74571954..1e975108257 100644 --- a/gcc/testsuite/g++.dg/concepts/generic-fn-err.C +++ b/gcc/testsuite/g++.dg/concepts/generic-fn-err.C @@ -11,8 +11,8 @@ template class X> struct S { }; -void f1(Int) { } // { dg-error "invalid" } -void f2(Template) { } // { dg-error "invalid" } +void f1(Int) { } // { dg-error "" } +void f2(Template) { } // { dg-error "" } struct S1 { void f1(auto x) { } diff --git a/gcc/testsuite/g++.dg/concepts/placeholder6.C b/gcc/testsuite/g++.dg/concepts/placeholder6.C new file mode 100644 index 00000000000..7f2e67a9192 --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/placeholder6.C @@ -0,0 +1,10 @@ +// { dg-options -std=c++1z } + +template struct B { static const int i = I; }; +template concept bool Few = I < 10; + +constexpr int g(B b) { return b.i; } + +#define SA(X) static_assert((X),#X) +SA(g(B<2>{}) == 2); +SA(g(B<10>{}) == 10); // { dg-error "" } -- 2.30.2