81204 is a regression whereby previously we would accidentally get the parsing of res.template set<I> right because when we did the lookup in the surrounding context, we found the function template and then ignored it. This patch partially reverts the handling of .template to how it was in GCC 6.
But this bug is really a special case of 54769; we should be treating that name as dependent and not doing a lookup in the enclosing context at all. As I noted in discussion of 55576, we need to pass template_keyword_p into nested_name_specifier_opt. So this patch does that, and also adjusts cp_parser_template_name to consider object scope. With that change, we see TEMPLATE_ID_EXPR in more error cases, so I adjusted cp_parser_template_id to use the range on those expression nodes as well as on the replacement token. 45976 and 55639 are cases where we gave unhelpful diagnostics for uses of ::template that are pedantically ill-formed, but harmless and accepted by other compilers. So these patches fix G++ to accept them with a pedwarn. Tested x86_64-pc-linux-gnu, applying to trunk. 81204 also to 7.
commit 0a9d6a9e176acba3a8753caa2bd8b14d6bc622fb Author: Jason Merrill <ja...@redhat.com> Date: Mon Jun 26 16:24:28 2017 -0400 PR c++/81204 - parse error with dependent template-name * parser.c (cp_parser_lookup_name): Disqualify function templates after lookup. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 2ff6afd..e0a6c8b 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -25813,11 +25813,22 @@ cp_parser_lookup_name (cp_parser *parser, tree name, decl = NULL_TREE; if (!decl) - /* Look it up in the enclosing context. DR 141: When looking for a - template-name after -> or ., only consider class templates. */ - decl = lookup_name_real (name, prefer_type_arg (tag_type, is_template), - /*nonclass=*/0, - /*block_p=*/true, is_namespace, 0); + { + /* Look it up in the enclosing context. */ + decl = lookup_name_real (name, prefer_type_arg (tag_type), + /*nonclass=*/0, + /*block_p=*/true, is_namespace, 0); + /* DR 141 says when looking for a template-name after -> or ., only + consider class templates. */ + if (decl && is_template && !DECL_TYPE_TEMPLATE_P (decl)) + { + tree d = decl; + if (is_overloaded_fn (d)) + d = get_first_fn (d); + if (DECL_P (d) && !DECL_CLASS_SCOPE_P (d)) + decl = NULL_TREE; + } + } if (object_type == unknown_type_node) /* The object is type-dependent, so we can't look anything up; we used this to get the DR 141 behavior. */ diff --git a/gcc/testsuite/g++.dg/template/lookup10.C b/gcc/testsuite/g++.dg/template/lookup10.C new file mode 100644 index 0000000..fa90af4 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/lookup10.C @@ -0,0 +1,12 @@ +// PR c++/81204 + +namespace std { + template<typename, typename> struct set { }; +} +using namespace std; + +template <int I, typename Result> +inline void set(Result & res) +{ + res.template set<I>(); +}
commit bb0c81aecf7ac956e770e4eb6eca02f4fe6fd686 Author: Jason Merrill <ja...@redhat.com> Date: Mon Jun 26 16:52:57 2017 -0400 PR c++/54769 - wrong lookup of dependent template-name. * parser.c (cp_parser_template_name): Handle dependent object type. (cp_parser_nested_name_specifier_opt): Make template_keyword_p a parameter. (cp_parser_id_expression): Pass it. (cp_parser_diagnose_invalid_type_name): Handle TEMPLATE_ID_EXPR. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 246af76..c9fc284 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2039,7 +2039,7 @@ static cp_expr cp_parser_id_expression static cp_expr cp_parser_unqualified_id (cp_parser *, bool, bool, bool, bool); static tree cp_parser_nested_name_specifier_opt - (cp_parser *, bool, bool, bool, bool); + (cp_parser *, bool, bool, bool, bool, bool = false); static tree cp_parser_nested_name_specifier (cp_parser *, bool, bool, bool, bool); static tree cp_parser_qualifying_entity @@ -3253,6 +3253,10 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id, error_at (location_of (id), "%qE in namespace %qE does not name a template type", id, parser->scope); + else if (TREE_CODE (id) == TEMPLATE_ID_EXPR) + error_at (location_of (id), + "%qE in namespace %qE does not name a template type", + TREE_OPERAND (id, 0), parser->scope); else error_at (location_of (id), "%qE in namespace %qE does not name a type", @@ -3296,6 +3300,10 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id, error_at (location_of (id), "%qE in %q#T does not name a template type", id, parser->scope); + else if (TREE_CODE (id) == TEMPLATE_ID_EXPR) + error_at (location_of (id), + "%qE in %q#T does not name a template type", + TREE_OPERAND (id, 0), parser->scope); else error_at (location_of (id), "%qE in %q#T does not name a type", @@ -5420,16 +5428,21 @@ cp_parser_id_expression (cp_parser *parser, /* Look for the optional `::' operator. */ global_scope_p - = (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false) - != NULL_TREE); + = (!template_keyword_p + && (cp_parser_global_scope_opt (parser, + /*current_scope_valid_p=*/false) + != NULL_TREE)); + /* Look for the optional nested-name-specifier. */ nested_name_specifier_p = (cp_parser_nested_name_specifier_opt (parser, /*typename_keyword_p=*/false, check_dependency_p, /*type_p=*/false, - declarator_p) + declarator_p, + template_keyword_p) != NULL_TREE); + /* If there is a nested-name-specifier, then we are looking at the first qualified-id production. */ if (nested_name_specifier_p) @@ -5874,7 +5887,8 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, bool typename_keyword_p, bool check_dependency_p, bool type_p, - bool is_declaration) + bool is_declaration, + bool template_keyword_p /* = false */) { bool success = false; cp_token_position start = 0; @@ -5892,7 +5906,6 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, tree new_scope; tree old_scope; tree saved_qualifying_scope; - bool template_keyword_p; /* Spot cases that cannot be the beginning of a nested-name-specifier. */ @@ -5967,8 +5980,6 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, first time through the loop. */ if (success) template_keyword_p = cp_parser_optional_template_keyword (parser); - else - template_keyword_p = false; /* Save the old scope since the name lookup we are about to do might destroy it. */ @@ -15861,15 +15872,19 @@ cp_parser_template_name (cp_parser* parser, no point in doing name-lookup, so we just return IDENTIFIER. But, if the qualifying scope is non-dependent then we can (and must) do name-lookup normally. */ - if (template_keyword_p - && (!parser->scope - || (TYPE_P (parser->scope) - && dependent_type_p (parser->scope)))) + if (template_keyword_p) { - /* We're optimizing away the call to cp_parser_lookup_name, but we - still need to do this. */ - parser->context->object_type = NULL_TREE; - return identifier; + tree scope = (parser->scope ? parser->scope + : parser->context->object_type); + if (scope && TYPE_P (scope) + && (!CLASS_TYPE_P (scope) + || (check_dependency_p && dependent_type_p (scope)))) + { + /* We're optimizing away the call to cp_parser_lookup_name, but + we still need to do this. */ + parser->context->object_type = NULL_TREE; + return identifier; + } } } @@ -15882,6 +15897,11 @@ cp_parser_template_name (cp_parser* parser, /*ambiguous_decls=*/NULL, token->location); + /* If the lookup failed and we got the 'template' keyword, believe it. */ + if (decl == error_mark_node && template_keyword_p + && processing_template_decl) + return identifier; + decl = strip_using_decl (decl); /* If DECL is a template, then the name was a template-name. */ diff --git a/gcc/testsuite/g++.dg/template/lookup11.C b/gcc/testsuite/g++.dg/template/lookup11.C new file mode 100644 index 0000000..203460e --- /dev/null +++ b/gcc/testsuite/g++.dg/template/lookup11.C @@ -0,0 +1,11 @@ +// PR c++/81026 + +namespace std { + template<class> struct extent; +} +using namespace std; + +template <class T> +struct S { + void f() { T().template extent<42>(); } +};
commit 2f4e3c6bd0be31008674c8e56a9c41ddacc3924b Author: Jason Merrill <ja...@redhat.com> Date: Tue Jun 27 02:19:33 2017 -0400 Make the TEMPLATE_ID_EXPR location a range. * parser.c (cp_parser_template_id): Use the range location on the TEMPLATE_ID_EXPR. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e0a6c8b..246af76 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -15522,17 +15522,17 @@ cp_parser_template_id (cp_parser *parser, /* If the next token corresponds to a template-id, there is no need to reparse it. */ - next_token = cp_lexer_peek_token (parser->lexer); - if (next_token->type == CPP_TEMPLATE_ID) + cp_token *token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_TEMPLATE_ID) { cp_lexer_consume_token (parser->lexer); - return saved_checks_value (next_token->u.tree_check_value); + return saved_checks_value (token->u.tree_check_value); } /* Avoid performing name lookup if there is no possibility of finding a template-id. */ - if ((next_token->type != CPP_NAME && next_token->keyword != RID_OPERATOR) - || (next_token->type == CPP_NAME + if ((token->type != CPP_NAME && token->keyword != RID_OPERATOR) + || (token->type == CPP_NAME && !cp_parser_nth_token_starts_template_argument_list_p (parser, 2))) { @@ -15623,9 +15623,19 @@ cp_parser_template_id (cp_parser *parser, arguments = cp_parser_enclosed_template_argument_list (parser); } + /* Set the location to be of the form: + template-name < template-argument-list [opt] > + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + with caret == start at the start of the template-name, + ranging until the closing '>'. */ + location_t finish_loc + = get_finish (cp_lexer_previous_token (parser->lexer)->location); + location_t combined_loc + = make_location (token->location, token->location, finish_loc); + /* Build a representation of the specialization. */ if (identifier_p (templ)) - template_id = build_min_nt_loc (next_token->location, + template_id = build_min_nt_loc (combined_loc, TEMPLATE_ID_EXPR, templ, arguments); else if (DECL_TYPE_TEMPLATE_P (templ) @@ -15652,7 +15662,7 @@ cp_parser_template_id (cp_parser *parser, { template_id = lookup_template_variable (templ, arguments); if (TREE_CODE (template_id) == TEMPLATE_ID_EXPR) - SET_EXPR_LOCATION (template_id, next_token->location); + SET_EXPR_LOCATION (template_id, combined_loc); } else { @@ -15664,7 +15674,7 @@ cp_parser_template_id (cp_parser *parser, template_id = lookup_template_function (templ, arguments); if (TREE_CODE (template_id) == TEMPLATE_ID_EXPR) - SET_EXPR_LOCATION (template_id, next_token->location); + SET_EXPR_LOCATION (template_id, combined_loc); } /* If parsing tentatively, replace the sequence of tokens that makes @@ -15680,20 +15690,8 @@ cp_parser_template_id (cp_parser *parser, && cp_parser_parsing_tentatively (parser) && parser->in_declarator_p)) { - cp_token *token = cp_lexer_token_at (parser->lexer, start_of_id); - /* Reset the contents of the START_OF_ID token. */ token->type = CPP_TEMPLATE_ID; - - /* Update the location to be of the form: - template-name < template-argument-list [opt] > - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - with caret == start at the start of the template-name, - ranging until the closing '>'. */ - location_t finish_loc - = get_finish (cp_lexer_previous_token (parser->lexer)->location); - location_t combined_loc - = make_location (token->location, token->location, finish_loc); token->location = combined_loc; /* We must mark the lookup as kept, so we don't throw it away on
commit 8938ec573f84ed013fc9f4721f17e73a0bfc82e1 Author: Jason Merrill <ja...@redhat.com> Date: Tue Jun 27 14:05:16 2017 -0400 PR c++/45976 - error with ::template in declarator. * pt.c (resolve_typename_type): Fix TEMPLATE_ID_EXPR handling. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 957d229..b060a19 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -24624,26 +24624,38 @@ resolve_typename_type (tree type, bool only_current_p) /* For a TYPENAME_TYPE like "typename X::template Y<T>", we want to find a TEMPLATE_DECL. Otherwise, we want to find a TYPE_DECL. */ + tree fullname = TYPENAME_TYPE_FULLNAME (type); if (!decl) /*nop*/; - else if (identifier_p (TYPENAME_TYPE_FULLNAME (type)) + else if (identifier_p (fullname) && TREE_CODE (decl) == TYPE_DECL) { result = TREE_TYPE (decl); if (result == error_mark_node) result = NULL_TREE; } - else if (TREE_CODE (TYPENAME_TYPE_FULLNAME (type)) == TEMPLATE_ID_EXPR + else if (TREE_CODE (fullname) == TEMPLATE_ID_EXPR && DECL_CLASS_TEMPLATE_P (decl)) { - tree tmpl; - tree args; /* Obtain the template and the arguments. */ - tmpl = TREE_OPERAND (TYPENAME_TYPE_FULLNAME (type), 0); - args = TREE_OPERAND (TYPENAME_TYPE_FULLNAME (type), 1); + tree tmpl = TREE_OPERAND (fullname, 0); + if (TREE_CODE (tmpl) == IDENTIFIER_NODE) + { + /* We get here with a plain identifier because a previous tentative + parse of the nested-name-specifier as part of a ptr-operator saw + ::template X<A>. The use of ::template is necessary in a + ptr-operator, but wrong in a declarator-id. + + [temp.names]: In a qualified-id of a declarator-id, the keyword + template shall not appear at the top level. */ + pedwarn (EXPR_LOC_OR_LOC (fullname, input_location), OPT_Wpedantic, + "keyword %<template%> not allowed in declarator-id"); + tmpl = decl; + } + tree args = TREE_OPERAND (fullname, 1); /* Instantiate the template. */ result = lookup_template_class (tmpl, args, NULL_TREE, NULL_TREE, - /*entering_scope=*/0, + /*entering_scope=*/true, tf_error | tf_user); if (result == error_mark_node) result = NULL_TREE; diff --git a/gcc/testsuite/g++.dg/template/template-keyword1.C b/gcc/testsuite/g++.dg/template/template-keyword1.C new file mode 100644 index 0000000..0f928a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/template-keyword1.C @@ -0,0 +1,15 @@ +// PR c++/45976 + +template<int a> +struct A { + static const int value; + + template<int b> + struct B { + static const int value; + }; +}; + +template<int a> +template<int b> +const int A<a>::template B<b>::value = 0; // { dg-error "keyword .template" }
commit bef4c2fc9c89825503ddbff062544dd7d2582ac2 Author: Jason Merrill <ja...@redhat.com> Date: Wed Jun 28 12:41:34 2017 -0400 PR c++/55639 - partial specialization with ::template * parser.c (cp_parser_class_head): Handle ::template. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c9fc284..bd99c05 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -22602,6 +22602,9 @@ cp_parser_class_head (cp_parser* parser, /*is_declaration=*/false); /* If there was a nested-name-specifier, then there *must* be an identifier. */ + + cp_token *bad_template_keyword = NULL; + if (nested_name_specifier) { type_start_token = cp_lexer_peek_token (parser->lexer); @@ -22623,6 +22626,8 @@ cp_parser_class_head (cp_parser* parser, class-name is a template-id; if we looked for the template-name first we would stop after the template-name. */ cp_parser_parse_tentatively (parser); + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) + bad_template_keyword = cp_lexer_consume_token (parser->lexer); type = cp_parser_class_name (parser, /*typename_keyword_p=*/false, /*template_keyword_p=*/false, @@ -22742,6 +22747,12 @@ cp_parser_class_head (cp_parser* parser, { tree scope; + if (bad_template_keyword) + /* [temp.names]: in a qualified-id formed by a class-head-name, the + keyword template shall not appear at the top level. */ + pedwarn (bad_template_keyword->location, OPT_Wpedantic, + "keyword %<template%> not allowed in class-head-name"); + /* Reject typedef-names in class heads. */ if (!DECL_IMPLICIT_TYPEDEF_P (type)) { diff --git a/gcc/testsuite/g++.dg/template/partial-specialization8.C b/gcc/testsuite/g++.dg/template/partial-specialization8.C new file mode 100644 index 0000000..e3ffe3b --- /dev/null +++ b/gcc/testsuite/g++.dg/template/partial-specialization8.C @@ -0,0 +1,19 @@ +// PR c++/55639 + +template <int number> +struct SomeClass +{ + SomeClass() { } + + template <typename E, int number2> + struct Fun { + static void + fun() { } + }; +}; + +template <int number> +template <typename E> +struct SomeClass<number>::template Fun<E, 0> { // { dg-error "template" } + static void fun() { } +};