diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8df18c38d43..1fcd50c64fd 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7263,6 +7263,7 @@ extern tree maybe_get_template_decl_from_type_decl (tree); extern int processing_template_parmlist; extern bool dependent_type_p (tree); extern bool dependent_scope_p (tree); +extern bool dependentish_scope_p (tree); extern bool any_dependent_template_arguments_p (const_tree); extern bool any_erroneous_template_args_p (const_tree); extern bool dependent_template_p (tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 20f949edfe0..31bae6d8983 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -18187,6 +18187,16 @@ cp_parser_template_id (cp_parser *parser, if (TREE_CODE (template_id) == TEMPLATE_ID_EXPR) SET_EXPR_LOCATION (template_id, combined_loc); } + else if (TREE_CODE (templ) == TYPE_DECL + && TREE_CODE (TREE_TYPE (templ)) == TYPENAME_TYPE) + { + /* Some type template in dependent scope. */ + tree &name = TYPENAME_TYPE_FULLNAME (TREE_TYPE (templ)); + name = build_min_nt_loc (combined_loc, + TEMPLATE_ID_EXPR, + name, arguments); + template_id = templ; + } else { /* If it's not a class-template or a template-template, it should be @@ -18413,8 +18423,8 @@ cp_parser_template_name (cp_parser* parser, } /* cp_parser_lookup_name clears OBJECT_TYPE. */ - const bool scoped_p = ((parser->scope ? parser->scope - : parser->context->object_type) != NULL_TREE); + tree scope = (parser->scope ? parser->scope + : parser->context->object_type); /* Look up the name. */ decl = cp_parser_lookup_name (parser, identifier, @@ -18427,6 +18437,19 @@ cp_parser_template_name (cp_parser* parser, decl = strip_using_decl (decl); + /* 13.3 [temp.names] A < is interpreted as the delimiter of a + template-argument-list if it follows a name that is not a + conversion-function-id and + - that follows the keyword template or a ~ after a nested-name-specifier or + in a class member access expression, or + - for which name lookup finds the injected-class-name of a class template + or finds any declaration of a template, or + - that is an unqualified name for which name lookup either finds one or + more functions or finds nothing, or + - that is a terminal name in a using-declarator (9.9), in a declarator-id + (9.3.4), or in a type-only context other than a nested-name-specifier + (13.8). */ + /* If DECL is a template, then the name was a template-name. */ if (TREE_CODE (decl) == TEMPLATE_DECL) { @@ -18454,11 +18477,7 @@ cp_parser_template_name (cp_parser* parser, } else { - /* The standard does not explicitly indicate whether a name that - names a set of overloaded declarations, some of which are - templates, is a template-name. However, such a name should - be a template-name; otherwise, there is no way to form a - template-id for the overloaded templates. */ + /* Look through an overload set for any templates. */ bool found = false; for (lkp_iterator iter (MAYBE_BASELINK_FUNCTIONS (decl)); @@ -18466,34 +18485,41 @@ cp_parser_template_name (cp_parser* parser, if (TREE_CODE (*iter) == TEMPLATE_DECL) found = true; + /* "an unqualified name for which name lookup either finds one or more + functions or finds nothing". */ if (!found && (cxx_dialect > cxx17) - && !scoped_p + && !scope && cp_lexer_next_token_is (parser->lexer, CPP_LESS) && tag_type == none_type) { - /* [temp.names] says "A name is also considered to refer to a template - if it is an unqualified-id followed by a < and name lookup finds - either one or more functions or finds nothing." */ - /* The "more functions" case. Just use the OVERLOAD as normally. We don't use is_overloaded_fn here to avoid considering BASELINKs. */ if (TREE_CODE (decl) == OVERLOAD /* Name lookup found one function. */ - || TREE_CODE (decl) == FUNCTION_DECL) + || TREE_CODE (decl) == FUNCTION_DECL + /* Name lookup found nothing. */ + || decl == error_mark_node) found = true; - /* Name lookup found nothing. */ - else if (decl == error_mark_node) - return identifier; } + /* "in a type-only context" */ + if (!found && scope + && tag_type != none_type + && dependentish_scope_p (scope) + && cp_parser_nth_token_starts_template_argument_list_p (parser, 1)) + found = true; + if (!found) { /* The name does not name a template. */ cp_parser_error (parser, "expected template-name"); return error_mark_node; } + else if (decl == error_mark_node) + /* Repeat the lookup at instantiation time. */ + decl = identifier; } return decl; @@ -30373,6 +30399,17 @@ cp_parser_lookup_name (cp_parser *parser, tree name, consider class templates. */ : is_template ? LOOK_want::TYPE : prefer_type_arg (tag_type)); + + /* If we know we're looking for a type (e.g. A in p->A::x), + mock up a typename. */ + if (!decl && object_type && tag_type != none_type + && dependentish_scope_p (object_type)) + { + tree type = build_typename_type (object_type, name, name, + typename_type); + decl = TYPE_NAME (type); + } + parser->object_scope = object_type; parser->qualifying_scope = NULL_TREE; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 12c8812d8b2..4d42899f28d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -26970,6 +26970,15 @@ dependent_scope_p (tree scope) && !currently_open_class (scope)); } +/* True if we might find more declarations in SCOPE during instantiation than + we can when parsing the template. */ + +bool +dependentish_scope_p (tree scope) +{ + return dependent_scope_p (scope) || any_dependent_bases_p (scope); +} + /* T is a SCOPE_REF. Return whether it represents a non-static member of an unknown base of 'this' (and is therefore instantiation-dependent). */ diff --git a/gcc/testsuite/g++.dg/cpp23/lookup2.C b/gcc/testsuite/g++.dg/cpp23/lookup2.C new file mode 100644 index 00000000000..a16afbe2196 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/lookup2.C @@ -0,0 +1,6 @@ +// DR 1835 + +template void f(T t) { t.foo::bar(); } +struct foo { void bar(); }; +struct baz : foo { }; +int main() { f(baz()); } diff --git a/gcc/testsuite/g++.dg/template/dtor11.C b/gcc/testsuite/g++.dg/template/dtor11.C new file mode 100644 index 00000000000..9bb58b41d47 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/dtor11.C @@ -0,0 +1,22 @@ +template +struct B +{ + void f(T *p) + { + p->template A::~A(); + p->A::~A(); + p->~A(); + p->~A(); + p->~T(); + p->T::~T(); + } +}; + +template +struct A +{ }; + +int main() +{ + B >().f(0); +} diff --git a/gcc/testsuite/g++.dg/template/dtor5.C b/gcc/testsuite/g++.dg/template/dtor5.C index 8fa4eeb6f06..d9a1c692a34 100644 --- a/gcc/testsuite/g++.dg/template/dtor5.C +++ b/gcc/testsuite/g++.dg/template/dtor5.C @@ -11,7 +11,7 @@ template void f(A *ap) { } template void g(A *ap) { - ap->~B(); // { dg-error "destructor name" } + ap->~B(); // { dg-error "" } } int main()