From e922b256906a07da5571ed0258c4ee57a4b1859c Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 9 Nov 2016 15:02:56 -0500 Subject: [PATCH] Fix C++17 template placeholder for template template parm. * parser.c (cp_parser_simple_type_specifier): Allow placeholder for template template parameter. (cp_parser_type_id_1): Improve diagnostic. * decl.c (grokdeclarator): Handle class deduction diagnostics here. * pt.c (splice_late_return_type): Not here. (tsubst) [TEMPLATE_TYPE_PARM]: Substitute into placeholder template. (do_class_deduction): Handle non-class templates. From-SVN: r242018 --- gcc/cp/ChangeLog | 8 +++ gcc/cp/decl.c | 58 +++++++++++++++---- gcc/cp/parser.c | 52 ++++++++++------- gcc/cp/pt.c | 40 ++++++------- gcc/testsuite/g++.dg/cpp0x/variadic-ex1.C | 2 +- .../g++.dg/cpp1z/class-deduction21.C | 13 +++++ .../g++.dg/cpp1z/class-deduction22.C | 21 +++++++ .../g++.dg/cpp1z/class-deduction23.C | 10 ++++ gcc/testsuite/g++.old-deja/g++.pt/ttp10.C | 2 +- 9 files changed, 151 insertions(+), 55 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction21.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction22.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction23.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e220c5f8562..2e3b15d5579 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,13 @@ 2016-11-09 Jason Merrill + * parser.c (cp_parser_simple_type_specifier): Allow placeholder + for template template parameter. + (cp_parser_type_id_1): Improve diagnostic. + * decl.c (grokdeclarator): Handle class deduction diagnostics here. + * pt.c (splice_late_return_type): Not here. + (tsubst) [TEMPLATE_TYPE_PARM]: Substitute into placeholder template. + (do_class_deduction): Handle non-class templates. + Implement P0127R2, Declaring non-type parameters with auto. * cp-tree.h (enum auto_deduction_context): Add adc_unify. * decl.c (grokdeclarator): Allow 'auto' in C++17 template non-type diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index bd37faa8bfd..4b18d4ea761 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -9490,6 +9490,11 @@ grokdeclarator (const cp_declarator *declarator, if (initialized > 1) funcdef_flag = true; + location_t typespec_loc = smallest_type_quals_location (type_quals, + declspecs->locations); + if (typespec_loc == UNKNOWN_LOCATION) + typespec_loc = declspecs->locations[ds_type_spec]; + /* Look inside a declarator for the name being declared and get it as a string, for an error message. */ for (id_declarator = declarator; @@ -10011,6 +10016,16 @@ grokdeclarator (const cp_declarator *declarator, /* We might have ignored or rejected some of the qualifiers. */ type_quals = cp_type_quals (type); + if (cxx_dialect >= cxx1z && type && is_auto (type) + && innermost_code != cdk_function + && id_declarator && declarator != id_declarator) + if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (type)) + { + error_at (typespec_loc, "template placeholder type %qT must be followed " + "by a simple declarator-id", type); + inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here", tmpl); + } + staticp = 0; inlinep = decl_spec_seq_has_spec_p (declspecs, ds_inline); virtualp = decl_spec_seq_has_spec_p (declspecs, ds_virtual); @@ -10247,12 +10262,7 @@ grokdeclarator (const cp_declarator *declarator, { if (SCALAR_TYPE_P (type) || VOID_TYPE_P (type)) { - location_t loc; - loc = smallest_type_quals_location (type_quals, - declspecs->locations); - if (loc == UNKNOWN_LOCATION) - loc = declspecs->locations[ds_type_spec]; - warning_at (loc, OPT_Wignored_qualifiers, "type " + warning_at (typespec_loc, OPT_Wignored_qualifiers, "type " "qualifiers ignored on function return type"); } /* We now know that the TYPE_QUALS don't apply to the @@ -10301,11 +10311,12 @@ grokdeclarator (const cp_declarator *declarator, funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id; /* Handle a late-specified return type. */ + tree late_return_type = declarator->u.function.late_return_type; if (funcdecl_p) { - if (type_uses_auto (type)) + if (tree auto_node = type_uses_auto (type)) { - if (!declarator->u.function.late_return_type) + if (!late_return_type) { if (current_class_type && LAMBDA_TYPE_P (current_class_type)) @@ -10333,8 +10344,32 @@ grokdeclarator (const cp_declarator *declarator, name, type); return error_mark_node; } + if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) + { + if (!late_return_type) + { + if (dguide_name_p (unqualified_id)) + error_at (typespec_loc, "deduction guide for " + "%qT must have trailing return type", + TREE_TYPE (tmpl)); + else + error_at (typespec_loc, "deduced class type %qT " + "in function return type", type); + inform (DECL_SOURCE_LOCATION (tmpl), + "%qD declared here", tmpl); + } + else if (CLASS_TYPE_P (late_return_type) + && CLASSTYPE_TEMPLATE_INFO (late_return_type) + && (CLASSTYPE_TI_TEMPLATE (late_return_type) + == tmpl)) + /* OK */; + else + error ("trailing return type %qT of deduction guide " + "is not a specialization of %qT", + late_return_type, TREE_TYPE (tmpl)); + } } - else if (declarator->u.function.late_return_type + else if (late_return_type && sfk != sfk_conversion) { if (cxx_dialect < cxx11) @@ -10348,12 +10383,11 @@ grokdeclarator (const cp_declarator *declarator, return error_mark_node; } } - type = splice_late_return_type - (type, declarator->u.function.late_return_type); + type = splice_late_return_type (type, late_return_type); if (type == error_mark_node) return error_mark_node; - if (declarator->u.function.late_return_type) + if (late_return_type) late_return_type_p = true; if (ctype == NULL_TREE diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e4436485053..7b95dba72f2 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16596,7 +16596,8 @@ cp_parser_simple_type_specifier (cp_parser* parser, /*ambiguous_decls=*/NULL, token->location); if (tmpl && tmpl != error_mark_node - && DECL_CLASS_TEMPLATE_P (tmpl)) + && (DECL_CLASS_TEMPLATE_P (tmpl) + || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) type = make_template_placeholder (tmpl); else { @@ -20311,26 +20312,35 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg, && (!flag_concepts || parser->in_type_id_in_expr_p) /* None of the valid uses of 'auto' in C++14 involve the type-id nonterminal, but it is valid in a trailing-return-type. */ - && !(cxx_dialect >= cxx14 && is_trailing_return) - && type_uses_auto (type_specifier_seq.type)) - { - /* A type-id with type 'auto' is only ok if the abstract declarator - is a function declarator with a late-specified return type. - - A type-id with 'auto' is also valid in a trailing-return-type - in a compound-requirement. */ - if (abstract_declarator - && abstract_declarator->kind == cdk_function - && abstract_declarator->u.function.late_return_type) - /* OK */; - else if (parser->in_result_type_constraint_p) - /* OK */; - else - { - error ("invalid use of %"); - return error_mark_node; - } - } + && !(cxx_dialect >= cxx14 && is_trailing_return)) + if (tree auto_node = type_uses_auto (type_specifier_seq.type)) + { + /* A type-id with type 'auto' is only ok if the abstract declarator + is a function declarator with a late-specified return type. + + A type-id with 'auto' is also valid in a trailing-return-type + in a compound-requirement. */ + if (abstract_declarator + && abstract_declarator->kind == cdk_function + && abstract_declarator->u.function.late_return_type) + /* OK */; + else if (parser->in_result_type_constraint_p) + /* OK */; + else + { + location_t loc = type_specifier_seq.locations[ds_type_spec]; + if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) + { + error_at (loc, "missing template arguments after %qT", + auto_node); + inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here", + tmpl); + } + else + error_at (loc, "invalid use of %qT", auto_node); + return error_mark_node; + } + } return groktypename (&type_specifier_seq, abstract_declarator, is_template_arg); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 64e566e12b0..e8b6afd13ab 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13314,7 +13314,11 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) PLACEHOLDER_TYPE_CONSTRAINTS (r) = tsubst_constraint (constr, args, complain, in_decl); else if (tree pl = CLASS_PLACEHOLDER_TEMPLATE (t)) - CLASS_PLACEHOLDER_TEMPLATE (r) = pl; + { + if (DECL_TEMPLATE_TEMPLATE_PARM_P (pl)) + pl = tsubst (pl, args, complain, in_decl); + CLASS_PLACEHOLDER_TEMPLATE (r) = pl; + } } if (TREE_CODE (r) == TEMPLATE_TEMPLATE_PARM) @@ -24625,13 +24629,23 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain) return ded_tmpl; } -/* Deduce template arguments for the class template TMPL based on the - initializer INIT, and return the resulting type. */ +/* Deduce template arguments for the class template placeholder PTYPE for + template TMPL based on the initializer INIT, and return the resulting + type. */ tree -do_class_deduction (tree tmpl, tree init, tsubst_flags_t complain) +do_class_deduction (tree ptype, tree tmpl, tree init, tsubst_flags_t complain) { - gcc_assert (DECL_CLASS_TEMPLATE_P (tmpl)); + if (!DECL_CLASS_TEMPLATE_P (tmpl)) + { + /* We should have handled this in the caller. */ + if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)) + return ptype; + if (complain & tf_error) + error ("non-class template %qT used without template arguments", tmpl); + return error_mark_node; + } + tree type = TREE_TYPE (tmpl); vec *args; @@ -24733,7 +24747,7 @@ do_auto_deduction (tree type, tree init, tree auto_node, if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) /* C++17 class template argument deduction. */ - return do_class_deduction (tmpl, init, complain); + return do_class_deduction (type, tmpl, init, complain); /* [dcl.spec.auto]: Obtain P from T by replacing the occurrences of auto with either a new invented type template parameter U or, if the @@ -24881,20 +24895,6 @@ splice_late_return_type (tree type, tree late_return_type) { if (is_auto (type)) { - if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (type)) - { - if (!late_return_type) - error ("deduction guide must have trailing return type"); - else if (CLASS_TYPE_P (late_return_type) - && CLASSTYPE_TEMPLATE_INFO (late_return_type) - && CLASSTYPE_TI_TEMPLATE (late_return_type) == tmpl) - /* OK */; - else - error ("trailing return type %qT of deduction guide is not " - "a specialization of %qT", - late_return_type, TREE_TYPE (tmpl)); - } - if (late_return_type) return late_return_type; diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ex1.C b/gcc/testsuite/g++.dg/cpp0x/variadic-ex1.C index b3016040933..87b4b3575dd 100644 --- a/gcc/testsuite/g++.dg/cpp0x/variadic-ex1.C +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ex1.C @@ -1,4 +1,4 @@ // { dg-do compile { target c++11 } } template class Tuple; Tuple<>* t; // OK: Elements is empty -Tuple* u; // { dg-error "template-name" } +Tuple* u; // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction21.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction21.C new file mode 100644 index 00000000000..5eebef7cbaf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction21.C @@ -0,0 +1,13 @@ +// { dg-options -std=c++1z } + +template +struct S { T t; }; +template +S(U) -> S; + +struct A { + using type = short; + operator type(); +}; +S s{A()}; // OK +S x(A()); // { dg-error "return type" } diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction22.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction22.C new file mode 100644 index 00000000000..b15b0c4ad95 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction22.C @@ -0,0 +1,21 @@ +// { dg-options -std=c++1z } + +template