@@ -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);
@@ -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;
}
@@ -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). */
new file mode 100644
@@ -0,0 +1,6 @@
+// DR 1835
+
+template <class T> void f(T t) { t.foo::bar(); }
+struct foo { void bar(); };
+struct baz : foo { };
+int main() { f(baz()); }
new file mode 100644
@@ -0,0 +1,22 @@
+template <class T>
+struct B
+{
+ void f(T *p)
+ {
+ p->template A<int>::~A<int>();
+ p->A::~A();
+ p->~A<int>();
+ p->~A();
+ p->~T();
+ p->T::~T();
+ }
+};
+
+template <class T>
+struct A
+{ };
+
+int main()
+{
+ B<A<int> >().f(0);
+}
@@ -11,7 +11,7 @@ template <class T> void f(A<T> *ap) {
}
template <class T> void g(A<T> *ap) {
- ap->~B(); // { dg-error "destructor name" }
+ ap->~B(); // { dg-error "" }
}
int main()