From 96c35892bea68ac180f19079cf08fea3b6cda0a8 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Sat, 1 Dec 2018 17:56:27 +0000 Subject: [PATCH] Implement P0634R3, Down with typename! * parser.c (CP_PARSER_FLAGS_TYPENAME_OPTIONAL): New enumerator. (cp_parser_type_name): Remove declaration. (cp_parser_postfix_expression): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL to cp_parser_type_id. (cp_parser_new_type_id): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL to cp_parser_type_specifier_seq. (cp_parser_lambda_declarator_opt): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL to cp_parser_parameter_declaration_clause. (cp_parser_condition): Pass CP_PARSER_FLAGS_NONE to cp_parser_declarator. (cp_parser_simple_declaration): Pass CP_PARSER_FLAGS_NONE to cp_parser_init_declarator. (cp_parser_conversion_type_id): Pass CP_PARSER_FLAGS_NONE to cp_parser_type_specifier_seq. (cp_parser_default_type_template_argument): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL to cp_parser_type_id. (cp_parser_template_parameter): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL to cp_parser_parameter_declaration. (cp_parser_explicit_instantiation): Pass CP_PARSER_FLAGS_NONE to cp_parser_declarator. (cp_parser_simple_type_specifier): Adjust call to cp_parser_type_name to relay if we should treat the typename keyword as optional. Maybe call cp_parser_make_typename_type is parsing a template-id and it's not a TYPE_DECL. (cp_parser_type_name): Remove unused function. (cp_parser_enum_specifier): Pass to CP_PARSER_FLAGS_NONE cp_parser_type_specifier_seq. (cp_parser_alias_declaration): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL to cp_parser_type_id. (cp_parser_init_declarator): New parameter. Pass it down to cp_parser_declarator. (cp_parser_declarator): New parameter. Pass CP_PARSER_FLAGS_NONE to cp_parser_declarator. Pass the new parameter to cp_parser_direct_declarator. (cp_parser_direct_declarator): New parameter. Pass it to cp_parser_parameter_declaration_clause and cp_parser_declarator. (cp_parser_declarator_id): (cp_parser_type_id_1): New parameter. Pass it to cp_parser_type_specifier_seq. Adjust call to cp_parser_declarator. (cp_parser_type_id): New parameter. Pass it to cp_parser_type_id_1. (cp_parser_template_type_arg): Pass CP_PARSER_FLAGS_NONE to cp_parser_type_id_1. (cp_parser_trailing_type_id): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL to cp_parser_type_id_1. (cp_parser_type_specifier_seq): New parameter. (function_being_declared_is_template_p): (cp_parser_parameter_declaration_clause): New parameter. Pass it to cp_parser_parameter_declaration_list. (cp_parser_parameter_declaration_list): New parameter. Pass it to cp_parser_parameter_declaration. (cp_parser_parameter_declaration): New parameter. Pass it to cp_parser_decl_specifier_seq. Pass CP_PARSER_FLAGS_NONE to cp_parser_declarator. (cp_parser_member_declaration): Adjust call to cp_parser_decl_specifier_seq to also include CP_PARSER_FLAGS_TYPENAME_OPTIONAL. Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL to cp_parser_declarator. (cp_parser_exception_declaration): Pass CP_PARSER_FLAGS_NONE to cp_parser_type_specifier_seq and cp_parser_declarator. (cp_parser_requirement_parameter_list): Pass CP_PARSER_FLAGS_NONE to cp_parser_parameter_declaration_clause. (cp_parser_constructor_declarator_p): Resolve the TYPENAME_TYPE. (cp_parser_single_declaration): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL to cp_parser_decl_specifier_seq and cp_parser_init_declarator. (cp_parser_cache_defarg): Pass CP_PARSER_FLAGS_NONE to cp_parser_declarator and cp_parser_parameter_declaration_list. (cp_parser_objc_method_tail_params_opt): Pass CP_PARSER_FLAGS_NONE to cp_parser_parameter_declaration. (cp_parser_objc_class_ivars): Pass CP_PARSER_FLAGS_NONE to cp_parser_declarator. (cp_parser_objc_try_catch_finally_statement): Pass CP_PARSER_FLAGS_NONE to cp_parser_parameter_declaration (cp_parser_objc_struct_declaration): Pass CP_PARSER_FLAGS_NONE to cp_parser_declarator. (cp_parser_omp_for_loop_init): Pass CP_PARSER_FLAGS_NONE to cp_parser_declarator and cp_parser_type_specifier_seq. * g++.dg/cpp0x/alias-decl-43.C: Adjust dg-error. * g++.dg/cpp0x/decltype67.C: Only expect error in c++17_down. * g++.dg/cpp1z/typename1.C: New test. * g++.dg/cpp2a/typename1.C: New test. * g++.dg/cpp2a/typename10.C: New test. * g++.dg/cpp2a/typename11.C: New test. * g++.dg/cpp2a/typename2.C: New test. * g++.dg/cpp2a/typename3.C: New test. * g++.dg/cpp2a/typename4.C: New test. * g++.dg/cpp2a/typename5.C: New test. * g++.dg/cpp2a/typename6.C: New test. * g++.dg/cpp2a/typename7.C: New test. * g++.dg/cpp2a/typename8.C: New test. * g++.dg/cpp2a/typename9.C: New test. * g++.dg/diagnostic/missing-typename.C: Only run the test in c++17_down. * g++.dg/other/crash-9.C: Add template disambiguator. * g++.dg/other/nontype-1.C: Only expect error in c++17_down. * g++.dg/parse/crash13.C: Likewise. * g++.dg/parse/error36.C: Likewise. * g++.dg/parse/no-typename1.C: Likewise. * g++.dg/parse/typedef2.C: Likewise. * g++.dg/parse/typename11.C: Likewise. * g++.dg/template/crash48.C: Adjust dg-error. * g++.dg/template/dependent-name5.C: Only expect error in c++17_down. Add dg-error. * g++.dg/template/error29.C: Only expect error in c++17_down. * g++.dg/template/nested5.C: Add template disambiguator. * g++.dg/template/pr84789.C: Only expect error in c++17_down. * g++.dg/template/static30.C: Add dg-error. * g++.dg/template/typedef6.C: Adjust dg-error. * g++.dg/template/typename3.C: Only expect error in c++17_down. From-SVN: r266710 --- gcc/cp/ChangeLog | 81 +++++++ gcc/cp/parser.c | 207 +++++++++++++----- gcc/testsuite/ChangeLog | 36 +++ gcc/testsuite/g++.dg/cpp0x/alias-decl-43.C | 2 +- gcc/testsuite/g++.dg/cpp0x/decltype67.C | 2 +- gcc/testsuite/g++.dg/cpp1z/typename1.C | 117 ++++++++++ gcc/testsuite/g++.dg/cpp2a/typename1.C | 42 ++++ gcc/testsuite/g++.dg/cpp2a/typename10.C | 20 ++ gcc/testsuite/g++.dg/cpp2a/typename11.C | 17 ++ gcc/testsuite/g++.dg/cpp2a/typename2.C | 22 ++ gcc/testsuite/g++.dg/cpp2a/typename3.C | 23 ++ gcc/testsuite/g++.dg/cpp2a/typename4.C | 8 + gcc/testsuite/g++.dg/cpp2a/typename5.C | 65 ++++++ gcc/testsuite/g++.dg/cpp2a/typename6.C | 126 +++++++++++ gcc/testsuite/g++.dg/cpp2a/typename7.C | 26 +++ gcc/testsuite/g++.dg/cpp2a/typename8.C | 20 ++ gcc/testsuite/g++.dg/cpp2a/typename9.C | 12 + .../g++.dg/diagnostic/missing-typename.C | 1 + gcc/testsuite/g++.dg/other/crash-9.C | 2 +- gcc/testsuite/g++.dg/other/nontype-1.C | 4 +- gcc/testsuite/g++.dg/parse/crash13.C | 4 +- gcc/testsuite/g++.dg/parse/error36.C | 4 +- gcc/testsuite/g++.dg/parse/no-typename1.C | 2 +- gcc/testsuite/g++.dg/parse/typedef2.C | 2 +- gcc/testsuite/g++.dg/parse/typename11.C | 4 +- gcc/testsuite/g++.dg/template/crash48.C | 2 +- .../g++.dg/template/dependent-name5.C | 8 +- gcc/testsuite/g++.dg/template/error29.C | 4 +- gcc/testsuite/g++.dg/template/nested5.C | 2 +- gcc/testsuite/g++.dg/template/pr84789.C | 2 +- gcc/testsuite/g++.dg/template/static30.C | 2 +- gcc/testsuite/g++.dg/template/typedef6.C | 2 +- gcc/testsuite/g++.dg/template/typename3.C | 2 +- 33 files changed, 789 insertions(+), 84 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/typename1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/typename1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/typename10.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/typename11.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/typename2.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/typename3.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/typename4.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/typename5.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/typename6.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/typename7.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/typename8.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/typename9.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index dbe4ad30bdb..92238849903 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,84 @@ +2018-12-01 Marek Polacek + + Implement P0634R3, Down with typename! + * parser.c (CP_PARSER_FLAGS_TYPENAME_OPTIONAL): New enumerator. + (cp_parser_type_name): Remove declaration. + (cp_parser_postfix_expression): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL + to cp_parser_type_id. + (cp_parser_new_type_id): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL to + cp_parser_type_specifier_seq. + (cp_parser_lambda_declarator_opt): Pass + CP_PARSER_FLAGS_TYPENAME_OPTIONAL to + cp_parser_parameter_declaration_clause. + (cp_parser_condition): Pass CP_PARSER_FLAGS_NONE to + cp_parser_declarator. + (cp_parser_simple_declaration): Pass CP_PARSER_FLAGS_NONE to + cp_parser_init_declarator. + (cp_parser_conversion_type_id): Pass CP_PARSER_FLAGS_NONE to + cp_parser_type_specifier_seq. + (cp_parser_default_type_template_argument): Pass + CP_PARSER_FLAGS_TYPENAME_OPTIONAL to cp_parser_type_id. + (cp_parser_template_parameter): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL + to cp_parser_parameter_declaration. + (cp_parser_explicit_instantiation): Pass CP_PARSER_FLAGS_NONE to + cp_parser_declarator. + (cp_parser_simple_type_specifier): Adjust call to cp_parser_type_name + to relay if we should treat the typename keyword as optional. Maybe + call cp_parser_make_typename_type is parsing a template-id and it's + not a TYPE_DECL. + (cp_parser_type_name): Remove unused function. + (cp_parser_enum_specifier): Pass to CP_PARSER_FLAGS_NONE + cp_parser_type_specifier_seq. + (cp_parser_alias_declaration): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL + to cp_parser_type_id. + (cp_parser_init_declarator): New parameter. Pass it down to + cp_parser_declarator. + (cp_parser_declarator): New parameter. Pass CP_PARSER_FLAGS_NONE to + cp_parser_declarator. Pass the new parameter to + cp_parser_direct_declarator. + (cp_parser_direct_declarator): New parameter. Pass it to + cp_parser_parameter_declaration_clause and cp_parser_declarator. + (cp_parser_declarator_id): + (cp_parser_type_id_1): New parameter. Pass it to + cp_parser_type_specifier_seq. Adjust call to cp_parser_declarator. + (cp_parser_type_id): New parameter. Pass it to cp_parser_type_id_1. + (cp_parser_template_type_arg): Pass CP_PARSER_FLAGS_NONE to + cp_parser_type_id_1. + (cp_parser_trailing_type_id): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL + to cp_parser_type_id_1. + (cp_parser_type_specifier_seq): New parameter. + (function_being_declared_is_template_p): + (cp_parser_parameter_declaration_clause): New parameter. Pass it to + cp_parser_parameter_declaration_list. + (cp_parser_parameter_declaration_list): New parameter. Pass it to + cp_parser_parameter_declaration. + (cp_parser_parameter_declaration): New parameter. Pass it to + cp_parser_decl_specifier_seq. Pass CP_PARSER_FLAGS_NONE to + cp_parser_declarator. + (cp_parser_member_declaration): Adjust call to + cp_parser_decl_specifier_seq to also include + CP_PARSER_FLAGS_TYPENAME_OPTIONAL. Pass + CP_PARSER_FLAGS_TYPENAME_OPTIONAL to cp_parser_declarator. + (cp_parser_exception_declaration): Pass CP_PARSER_FLAGS_NONE to + cp_parser_type_specifier_seq and cp_parser_declarator. + (cp_parser_requirement_parameter_list): Pass CP_PARSER_FLAGS_NONE to + cp_parser_parameter_declaration_clause. + (cp_parser_constructor_declarator_p): Resolve the TYPENAME_TYPE. + (cp_parser_single_declaration): Pass CP_PARSER_FLAGS_TYPENAME_OPTIONAL + to cp_parser_decl_specifier_seq and cp_parser_init_declarator. + (cp_parser_cache_defarg): Pass CP_PARSER_FLAGS_NONE to + cp_parser_declarator and cp_parser_parameter_declaration_list. + (cp_parser_objc_method_tail_params_opt): Pass CP_PARSER_FLAGS_NONE to + cp_parser_parameter_declaration. + (cp_parser_objc_class_ivars): Pass CP_PARSER_FLAGS_NONE to + cp_parser_declarator. + (cp_parser_objc_try_catch_finally_statement): Pass CP_PARSER_FLAGS_NONE + to cp_parser_parameter_declaration + (cp_parser_objc_struct_declaration): Pass CP_PARSER_FLAGS_NONE to + cp_parser_declarator. + (cp_parser_omp_for_loop_init): Pass CP_PARSER_FLAGS_NONE to + cp_parser_declarator and cp_parser_type_specifier_seq. + 2018-11-30 David Malcolm * typeck2.c: Include "gcc-rich-location.h". diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 634485b5a8c..e271e87a707 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1791,7 +1791,9 @@ enum constexpr. */ CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR = 0x8, /* When parsing a decl-specifier-seq, only allow mutable or constexpr. */ - CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10 + CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10, + /* When parsing a decl-specifier-seq, allow missing typename. */ + CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20 }; /* This type is used for parameters and variables which hold @@ -2156,8 +2158,6 @@ static tree cp_parser_simple_type_specifier (cp_parser *, cp_decl_specifier_seq *, cp_parser_flags); static tree cp_parser_type_name (cp_parser *, bool); -static tree cp_parser_type_name - (cp_parser *); static tree cp_parser_nonclass_name (cp_parser* parser); static tree cp_parser_elaborated_type_specifier @@ -2198,12 +2198,14 @@ static tree cp_parser_decomposition_declaration /* Declarators [gram.dcl.decl] */ static tree cp_parser_init_declarator - (cp_parser *, cp_decl_specifier_seq *, vec *, - bool, bool, int, bool *, tree *, location_t *, tree *); + (cp_parser *, cp_parser_flags, cp_decl_specifier_seq *, + vec *, bool, bool, int, bool *, tree *, + location_t *, tree *); static cp_declarator *cp_parser_declarator - (cp_parser *, cp_parser_declarator_kind, int *, bool *, bool, bool); + (cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool *, + bool, bool); static cp_declarator *cp_parser_direct_declarator - (cp_parser *, cp_parser_declarator_kind, int *, bool, bool); + (cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool, bool); static enum tree_code cp_parser_ptr_operator (cp_parser *, tree *, cp_cv_quals *, tree *); static cp_cv_quals cp_parser_cv_qualifier_seq_opt @@ -2219,20 +2221,20 @@ static tree cp_parser_late_return_type_opt static tree cp_parser_declarator_id (cp_parser *, bool); static tree cp_parser_type_id - (cp_parser *, location_t * = NULL); + (cp_parser *, cp_parser_flags = CP_PARSER_FLAGS_NONE, location_t * = NULL); static tree cp_parser_template_type_arg (cp_parser *); static tree cp_parser_trailing_type_id (cp_parser *); static tree cp_parser_type_id_1 - (cp_parser *, bool, bool, location_t *); + (cp_parser *, cp_parser_flags, bool, bool, location_t *); static void cp_parser_type_specifier_seq - (cp_parser *, bool, bool, cp_decl_specifier_seq *); + (cp_parser *, cp_parser_flags, bool, bool, cp_decl_specifier_seq *); static tree cp_parser_parameter_declaration_clause - (cp_parser *); + (cp_parser *, cp_parser_flags); static tree cp_parser_parameter_declaration_list - (cp_parser *); + (cp_parser *, cp_parser_flags); static cp_parameter_declarator *cp_parser_parameter_declaration - (cp_parser *, bool, bool *); + (cp_parser *, cp_parser_flags, bool, bool *); static tree cp_parser_default_argument (cp_parser *, bool); static void cp_parser_function_body @@ -6789,7 +6791,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, /* Parse the type to which we are casting. */ saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p; parser->in_type_id_in_expr_p = true; - type = cp_parser_type_id (parser); + type = cp_parser_type_id (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL, + NULL); parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; /* Look for the closing `>'. */ cp_parser_require (parser, CPP_GREATER, RT_GREATER); @@ -8710,7 +8713,8 @@ cp_parser_new_type_id (cp_parser* parser, tree *nelts) parser->type_definition_forbidden_message = G_("types may not be defined in a new-type-id"); /* Parse the type-specifier-seq. */ - cp_parser_type_specifier_seq (parser, /*is_declaration=*/false, + cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL, + /*is_declaration=*/false, /*is_trailing_return=*/false, &type_specifier_seq); /* Restore the old message. */ @@ -10727,7 +10731,9 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) begin_scope (sk_function_parms, /*entity=*/NULL_TREE); /* Parse parameters. */ - param_list = cp_parser_parameter_declaration_clause (parser); + param_list + = cp_parser_parameter_declaration_clause + (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL); /* Default arguments shall not be specified in the parameter-declaration-clause of a lambda-declarator. */ @@ -11913,6 +11919,7 @@ cp_parser_condition (cp_parser* parser) /* Parse the declarator. */ declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + CP_PARSER_FLAGS_NONE, /*ctor_dtor_or_conv_p=*/NULL, /*parenthesized_p=*/NULL, /*member_p=*/false, @@ -13387,7 +13394,9 @@ cp_parser_simple_declaration (cp_parser* parser, saw_declarator = true; /* Parse the init-declarator. */ - decl = cp_parser_init_declarator (parser, &decl_specifiers, + decl = cp_parser_init_declarator (parser, + CP_PARSER_FLAGS_NONE, + &decl_specifiers, /*checks=*/NULL, function_definition_allowed_p, /*member_p=*/false, @@ -14653,7 +14662,8 @@ cp_parser_conversion_type_id (cp_parser* parser) = G_("types may not be defined in a conversion-type-id"); /* Parse the type-specifiers. */ - cp_parser_type_specifier_seq (parser, /*is_declaration=*/false, + cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE, + /*is_declaration=*/false, /*is_trailing_return=*/false, &type_specifiers); @@ -15742,7 +15752,9 @@ cp_parser_default_type_template_argument (cp_parser *parser) /* Parse the default-argument. */ push_deferring_access_checks (dk_no_deferred); - tree default_argument = cp_parser_type_id (parser); + tree default_argument = cp_parser_type_id (parser, + CP_PARSER_FLAGS_TYPENAME_OPTIONAL, + NULL); pop_deferring_access_checks (); if (flag_concepts && type_uses_auto (default_argument)) @@ -15869,7 +15881,9 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type, of the template parameter-list rather than a greater-than operator. */ parameter_declarator - = cp_parser_parameter_declaration (parser, /*template_parm_p=*/true, + = cp_parser_parameter_declaration (parser, + CP_PARSER_FLAGS_TYPENAME_OPTIONAL, + /*template_parm_p=*/true, /*parenthesized_p=*/NULL); if (!parameter_declarator) @@ -17016,6 +17030,7 @@ cp_parser_explicit_instantiation (cp_parser* parser) /* Parse the declarator. */ declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + CP_PARSER_FLAGS_NONE, /*ctor_dtor_or_conv_p=*/NULL, /*parenthesized_p=*/NULL, /*member_p=*/false, @@ -17616,6 +17631,8 @@ cp_parser_simple_type_specifier (cp_parser* parser, { bool qualified_p; bool global_p; + const bool typename_p = (cxx_dialect >= cxx2a + && (flags & CP_PARSER_FLAGS_TYPENAME_OPTIONAL)); /* Don't gobble tokens or issue error messages if this is an optional type-specifier. */ @@ -17652,13 +17669,21 @@ cp_parser_simple_type_specifier (cp_parser* parser, luck. */ if (TREE_CODE (type) != TYPE_DECL) { - cp_parser_error (parser, "expected template-id for type"); - type = NULL_TREE; + /* ...unless we pretend we have seen 'typename'. */ + if (typename_p) + type = cp_parser_make_typename_type (parser, type, + token->location); + else + { + cp_parser_error (parser, "expected template-id for type"); + type = NULL_TREE; + } } } /* Otherwise, look for a type-name. */ else - type = cp_parser_type_name (parser); + type = cp_parser_type_name (parser, (qualified_p && typename_p)); + /* Keep track of all name-lookups performed in class scopes. */ if (type && !global_p @@ -17783,13 +17808,6 @@ cp_parser_simple_type_specifier (cp_parser* parser, Returns a TYPE_DECL for the type. */ -static tree -cp_parser_type_name (cp_parser* parser) -{ - return cp_parser_type_name (parser, /*typename_keyword_p=*/false); -} - -/* See above. */ static tree cp_parser_type_name (cp_parser* parser, bool typename_keyword_p) { @@ -18577,7 +18595,8 @@ cp_parser_enum_specifier (cp_parser* parser) cp_lexer_consume_token (parser->lexer); /* Parse the type-specifier-seq. */ - cp_parser_type_specifier_seq (parser, /*is_declaration=*/false, + cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE, + /*is_declaration=*/false, /*is_trailing_return=*/false, &type_specifiers); @@ -19434,7 +19453,8 @@ cp_parser_alias_declaration (cp_parser* parser) G_("types may not be defined in alias template declarations"); } - type = cp_parser_type_id (parser, &type_location); + type = cp_parser_type_id (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL, + &type_location); /* Restore the error message if need be. */ if (parser->num_template_parameter_lists) @@ -19814,6 +19834,8 @@ strip_declarator_types (tree type, cp_declarator *declarator) function-definition: decl-specifier-seq [opt] declarator function-transaction-block + The parser flags FLAGS is used to control type-specifier parsing. + The DECL_SPECIFIERS apply to this declarator. Returns a representation of the entity declared. If MEMBER_P is TRUE, then this declarator appears in a class scope. The new DECL created by @@ -19845,6 +19867,7 @@ strip_declarator_types (tree type, cp_declarator *declarator) static tree cp_parser_init_declarator (cp_parser* parser, + cp_parser_flags flags, cp_decl_specifier_seq *decl_specifiers, vec *checks, bool function_definition_allowed_p, @@ -19901,7 +19924,7 @@ cp_parser_init_declarator (cp_parser* parser, /* Parse the declarator. */ declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, - &ctor_dtor_or_conv_p, + flags, &ctor_dtor_or_conv_p, /*parenthesized_p=*/NULL, member_p, friend_p); /* Gather up the deferred checks. */ @@ -20300,6 +20323,8 @@ cp_parser_init_declarator (cp_parser* parser, attributes [opt] ptr-operator abstract-declarator [opt] attributes [opt] direct-abstract-declarator + The parser flags FLAGS is used to control type-specifier parsing. + If CTOR_DTOR_OR_CONV_P is not NULL, *CTOR_DTOR_OR_CONV_P is used to detect constructors, destructors, deduction guides, or conversion operators. It is set to -1 if the declarator is a name, and +1 if it is a @@ -20324,6 +20349,7 @@ cp_parser_init_declarator (cp_parser* parser, static cp_declarator * cp_parser_declarator (cp_parser* parser, cp_parser_declarator_kind dcl_kind, + cp_parser_flags flags, int* ctor_dtor_or_conv_p, bool* parenthesized_p, bool member_p, bool friend_p) @@ -20364,6 +20390,7 @@ cp_parser_declarator (cp_parser* parser, /* Parse the dependent declarator. */ declarator = cp_parser_declarator (parser, dcl_kind, + CP_PARSER_FLAGS_NONE, /*ctor_dtor_or_conv_p=*/NULL, /*parenthesized_p=*/NULL, /*member_p=*/false, @@ -20385,7 +20412,7 @@ cp_parser_declarator (cp_parser* parser, *parenthesized_p = cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN); declarator = cp_parser_direct_declarator (parser, dcl_kind, - ctor_dtor_or_conv_p, + flags, ctor_dtor_or_conv_p, member_p, friend_p); } @@ -20420,12 +20447,15 @@ cp_parser_declarator (cp_parser* parser, we are parsing a direct-declarator. It is CP_PARSER_DECLARATOR_EITHER, if we can accept either - in the case of ambiguity we prefer an abstract declarator, as per - [dcl.ambig.res]. CTOR_DTOR_OR_CONV_P, MEMBER_P, and FRIEND_P are + [dcl.ambig.res]. + The parser flags FLAGS is used to control type-specifier parsing. + CTOR_DTOR_OR_CONV_P, MEMBER_P, and FRIEND_P are as for cp_parser_declarator. */ static cp_declarator * cp_parser_direct_declarator (cp_parser* parser, cp_parser_declarator_kind dcl_kind, + cp_parser_flags flags, int* ctor_dtor_or_conv_p, bool member_p, bool friend_p) { @@ -20512,7 +20542,8 @@ cp_parser_direct_declarator (cp_parser* parser, begin_scope (sk_function_parms, NULL_TREE); /* Parse the parameter-declaration-clause. */ - params = cp_parser_parameter_declaration_clause (parser); + params + = cp_parser_parameter_declaration_clause (parser, flags); /* Consume the `)'. */ parens.require_close (parser); @@ -20603,7 +20634,8 @@ cp_parser_direct_declarator (cp_parser* parser, saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p; parser->in_type_id_in_expr_p = true; declarator - = cp_parser_declarator (parser, dcl_kind, ctor_dtor_or_conv_p, + = cp_parser_declarator (parser, dcl_kind, flags, + ctor_dtor_or_conv_p, /*parenthesized_p=*/NULL, member_p, friend_p); parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; @@ -21453,17 +21485,26 @@ cp_parser_declarator_id (cp_parser* parser, bool optional_p) type-id: type-specifier-seq abstract-declarator [opt] + The parser flags FLAGS is used to control type-specifier parsing. + + If IS_TEMPLATE_ARG is true, we are parsing a template argument. + + If IS_TRAILING_RETURN is true, we are in a trailing-return-type, + i.e. we've just seen "->". + Returns the TYPE specified. */ static tree -cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg, - bool is_trailing_return, location_t * type_location) +cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags, + bool is_template_arg, bool is_trailing_return, + location_t *type_location) { cp_decl_specifier_seq type_specifier_seq; cp_declarator *abstract_declarator; /* Parse the type-specifier-seq. */ - cp_parser_type_specifier_seq (parser, /*is_declaration=*/false, + cp_parser_type_specifier_seq (parser, flags, + /*is_declaration=*/false, is_trailing_return, &type_specifier_seq); if (type_location) @@ -21486,7 +21527,8 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg, cp_parser_parse_tentatively (parser); /* Look for the declarator. */ abstract_declarator - = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_ABSTRACT, NULL, + = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_ABSTRACT, + CP_PARSER_FLAGS_NONE, NULL, /*parenthesized_p=*/NULL, /*member_p=*/false, /*friend_p=*/false); @@ -21533,12 +21575,17 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg, is_template_arg); } +/* Wrapper for cp_parser_type_id_1. */ + static tree -cp_parser_type_id (cp_parser *parser, location_t * type_location) +cp_parser_type_id (cp_parser *parser, cp_parser_flags flags, + location_t *type_location) { - return cp_parser_type_id_1 (parser, false, false, type_location); + return cp_parser_type_id_1 (parser, flags, false, false, type_location); } +/* Wrapper for cp_parser_type_id_1. */ + static tree cp_parser_template_type_arg (cp_parser *parser) { @@ -21546,7 +21593,7 @@ cp_parser_template_type_arg (cp_parser *parser) const char *saved_message = parser->type_definition_forbidden_message; parser->type_definition_forbidden_message = G_("types may not be defined in template arguments"); - r = cp_parser_type_id_1 (parser, true, false, NULL); + r = cp_parser_type_id_1 (parser, CP_PARSER_FLAGS_NONE, true, false, NULL); parser->type_definition_forbidden_message = saved_message; if (cxx_dialect >= cxx14 && !flag_concepts && type_uses_auto (r)) { @@ -21556,10 +21603,13 @@ cp_parser_template_type_arg (cp_parser *parser) return r; } +/* Wrapper for cp_parser_type_id_1. */ + static tree cp_parser_trailing_type_id (cp_parser *parser) { - return cp_parser_type_id_1 (parser, false, true, NULL); + return cp_parser_type_id_1 (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL, + false, true, NULL); } /* Parse a type-specifier-seq. @@ -21572,6 +21622,8 @@ cp_parser_trailing_type_id (cp_parser *parser) type-specifier-seq: attributes type-specifier-seq [opt] + The parser flags FLAGS is used to control type-specifier parsing. + If IS_DECLARATION is true, we are at the start of a "condition" or exception-declaration, so we might be followed by a declarator-id. @@ -21582,17 +21634,18 @@ cp_parser_trailing_type_id (cp_parser *parser) static void cp_parser_type_specifier_seq (cp_parser* parser, + cp_parser_flags flags, bool is_declaration, bool is_trailing_return, cp_decl_specifier_seq *type_specifier_seq) { bool seen_type_specifier = false; - cp_parser_flags flags = CP_PARSER_FLAGS_OPTIONAL; cp_token *start_token = NULL; /* Clear the TYPE_SPECIFIER_SEQ. */ clear_decl_specs (type_specifier_seq); + flags |= CP_PARSER_FLAGS_OPTIONAL; /* In the context of a trailing return type, enum E { } is an elaborated-type-specifier followed by a function-body, not an enum-specifier. */ @@ -21698,12 +21751,15 @@ function_being_declared_is_template_p (cp_parser* parser) parameter-declaration-list [opt] ... [opt] parameter-declaration-list , ... + The parser flags FLAGS is used to control type-specifier parsing. + Returns a representation for the parameter declarations. A return value of NULL indicates a parameter-declaration-clause consisting only of an ellipsis. */ static tree -cp_parser_parameter_declaration_clause (cp_parser* parser) +cp_parser_parameter_declaration_clause (cp_parser* parser, + cp_parser_flags flags) { tree parameters; cp_token *token; @@ -21746,7 +21802,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser) } /* Parse the parameter-declaration-list. */ - parameters = cp_parser_parameter_declaration_list (parser); + parameters = cp_parser_parameter_declaration_list (parser, flags); /* If a parse error occurred while parsing the parameter-declaration-list, then the entire parameter-declaration-clause is erroneous. */ @@ -21789,12 +21845,14 @@ cp_parser_parameter_declaration_clause (cp_parser* parser) parameter-declaration parameter-declaration-list , parameter-declaration + The parser flags FLAGS is used to control type-specifier parsing. + Returns a representation of the parameter-declaration-list, as for cp_parser_parameter_declaration_clause. However, the `void_list_node' is never appended to the list. */ static tree -cp_parser_parameter_declaration_list (cp_parser* parser) +cp_parser_parameter_declaration_list (cp_parser* parser, cp_parser_flags flags) { tree parameters = NULL_TREE; tree *tail = ¶meters; @@ -21817,7 +21875,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser) /* Parse the parameter. */ parameter - = cp_parser_parameter_declaration (parser, + = cp_parser_parameter_declaration (parser, flags, /*template_parm_p=*/false, &parenthesized_p); @@ -21949,6 +22007,8 @@ cp_parser_parameter_declaration_list (cp_parser* parser) decl-specifier-seq ... [opt] abstract-declarator [opt] decl-specifier-seq abstract-declarator [opt] = assignment-expression + The parser flags FLAGS is used to control type-specifier parsing. + If TEMPLATE_PARM_P is TRUE, then this parameter-declaration declares a template parameter. (In that case, a non-nested `>' token encountered during the parsing of the assignment-expression @@ -21960,6 +22020,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser) static cp_parameter_declarator * cp_parser_parameter_declaration (cp_parser *parser, + cp_parser_flags flags, bool template_parm_p, bool *parenthesized_p) { @@ -21992,7 +22053,7 @@ cp_parser_parameter_declaration (cp_parser *parser, /* Parse the declaration-specifiers. */ cp_token *decl_spec_token_start = cp_lexer_peek_token (parser->lexer); cp_parser_decl_specifier_seq (parser, - CP_PARSER_FLAGS_NONE, + flags, &decl_specifiers, &declares_class_or_enum); @@ -22051,6 +22112,7 @@ cp_parser_parameter_declaration (cp_parser *parser, declarator_token_start = token; declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_EITHER, + CP_PARSER_FLAGS_NONE, /*ctor_dtor_or_conv_p=*/NULL, parenthesized_p, /*member_p=*/false, @@ -24024,7 +24086,8 @@ cp_parser_member_declaration (cp_parser* parser) /* Parse the decl-specifier-seq. */ decl_spec_token_start = cp_lexer_peek_token (parser->lexer); cp_parser_decl_specifier_seq (parser, - CP_PARSER_FLAGS_OPTIONAL, + (CP_PARSER_FLAGS_OPTIONAL + | CP_PARSER_FLAGS_TYPENAME_OPTIONAL), &decl_specifiers, &declares_class_or_enum); /* Check for an invalid type-name. */ @@ -24261,6 +24324,7 @@ cp_parser_member_declaration (cp_parser* parser) /* Parse the declarator. */ declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + CP_PARSER_FLAGS_TYPENAME_OPTIONAL, &ctor_dtor_or_conv_p, /*parenthesized_p=*/NULL, /*member_p=*/true, @@ -25132,7 +25196,8 @@ cp_parser_exception_declaration (cp_parser* parser) = G_("types may not be defined in exception-declarations"); /* Parse the type-specifier-seq. */ - cp_parser_type_specifier_seq (parser, /*is_declaration=*/true, + cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE, + /*is_declaration=*/true, /*is_trailing_return=*/false, &type_specifiers); /* If it's a `)', then there is no declarator. */ @@ -25140,6 +25205,7 @@ cp_parser_exception_declaration (cp_parser* parser) declarator = NULL; else declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_EITHER, + CP_PARSER_FLAGS_NONE, /*ctor_dtor_or_conv_p=*/NULL, /*parenthesized_p=*/NULL, /*member_p=*/false, @@ -26295,7 +26361,8 @@ cp_parser_requirement_parameter_list (cp_parser *parser) if (!parens.require_open (parser)) return error_mark_node; - tree parms = cp_parser_parameter_declaration_clause (parser); + tree parms + = cp_parser_parameter_declaration_clause (parser, CP_PARSER_FLAGS_NONE); if (!parens.require_close (parser)) return error_mark_node; @@ -27049,6 +27116,16 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p) /*type_p=*/false, /*is_declaration=*/false)); + /* Resolve the TYPENAME_TYPE, because the call above didn't do it. */ + if (nested_name_specifier + && TREE_CODE (nested_name_specifier) == TYPENAME_TYPE) + { + tree s = resolve_typename_type (nested_name_specifier, + /*only_current_p=*/false); + if (TREE_CODE (s) != TYPENAME_TYPE) + nested_name_specifier = s; + } + outside_class_specifier_p = (!at_class_scope_p () || !TYPE_BEING_DEFINED (current_class_type) || friend_p); @@ -27727,7 +27804,8 @@ cp_parser_single_declaration (cp_parser* parser, alternative. */ decl_spec_token_start = cp_lexer_peek_token (parser->lexer); cp_parser_decl_specifier_seq (parser, - CP_PARSER_FLAGS_OPTIONAL, + (CP_PARSER_FLAGS_OPTIONAL + | CP_PARSER_FLAGS_TYPENAME_OPTIONAL), &decl_specifiers, &declares_class_or_enum); if (friend_p) @@ -27817,6 +27895,7 @@ cp_parser_single_declaration (cp_parser* parser, || decl_specifiers.type != error_mark_node)) { decl = cp_parser_init_declarator (parser, + CP_PARSER_FLAGS_TYPENAME_OPTIONAL, &decl_specifiers, checks, /*function_definition_allowed_p=*/true, @@ -29451,6 +29530,7 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi) int ctor_dtor_or_conv_p; cp_lexer_consume_token (parser->lexer); cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + CP_PARSER_FLAGS_NONE, &ctor_dtor_or_conv_p, /*parenthesized_p=*/NULL, /*member_p=*/true, @@ -29470,8 +29550,9 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi) { cp_lexer_consume_token (parser->lexer); begin_scope (sk_function_parms, NULL_TREE); - if (cp_parser_parameter_declaration_list (parser) - == error_mark_node) + tree t = cp_parser_parameter_declaration_list + (parser, CP_PARSER_FLAGS_NONE); + if (t == error_mark_node) error = true; pop_bindings_and_leave_scope (); } @@ -30486,7 +30567,8 @@ cp_parser_objc_method_tail_params_opt (cp_parser* parser, bool *ellipsisp, } /* TODO: parse attributes for tail parameters. */ - parmdecl = cp_parser_parameter_declaration (parser, false, NULL); + parmdecl = cp_parser_parameter_declaration (parser, CP_PARSER_FLAGS_NONE, + false, NULL); parm = grokdeclarator (parmdecl->declarator, &parmdecl->decl_specifiers, PARM, /*initialized=*/0, @@ -30815,6 +30897,7 @@ cp_parser_objc_class_ivars (cp_parser* parser) /* Parse the declarator. */ declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + CP_PARSER_FLAGS_NONE, &ctor_dtor_or_conv_p, /*parenthesized_p=*/NULL, /*member_p=*/false, @@ -31168,7 +31251,8 @@ cp_parser_objc_try_catch_finally_statement (cp_parser *parser) { /* We have "@catch (NSException *exception)" or something like that. Parse the parameter declaration. */ - parm = cp_parser_parameter_declaration (parser, false, NULL); + parm = cp_parser_parameter_declaration (parser, CP_PARSER_FLAGS_NONE, + false, NULL); if (parm == NULL) parameter_declaration = error_mark_node; else @@ -31374,6 +31458,7 @@ cp_parser_objc_struct_declaration (cp_parser *parser) /* Parse the declarator. */ declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + CP_PARSER_FLAGS_NONE, NULL, NULL, false, false); /* Look for attributes that apply to the ivar. */ @@ -35985,7 +36070,8 @@ cp_parser_omp_for_loop_init (cp_parser *parser, cp_parser_condition, from whence the bulk of this is copied. */ cp_parser_parse_tentatively (parser); - cp_parser_type_specifier_seq (parser, /*is_declaration=*/true, + cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE, + /*is_declaration=*/true, /*is_trailing_return=*/false, &type_specifiers); if (cp_parser_parse_definitely (parser)) @@ -35997,6 +36083,7 @@ cp_parser_omp_for_loop_init (cp_parser *parser, declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + CP_PARSER_FLAGS_NONE, /*ctor_dtor_or_conv_p=*/NULL, /*parenthesized_p=*/NULL, /*member_p=*/false, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 18e08062163..610a26453fa 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,39 @@ +2018-12-01 Marek Polacek + + Implement P0634R3, Down with typename! + * g++.dg/cpp0x/alias-decl-43.C: Adjust dg-error. + * g++.dg/cpp0x/decltype67.C: Only expect error in c++17_down. + * g++.dg/cpp1z/typename1.C: New test. + * g++.dg/cpp2a/typename1.C: New test. + * g++.dg/cpp2a/typename10.C: New test. + * g++.dg/cpp2a/typename11.C: New test. + * g++.dg/cpp2a/typename2.C: New test. + * g++.dg/cpp2a/typename3.C: New test. + * g++.dg/cpp2a/typename4.C: New test. + * g++.dg/cpp2a/typename5.C: New test. + * g++.dg/cpp2a/typename6.C: New test. + * g++.dg/cpp2a/typename7.C: New test. + * g++.dg/cpp2a/typename8.C: New test. + * g++.dg/cpp2a/typename9.C: New test. + * g++.dg/diagnostic/missing-typename.C: Only run the test in + c++17_down. + * g++.dg/other/crash-9.C: Add template disambiguator. + * g++.dg/other/nontype-1.C: Only expect error in c++17_down. + * g++.dg/parse/crash13.C: Likewise. + * g++.dg/parse/error36.C: Likewise. + * g++.dg/parse/no-typename1.C: Likewise. + * g++.dg/parse/typedef2.C: Likewise. + * g++.dg/parse/typename11.C: Likewise. + * g++.dg/template/crash48.C: Adjust dg-error. + * g++.dg/template/dependent-name5.C: Only expect error in c++17_down. + Add dg-error. + * g++.dg/template/error29.C: Only expect error in c++17_down. + * g++.dg/template/nested5.C: Add template disambiguator. + * g++.dg/template/pr84789.C: Only expect error in c++17_down. + * g++.dg/template/static30.C: Add dg-error. + * g++.dg/template/typedef6.C: Adjust dg-error. + * g++.dg/template/typename3.C: Only expect error in c++17_down. + 2018-12-01 Jeff Law * gcc.dg/predict-22.c: Update expected output. diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-43.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-43.C index 02eb33643ac..f9b4477448b 100644 --- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-43.C +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-43.C @@ -1,4 +1,4 @@ // PR c++/59120 // { dg-do compile { target c++11 } } -template using X = int T::T*; // { dg-error "expected" } +template using X = int T::T*; // { dg-error "expected|two or more" } diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype67.C b/gcc/testsuite/g++.dg/cpp0x/decltype67.C index e8042ac59e7..f3bf9a24b04 100644 --- a/gcc/testsuite/g++.dg/cpp0x/decltype67.C +++ b/gcc/testsuite/g++.dg/cpp0x/decltype67.C @@ -3,5 +3,5 @@ template struct A { - void foo(decltype(T())::Y); // { dg-error {decltype\(T\(\)\)::Y} } + void foo(decltype(T())::Y); // { dg-error "decltype\\(T\\(\\)\\)::Y" "" { target c++17_down } } }; diff --git a/gcc/testsuite/g++.dg/cpp1z/typename1.C b/gcc/testsuite/g++.dg/cpp1z/typename1.C new file mode 100644 index 00000000000..4c598c839f2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/typename1.C @@ -0,0 +1,117 @@ +// P0634R3 +// { dg-do compile { target c++17_only } } + +// (5.2.1) simple-declaration or a function-definition in namespace scope + +template +T::X fn1 (int); // { dg-error "need .typename." } + +template +T::X fn1 (int) // { dg-error "need .typename." } +{ + return 42; +} + +template +T::X v1; // { dg-error "need .typename." } + +namespace N { + template + T::X v2; // { dg-error "need .typename." } +} + +// (5.2.2) member-declaration + +template +struct S { + [[noreturn]] T::X fn2 (); // { dg-error "need .typename." } + T::X fn3 (); // { dg-error "need .typename." } + T::X fn4 () { return 5; } // { dg-error "need .typename." } + T::X fn5 () final; // { dg-error "need .typename." } + T::X fn6 () = 0; // { dg-error "need .typename." } + T::X fn8 () override; // { dg-error "need .typename." } + T::X v3; // { dg-error "need .typename." } + T::X *v4; // { dg-error "need .typename." } + T::X v5[5]; // { dg-error "need .typename." } + T::X v6 = 0; // { dg-error "need .typename." } + T::X v7{0}; // { dg-error "need .typename.|;" } + T::X v8 : 16; // { dg-error "need .typename." } + static constexpr T::X v9 = 0; // { dg-error "need .typename." } + typedef T::X T2; // { dg-error "need .typename." } + friend T::X fn7 (); // { dg-error "need .typename." } + static inline T::X v10; // { dg-error "need .typename." } +}; + +// (5.2.3) parameter-declaration in a member-declaration, +// unless that parameter-declaration appears in a default argument + +template +struct S2 { + friend int fn1 (); // { dg-error "" } + int fn2 (T::X p); // { dg-error "not a type" } + int fn5 (int = T::X); +}; + +// (5.2.4) parameter-declaration in a declarator of a function or function +// template declaration whose declarator-id is qualified, +// unless that parameter-declaration appears in a default argument +template +int fn3 (T::X); + +template +int fn4 (T::X p) { return p; } // { dg-error "" } + +// (5.2.6) parameter-declaration of a (non-type) template-parameter + +template // { dg-error "not a type" } +struct S3 { }; + +// default argument of a type-parameter of a template +template // { dg-error "need .typename." } +struct S4 { }; + +// type-id of a static_cast, const_cast, reinterpret_cast, or dynamic_cast +template +struct S5 { + void fn6 (T::X p) // { dg-error "not a type" } + { + int i = static_cast(p); // { dg-error "need .typename." } + i = dynamic_cast(p); // { dg-error "need .typename." } + i = reinterpret_cast(p); // { dg-error "need .typename." } + i = const_cast(p); // { dg-error "need .typename." } + } +}; + +template +void fn7 (T::X p) // { dg-error "" } +{ + int i = static_cast(p); + i = dynamic_cast(p); + i = reinterpret_cast(p); + i = const_cast(p); +} + +// new-type-id +template +void +fn8 () +{ + new T::X[10]; // { dg-error "need .typename." } +} + +// defining-type-id + +template +struct W { typedef int M; }; + +template +struct S6 { + using TT = T::X; // { dg-error "need .typename." } + using TT2 = W::M; // { dg-error "need .typename." } +}; + +// trailing-return-type +template +struct S7 { + auto fn9() -> W::M; // { dg-error "need .typename." } +}; diff --git a/gcc/testsuite/g++.dg/cpp2a/typename1.C b/gcc/testsuite/g++.dg/cpp2a/typename1.C new file mode 100644 index 00000000000..833d3b86093 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/typename1.C @@ -0,0 +1,42 @@ +// P0634R3 +// { dg-do compile { target c++2a } } + +// OK, return type of a function declaration at global scope. +template T::R f(); + +// Ill-formed (no diagnostic required), attempt to declare +// a void variable template +template void f(T::R); + +template struct A; +template using B = A::U; + +template +struct PtrTraits { typedef int Ptr; }; + +template struct S { + // OK, in a defining-type-id. + using Ptr = PtrTraits::Ptr; + + // OK, trailing-return-type. + auto g() -> S::Ptr; + + // OK, class scope + T::R + f (T::P p) + { + // OK, type-id of a static_cast + return static_cast(p); + } +}; + +template +void f () +{ + // Variable pf of type void* initialized with T::X + void (*pf)(T::X); + + // Error: T::X at block scope does not denote a type + // (attempt to declare a void variable) + void g(T::X); // { dg-error "declared void" } +} diff --git a/gcc/testsuite/g++.dg/cpp2a/typename10.C b/gcc/testsuite/g++.dg/cpp2a/typename10.C new file mode 100644 index 00000000000..fa2cd000b5d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/typename10.C @@ -0,0 +1,20 @@ +// P0634R3 +// { dg-do compile { target c++2a } } + +namespace N { + // template extern T::type v; // #1a + template T::type v(typename T::value); // #1b +} +template T::type N::v(T::value); // #2 + +namespace N2 { + template extern T::type v; // #1a + //template T::type v(typename T::value); // #1b +} +template T::type N2::v(T::value); // { dg-error "" } + +namespace A { + inline namespace B { template int f(typename T::foo); } + inline namespace C { template extern int f; } +} +template int A::f(T::foo); // { dg-error "ambiguous" } diff --git a/gcc/testsuite/g++.dg/cpp2a/typename11.C b/gcc/testsuite/g++.dg/cpp2a/typename11.C new file mode 100644 index 00000000000..ed7ad958f62 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/typename11.C @@ -0,0 +1,17 @@ +// P0634R3 +// { dg-do compile { target c++2a } } + +template +struct A +{ + typedef int I; +}; + +template struct B +{ + A::I i; + typename A::I i2; + + A::I i3; + typename A::I i4; +}; diff --git a/gcc/testsuite/g++.dg/cpp2a/typename2.C b/gcc/testsuite/g++.dg/cpp2a/typename2.C new file mode 100644 index 00000000000..7c926177004 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/typename2.C @@ -0,0 +1,22 @@ +// P0634R3 +// { dg-do compile { target c++2a } } + +template typename T::R f(); + +template struct A; +template using B = typename A::U; + +template +struct PtrTraits { typedef int Ptr; }; + +template struct S { + using Ptr = typename PtrTraits::Ptr; + + auto g() -> typename S::Ptr; + + typename T::R + f (typename T::P p) + { + return static_cast(p); + } +}; diff --git a/gcc/testsuite/g++.dg/cpp2a/typename3.C b/gcc/testsuite/g++.dg/cpp2a/typename3.C new file mode 100644 index 00000000000..e64aa0316ef --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/typename3.C @@ -0,0 +1,23 @@ +// P0634R3 +// { dg-do compile { target c++2a } } + +template +void f(int i) +{ + T::x * i; // { dg-error "dependent-name" } +} + +struct Foo { + typedef int x; +}; + +struct Bar { + static int const x = 5; +}; + +int +main () +{ + f(1); + f(1); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/typename4.C b/gcc/testsuite/g++.dg/cpp2a/typename4.C new file mode 100644 index 00000000000..69154e7daaf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/typename4.C @@ -0,0 +1,8 @@ +// P0634R3 +// { dg-do compile { target c++2a } } + +template +struct A { + typedef int B; + B b; +}; diff --git a/gcc/testsuite/g++.dg/cpp2a/typename5.C b/gcc/testsuite/g++.dg/cpp2a/typename5.C new file mode 100644 index 00000000000..97c27adafcc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/typename5.C @@ -0,0 +1,65 @@ +// P0634R3 +// { dg-do compile { target c++2a } } + +struct X { + template + struct N { }; +}; + +template +struct Y { + template + struct N { }; +}; + +template +struct A +{ + template + struct N { }; + + typedef typename A::template N a1; + typedef typename A::template N a2; + typename A::template N a3; + typename A::template N a4; + A::template N a9; + A::template N a10; + typedef A::template N a13; + typedef A::template N a14; + + typedef typename X::template N x1; + typedef typename X::template N x2; + typename X::template N x3; + typename X::template N x4; + typedef X::N x5; + typedef X::N x6; + typedef typename X::N x7; + typedef typename X::N x8; + X::N x9; + X::N x10; + typename X::N x11; + typename X::N x12; + + typedef typename Y::template N y1; + typedef typename Y::template N y2; + typedef typename Y::template N y3; + typedef typename Y::template N y4; + typename Y::template N y5; + typename Y::template N y6; + typename Y::template N y7; + typename Y::template N y8; + typedef Y::N y9; + typedef Y::N y10; + typedef Y::template N y11; + typedef Y::template N y12; + typedef typename Y::N y13; + typedef typename Y::N y14; + Y::N y17; + Y::N y18; + typename Y::N y21; + typename Y::N y22; + typedef Y::N y25; + typedef Y::N y26; + typedef Y::template N y27; + typedef Y::template N y28; +}; diff --git a/gcc/testsuite/g++.dg/cpp2a/typename6.C b/gcc/testsuite/g++.dg/cpp2a/typename6.C new file mode 100644 index 00000000000..49e2235a53d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/typename6.C @@ -0,0 +1,126 @@ +// P0634R3 +// { dg-do compile { target c++2a } } + +// (5.2.1) simple-declaration or a function-definition in namespace scope + +template +T::X fn1 (int); + +template +T::X fn1 (int) +{ + return 42; +} + +template +T::X v1; + +namespace N { + template + T::X v2; +} + +// (5.2.2) member-declaration + +template +struct S { + [[noreturn]] T::X fn2 (); + T::X fn3 (); + T::X fn4 () { return 5; } + T::X fn5 () final; + T::X fn6 () = 0; + T::X fn8 () override; + T::X v3; + T::X *v4; + T::X v5[5]; + T::X v6 = 0; + T::X v7{0}; + T::X v8 : 16; + static constexpr T::X v9 = 0; + typedef T::X T2; + friend T::X fn7 (); + static inline T::X v10; +}; + +// (5.2.3) parameter-declaration in a member-declaration, +// unless that parameter-declaration appears in a default argument + +template +struct S2 { + friend int fn1 (); + int fn2 (T::X p); + int fn5 (int = T::X); +}; + +// (5.2.4) parameter-declaration in a declarator of a function or function +// template declaration whose declarator-id is qualified, +// unless that parameter-declaration appears in a default argument +template +int fn3 (T::X); + +template +int fn4 (T::X p) { return p; } + +// (5.2.5) parameter-declaration in a lambda-declarator, +// unless that parameter-declaration appears in a default argument + +void +fn5 () +{ + auto j = [](T::X t, int i) { return i; }; +} + +// (5.2.6) parameter-declaration of a (non-type) template-parameter + +template +struct S3 { }; + +// default argument of a type-parameter of a template +template +struct S4 { }; + +// type-id of a static_cast, const_cast, reinterpret_cast, or dynamic_cast +template +struct S5 { + void fn6 (T::X p) + { + int i = static_cast(p); + i = dynamic_cast(p); + i = reinterpret_cast(p); + i = const_cast(p); + } +}; + +template +void fn7 (T::X p) +{ + int i = static_cast(p); + i = dynamic_cast(p); + i = reinterpret_cast(p); + i = const_cast(p); +} + +// new-type-id +template +void +fn8 () +{ + new T::X[10]; +} + +// defining-type-id + +template +struct W { typedef int M; }; + +template +struct S6 { + using TT = T::X; + using TT2 = W::M; +}; + +// trailing-return-type +template +struct S7 { + auto fn9() -> W::M; +}; diff --git a/gcc/testsuite/g++.dg/cpp2a/typename7.C b/gcc/testsuite/g++.dg/cpp2a/typename7.C new file mode 100644 index 00000000000..713db51d972 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/typename7.C @@ -0,0 +1,26 @@ +// P0634R3 +// { dg-do compile { target c++2a } } + +// Not in namespace scope. +template +void fn1 () +{ + // init-statement -> simple-declaration + if (T::X r = 0; 0) // { dg-error "need .typename.|expected" } + ; + + for (T::X g = 0; ;) // { dg-error "need .typename.|expected" } + ; +} + +template +void +fn2 () +{ + T::X fn3 (); // { dg-error "need .typename.|expected" } + T::X v1; // { dg-error "need .typename.|expected" } + T::X v2 = 0; // { dg-error "need .typename.|expected" } + T::X v3{0}; // { dg-error "need .typename.|expected" } + static constexpr T::X v4 = 0; // { dg-error "need .typename." } + typedef T::X T2; // { dg-error "need .typename." } +} diff --git a/gcc/testsuite/g++.dg/cpp2a/typename8.C b/gcc/testsuite/g++.dg/cpp2a/typename8.C new file mode 100644 index 00000000000..3ebfde45ec5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/typename8.C @@ -0,0 +1,20 @@ +// P0634R3 +// { dg-do compile { target c++2a } } + +template +struct S { + static int foo (); +}; + +template +int +f () +{ + return S::foo(); +} + +void +test () +{ + f(); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/typename9.C b/gcc/testsuite/g++.dg/cpp2a/typename9.C new file mode 100644 index 00000000000..7b1865222b3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/typename9.C @@ -0,0 +1,12 @@ +// P0634R3 +// { dg-do compile { target c++2a } } +// { dg-options "-fconcepts" } + +template class A { class B; }; + +template class A::B { + B(A &); +}; + +template +A::B::B(A &) {} diff --git a/gcc/testsuite/g++.dg/diagnostic/missing-typename.C b/gcc/testsuite/g++.dg/diagnostic/missing-typename.C index 21d1ed18a60..b088bebf92f 100644 --- a/gcc/testsuite/g++.dg/diagnostic/missing-typename.C +++ b/gcc/testsuite/g++.dg/diagnostic/missing-typename.C @@ -1,4 +1,5 @@ // fix-it hint for missing "typename" (PR c++/63392) +// { dg-do compile { target c++17_down } } // { dg-options "-fdiagnostics-show-caret" } template diff --git a/gcc/testsuite/g++.dg/other/crash-9.C b/gcc/testsuite/g++.dg/other/crash-9.C index 0953fcbc46b..f5c4b2af329 100644 --- a/gcc/testsuite/g++.dg/other/crash-9.C +++ b/gcc/testsuite/g++.dg/other/crash-9.C @@ -11,5 +11,5 @@ class A }; }; template template -A::B A::B::foo() {} +A::template B A::B::foo() {} diff --git a/gcc/testsuite/g++.dg/other/nontype-1.C b/gcc/testsuite/g++.dg/other/nontype-1.C index 11bbfb82968..8d90c322a7e 100644 --- a/gcc/testsuite/g++.dg/other/nontype-1.C +++ b/gcc/testsuite/g++.dg/other/nontype-1.C @@ -1,7 +1,7 @@ template bool asfun(Op f, - Op::first_argument_type a, // { dg-error "not a type" } - Op::second_argument_type b) // { dg-error "not a type" } + Op::first_argument_type a, // { dg-error "not a type" "" { target c++17_down } } + Op::second_argument_type b) // { dg-error "not a type" "" { target c++17_down } } { return Op(a, b); } diff --git a/gcc/testsuite/g++.dg/parse/crash13.C b/gcc/testsuite/g++.dg/parse/crash13.C index 3c298ec8ede..7a4939a462d 100644 --- a/gcc/testsuite/g++.dg/parse/crash13.C +++ b/gcc/testsuite/g++.dg/parse/crash13.C @@ -12,11 +12,11 @@ struct A }; template -void func(A::B* ) // { dg-error "variable|template|expression" } +void func(A::B* ) // { dg-error "variable|template|expression" "" { target c++17_down } } { } int main() { - func(0); // { dg-error "not declared|expression|;" } + func(0); // { dg-error "not declared|expression|;" "" { target c++17_down } } } diff --git a/gcc/testsuite/g++.dg/parse/error36.C b/gcc/testsuite/g++.dg/parse/error36.C index 46080b4835d..7e52d1537e0 100644 --- a/gcc/testsuite/g++.dg/parse/error36.C +++ b/gcc/testsuite/g++.dg/parse/error36.C @@ -25,7 +25,7 @@ template struct B // PR c++/40738 template -void g(const A::type &t); // { dg-error "typename" "typename" } +void g(const A::type &t); // { dg-error "typename" "" { target c++17_down } } // PR c++/18451 -template A::B A::b; // { dg-error "typename" } +template A::B A::b; // { dg-error "typename" "" { target c++17_down } } diff --git a/gcc/testsuite/g++.dg/parse/no-typename1.C b/gcc/testsuite/g++.dg/parse/no-typename1.C index 42059ce7b80..711c621e26a 100644 --- a/gcc/testsuite/g++.dg/parse/no-typename1.C +++ b/gcc/testsuite/g++.dg/parse/no-typename1.C @@ -6,6 +6,6 @@ template struct A { template struct B { - A::template B foo(); // { dg-error "" } + A::template B foo(); // { dg-error "" "" { target c++17_down } } }; }; diff --git a/gcc/testsuite/g++.dg/parse/typedef2.C b/gcc/testsuite/g++.dg/parse/typedef2.C index 1cc1ea0d58f..fd7554e19ac 100644 --- a/gcc/testsuite/g++.dg/parse/typedef2.C +++ b/gcc/testsuite/g++.dg/parse/typedef2.C @@ -1,2 +1,2 @@ template struct B { typedef typename T::X X; }; -template struct A { typedef B::X::Y Z; }; // { dg-error "before 'B::X::Y' because 'B::X'" } +template struct A { typedef B::X::Y Z; }; // { dg-error "before 'B::X::Y' because 'B::X'" "" { target c++17_down } } diff --git a/gcc/testsuite/g++.dg/parse/typename11.C b/gcc/testsuite/g++.dg/parse/typename11.C index 22f300707c8..832913ffd67 100644 --- a/gcc/testsuite/g++.dg/parse/typename11.C +++ b/gcc/testsuite/g++.dg/parse/typename11.C @@ -10,7 +10,7 @@ template struct Y : X { // note: I is nested type in X, not Y! template -Y::I::I () {} // { dg-error "dependent typedef" "typedef" } -// { dg-error "no type|dependent type" "no type" { target *-*-* } .-1 } +Y::I::I () {} // { dg-error "expected|dependent typedef" "typedef" } +// { dg-error "no type|dependent type" "no type" { target c++17_down } .-1 } template struct Y<1>; diff --git a/gcc/testsuite/g++.dg/template/crash48.C b/gcc/testsuite/g++.dg/template/crash48.C index 6aa3aa3ed26..acbe4342542 100644 --- a/gcc/testsuite/g++.dg/template/crash48.C +++ b/gcc/testsuite/g++.dg/template/crash48.C @@ -7,4 +7,4 @@ template struct A typedef typename T::X X; }; -template A::X::X() {} // { dg-error "no type|invalid use|not a type|dependent" } +template A::X::X() {} // { dg-error "expected|no type|invalid use|not a type|dependent" } diff --git a/gcc/testsuite/g++.dg/template/dependent-name5.C b/gcc/testsuite/g++.dg/template/dependent-name5.C index 681060c7002..fc78983324b 100644 --- a/gcc/testsuite/g++.dg/template/dependent-name5.C +++ b/gcc/testsuite/g++.dg/template/dependent-name5.C @@ -17,13 +17,15 @@ struct A typedef Bar type1; typedef A::Bar type2; typedef A::Bar type3; - typedef A::Bar type4; // { dg-error "" } + typedef A::Bar type4; // { dg-error "" "" { target c++17_down } } typedef typename A::Bar type5; typedef N type6; typedef A::N type7; +// { dg-error "" "" { target c++2a } .-1 } typedef A::N type8; - typedef A::template N type9; // { dg-error "" } +// { dg-error "" "" { target c++2a } .-1 } + typedef A::template N type9; // { dg-error "" "" { target c++17_down } } typedef typename A::template N type10; typedef D Bar2; @@ -36,7 +38,7 @@ struct A typedef A::N2 type12; typedef typename type12::K k2; - typedef type12::K k1; // { dg-error "" } + typedef type12::K k1; // { dg-error "" "" { target c++17_down } } // Check that A::Bar2 is not considered dependent even if we use // the typename keyword. diff --git a/gcc/testsuite/g++.dg/template/error29.C b/gcc/testsuite/g++.dg/template/error29.C index 2e2291d7e87..6e335487224 100644 --- a/gcc/testsuite/g++.dg/template/error29.C +++ b/gcc/testsuite/g++.dg/template/error29.C @@ -1,5 +1,5 @@ // PR c++/33209 -template void foo(int, T::x); // { dg-error "T::x" } +template void foo(int, T::x); // { dg-error "T::x" "" { target c++17_down } } -template class T> void foo2(int, T::x); // { dg-error "T::x" } +template class T> void foo2(int, T::x); // { dg-error "T::x" "" { target c++17_down } } diff --git a/gcc/testsuite/g++.dg/template/nested5.C b/gcc/testsuite/g++.dg/template/nested5.C index 3850fdace3a..e3e871e6d85 100644 --- a/gcc/testsuite/g++.dg/template/nested5.C +++ b/gcc/testsuite/g++.dg/template/nested5.C @@ -6,7 +6,7 @@ template struct A { template struct D {}; }; - template static C::D bar (S const &); + template static C::template D bar (S const &); }; struct E {}; diff --git a/gcc/testsuite/g++.dg/template/pr84789.C b/gcc/testsuite/g++.dg/template/pr84789.C index 63b9832fecf..bdf80dc3edf 100644 --- a/gcc/testsuite/g++.dg/template/pr84789.C +++ b/gcc/testsuite/g++.dg/template/pr84789.C @@ -9,5 +9,5 @@ template struct B : A {}; template struct C : B { - B::A::I::I i; // { dg-error "not a class type|does not name a type|typename" } + B::A::I::I i; // { dg-error "not a class type|does not name a type|typename" "" { target c++17_down } } }; diff --git a/gcc/testsuite/g++.dg/template/static30.C b/gcc/testsuite/g++.dg/template/static30.C index 07dafe23ffa..8b8637a1abe 100644 --- a/gcc/testsuite/g++.dg/template/static30.C +++ b/gcc/testsuite/g++.dg/template/static30.C @@ -6,5 +6,5 @@ template struct A static const int i2; }; -template const int A::i1(A::i); +template const int A::i1(A::i); // { dg-error "no declaration matches" "" { target c++2a } } template const int A::i2(3, A::i); // { dg-error "expression list" } diff --git a/gcc/testsuite/g++.dg/template/typedef6.C b/gcc/testsuite/g++.dg/template/typedef6.C index c95945966fa..a6202b55181 100644 --- a/gcc/testsuite/g++.dg/template/typedef6.C +++ b/gcc/testsuite/g++.dg/template/typedef6.C @@ -5,4 +5,4 @@ template struct A typedef struct typename T::X X; // { dg-error "expected identifier|two or more" } }; -template A::X::X() {} // { dg-error "not a type|forbids declaration|invalid use of" } +template A::X::X() {} // { dg-error "expected|not a type|forbids declaration|invalid use of" } diff --git a/gcc/testsuite/g++.dg/template/typename3.C b/gcc/testsuite/g++.dg/template/typename3.C index 0ad9a2a0c41..ae10af27763 100644 --- a/gcc/testsuite/g++.dg/template/typename3.C +++ b/gcc/testsuite/g++.dg/template/typename3.C @@ -3,5 +3,5 @@ template struct B { - typedef A::C::D E; // { dg-error "" } + typedef A::C::D E; // { dg-error "" "" { target c++17_down } } }; -- 2.30.2