forked from OSchip/llvm-project
PR45294: Fix handling of assumed template names looked up in the lexical
scope. There are a few contexts in which we assume a name is a template name; if such a context is one where we should perform an unqualified lookup, and lookup finds nothing, we would form a dependent template name even if the name is not dependent. This happens in particular for the lookup of a pseudo-destructor. In passing, rename ActOnDependentTemplateName to just ActOnTemplateName given that we apply it for non-dependent template names too.
This commit is contained in:
parent
9dd92a5697
commit
499b2a8d63
|
@ -4919,6 +4919,9 @@ def err_template_kw_refers_to_non_template : Error<
|
|||
"%0 following the 'template' keyword does not refer to a template">;
|
||||
def note_template_kw_refers_to_non_template : Note<
|
||||
"declared as a non-template here">;
|
||||
def err_template_kw_refers_to_dependent_non_template : Error<
|
||||
"%0%select{| following the 'template' keyword}1 "
|
||||
"cannot refer to a dependent template">;
|
||||
def err_template_kw_refers_to_class_template : Error<
|
||||
"'%0%1' instantiated to a class template, not a function template">;
|
||||
def note_referenced_class_template : Note<
|
||||
|
|
|
@ -1773,6 +1773,12 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
|
|||
|
||||
// If there is a '<', the second type name is a template-id. Parse
|
||||
// it as such.
|
||||
//
|
||||
// FIXME: This is not a context in which a '<' is assumed to start a template
|
||||
// argument list. This affects examples such as
|
||||
// void f(auto *p) { p->~X<int>(); }
|
||||
// ... but there's no ambiguity, and nowhere to write 'template' in such an
|
||||
// example, so we accept it anyway.
|
||||
if (Tok.is(tok::less) &&
|
||||
ParseUnqualifiedIdTemplateId(
|
||||
SS, ObjectType, Base && Base->containsErrors(), SourceLocation(),
|
||||
|
|
|
@ -1878,11 +1878,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
|
|||
Tok.getLocation());
|
||||
} else if (Tok.is(tok::annot_template_id)) {
|
||||
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
|
||||
if (TemplateId->isInvalid())
|
||||
return true;
|
||||
if (TemplateId->Kind != TNK_Type_template &&
|
||||
TemplateId->Kind != TNK_Dependent_template_name &&
|
||||
TemplateId->Kind != TNK_Undeclared_template) {
|
||||
if (!TemplateId->mightBeType()) {
|
||||
Diag(Tok, diag::err_typename_refers_to_non_type_template)
|
||||
<< Tok.getAnnotationRange();
|
||||
return true;
|
||||
|
@ -1891,14 +1887,13 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
|
|||
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
|
||||
TemplateId->NumArgs);
|
||||
|
||||
Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS,
|
||||
TemplateId->TemplateKWLoc,
|
||||
TemplateId->Template,
|
||||
TemplateId->Name,
|
||||
TemplateId->TemplateNameLoc,
|
||||
TemplateId->LAngleLoc,
|
||||
TemplateArgsPtr,
|
||||
TemplateId->RAngleLoc);
|
||||
Ty = TemplateId->isInvalid()
|
||||
? TypeError()
|
||||
: Actions.ActOnTypenameType(
|
||||
getCurScope(), TypenameLoc, SS, TemplateId->TemplateKWLoc,
|
||||
TemplateId->Template, TemplateId->Name,
|
||||
TemplateId->TemplateNameLoc, TemplateId->LAngleLoc,
|
||||
TemplateArgsPtr, TemplateId->RAngleLoc);
|
||||
} else {
|
||||
Diag(Tok, diag::err_expected_type_name_after_typename)
|
||||
<< SS.getRange();
|
||||
|
|
|
@ -377,6 +377,9 @@ bool Sema::LookupTemplateName(LookupResult &Found,
|
|||
if (ATK)
|
||||
*ATK = AssumedTemplateKind::None;
|
||||
|
||||
if (SS.isInvalid())
|
||||
return true;
|
||||
|
||||
Found.setTemplateNameLookup(true);
|
||||
|
||||
// Determine where to perform name lookup
|
||||
|
@ -386,7 +389,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
|
|||
if (!ObjectType.isNull()) {
|
||||
// This nested-name-specifier occurs in a member access expression, e.g.,
|
||||
// x->B::f, and we are looking into the type of the object.
|
||||
assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
|
||||
assert(SS.isEmpty() && "ObjectType and scope specifier cannot coexist");
|
||||
LookupCtx = computeDeclContext(ObjectType);
|
||||
IsDependent = !LookupCtx && ObjectType->isDependentType();
|
||||
assert((IsDependent || !ObjectType->isIncompleteType() ||
|
||||
|
@ -412,11 +415,11 @@ bool Sema::LookupTemplateName(LookupResult &Found,
|
|||
Found.clear();
|
||||
return false;
|
||||
}
|
||||
} else if (SS.isSet()) {
|
||||
} else if (SS.isNotEmpty()) {
|
||||
// This nested-name-specifier occurs after another nested-name-specifier,
|
||||
// so long into the context associated with the prior nested-name-specifier.
|
||||
LookupCtx = computeDeclContext(SS, EnteringContext);
|
||||
IsDependent = !LookupCtx;
|
||||
IsDependent = !LookupCtx && isDependentScopeSpecifier(SS);
|
||||
|
||||
// The declaration context must be complete.
|
||||
if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx))
|
||||
|
@ -443,7 +446,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
|
|||
IsDependent |= Found.wasNotFoundInCurrentInstantiation();
|
||||
}
|
||||
|
||||
if (!SS.isSet() && (ObjectType.isNull() || Found.empty())) {
|
||||
if (SS.isEmpty() && (ObjectType.isNull() || Found.empty())) {
|
||||
// C++ [basic.lookup.classref]p1:
|
||||
// In a class member access expression (5.2.5), if the . or -> token is
|
||||
// immediately followed by an identifier followed by a <, the
|
||||
|
@ -470,7 +473,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
|
|||
if (Found.isAmbiguous())
|
||||
return false;
|
||||
|
||||
if (ATK && !SS.isSet() && ObjectType.isNull() && TemplateKWLoc.isInvalid()) {
|
||||
if (ATK && SS.isEmpty() && ObjectType.isNull() && TemplateKWLoc.isInvalid()) {
|
||||
// C++2a [temp.names]p2:
|
||||
// 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
|
||||
|
@ -3470,6 +3473,10 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
|
|||
DTN->getIdentifier(),
|
||||
TemplateArgs);
|
||||
|
||||
if (Name.getAsAssumedTemplateName() &&
|
||||
resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc))
|
||||
return QualType();
|
||||
|
||||
TemplateDecl *Template = Name.getAsTemplateDecl();
|
||||
if (!Template || isa<FunctionTemplateDecl>(Template) ||
|
||||
isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) {
|
||||
|
@ -4652,95 +4659,111 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S,
|
|||
diag::ext_template_outside_of_template)
|
||||
<< FixItHint::CreateRemoval(TemplateKWLoc);
|
||||
|
||||
if (SS.isInvalid())
|
||||
return TNK_Non_template;
|
||||
|
||||
// Figure out where isTemplateName is going to look.
|
||||
DeclContext *LookupCtx = nullptr;
|
||||
if (SS.isSet())
|
||||
if (SS.isNotEmpty())
|
||||
LookupCtx = computeDeclContext(SS, EnteringContext);
|
||||
if (!LookupCtx && ObjectType)
|
||||
LookupCtx = computeDeclContext(ObjectType.get());
|
||||
if (LookupCtx) {
|
||||
// C++0x [temp.names]p5:
|
||||
// If a name prefixed by the keyword template is not the name of
|
||||
// a template, the program is ill-formed. [Note: the keyword
|
||||
// template may not be applied to non-template members of class
|
||||
// templates. -end note ] [ Note: as is the case with the
|
||||
// typename prefix, the template prefix is allowed in cases
|
||||
// where it is not strictly necessary; i.e., when the
|
||||
// nested-name-specifier or the expression on the left of the ->
|
||||
// or . is not dependent on a template-parameter, or the use
|
||||
// does not appear in the scope of a template. -end note]
|
||||
//
|
||||
// Note: C++03 was more strict here, because it banned the use of
|
||||
// the "template" keyword prior to a template-name that was not a
|
||||
// dependent name. C++ DR468 relaxed this requirement (the
|
||||
// "template" keyword is now permitted). We follow the C++0x
|
||||
// rules, even in C++03 mode with a warning, retroactively applying the DR.
|
||||
bool MemberOfUnknownSpecialization;
|
||||
TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name,
|
||||
ObjectType, EnteringContext, Result,
|
||||
MemberOfUnknownSpecialization);
|
||||
if (TNK == TNK_Non_template && MemberOfUnknownSpecialization) {
|
||||
// This is a dependent template. Handle it below.
|
||||
} else if (TNK == TNK_Non_template) {
|
||||
// Do the lookup again to determine if this is a "nothing found" case or
|
||||
// a "not a template" case. FIXME: Refactor isTemplateName so we don't
|
||||
// need to do this.
|
||||
DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name);
|
||||
LookupResult R(*this, DNI.getName(), Name.getBeginLoc(),
|
||||
LookupOrdinaryName);
|
||||
bool MOUS;
|
||||
if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext,
|
||||
MOUS, TemplateKWLoc) && !R.isAmbiguous())
|
||||
else if (ObjectType)
|
||||
LookupCtx = computeDeclContext(GetTypeFromParser(ObjectType));
|
||||
|
||||
// C++0x [temp.names]p5:
|
||||
// If a name prefixed by the keyword template is not the name of
|
||||
// a template, the program is ill-formed. [Note: the keyword
|
||||
// template may not be applied to non-template members of class
|
||||
// templates. -end note ] [ Note: as is the case with the
|
||||
// typename prefix, the template prefix is allowed in cases
|
||||
// where it is not strictly necessary; i.e., when the
|
||||
// nested-name-specifier or the expression on the left of the ->
|
||||
// or . is not dependent on a template-parameter, or the use
|
||||
// does not appear in the scope of a template. -end note]
|
||||
//
|
||||
// Note: C++03 was more strict here, because it banned the use of
|
||||
// the "template" keyword prior to a template-name that was not a
|
||||
// dependent name. C++ DR468 relaxed this requirement (the
|
||||
// "template" keyword is now permitted). We follow the C++0x
|
||||
// rules, even in C++03 mode with a warning, retroactively applying the DR.
|
||||
bool MemberOfUnknownSpecialization;
|
||||
TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name,
|
||||
ObjectType, EnteringContext, Result,
|
||||
MemberOfUnknownSpecialization);
|
||||
if (TNK != TNK_Non_template) {
|
||||
// We resolved this to a (non-dependent) template name. Return it.
|
||||
auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx);
|
||||
if (!AllowInjectedClassName && SS.isNotEmpty() && LookupRD &&
|
||||
Name.getKind() == UnqualifiedIdKind::IK_Identifier &&
|
||||
Name.Identifier && LookupRD->getIdentifier() == Name.Identifier) {
|
||||
// C++14 [class.qual]p2:
|
||||
// In a lookup in which function names are not ignored and the
|
||||
// nested-name-specifier nominates a class C, if the name specified
|
||||
// [...] is the injected-class-name of C, [...] the name is instead
|
||||
// considered to name the constructor
|
||||
//
|
||||
// We don't get here if naming the constructor would be valid, so we
|
||||
// just reject immediately and recover by treating the
|
||||
// injected-class-name as naming the template.
|
||||
Diag(Name.getBeginLoc(),
|
||||
diag::ext_out_of_line_qualified_id_type_names_constructor)
|
||||
<< Name.Identifier
|
||||
<< 0 /*injected-class-name used as template name*/
|
||||
<< TemplateKWLoc.isValid();
|
||||
}
|
||||
return TNK;
|
||||
}
|
||||
|
||||
if (!MemberOfUnknownSpecialization) {
|
||||
// Didn't find a template name, and the lookup wasn't dependent.
|
||||
// Do the lookup again to determine if this is a "nothing found" case or
|
||||
// a "not a template" case. FIXME: Refactor isTemplateName so we don't
|
||||
// need to do this.
|
||||
DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name);
|
||||
LookupResult R(*this, DNI.getName(), Name.getBeginLoc(),
|
||||
LookupOrdinaryName);
|
||||
bool MOUS;
|
||||
// FIXME: If LookupTemplateName fails here, we'll have produced its
|
||||
// diagnostics twice.
|
||||
if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext,
|
||||
MOUS, TemplateKWLoc) && !R.isAmbiguous()) {
|
||||
if (LookupCtx)
|
||||
Diag(Name.getBeginLoc(), diag::err_no_member)
|
||||
<< DNI.getName() << LookupCtx << SS.getRange();
|
||||
return TNK_Non_template;
|
||||
} else {
|
||||
// We found something; return it.
|
||||
auto *LookupRD = dyn_cast<CXXRecordDecl>(LookupCtx);
|
||||
if (!AllowInjectedClassName && SS.isSet() && LookupRD &&
|
||||
Name.getKind() == UnqualifiedIdKind::IK_Identifier &&
|
||||
Name.Identifier && LookupRD->getIdentifier() == Name.Identifier) {
|
||||
// C++14 [class.qual]p2:
|
||||
// In a lookup in which function names are not ignored and the
|
||||
// nested-name-specifier nominates a class C, if the name specified
|
||||
// [...] is the injected-class-name of C, [...] the name is instead
|
||||
// considered to name the constructor
|
||||
//
|
||||
// We don't get here if naming the constructor would be valid, so we
|
||||
// just reject immediately and recover by treating the
|
||||
// injected-class-name as naming the template.
|
||||
Diag(Name.getBeginLoc(),
|
||||
diag::ext_out_of_line_qualified_id_type_names_constructor)
|
||||
<< Name.Identifier
|
||||
<< 0 /*injected-class-name used as template name*/
|
||||
<< 1 /*'template' keyword was used*/;
|
||||
}
|
||||
return TNK;
|
||||
else
|
||||
Diag(Name.getBeginLoc(), diag::err_undeclared_use)
|
||||
<< DNI.getName() << SS.getRange();
|
||||
}
|
||||
return TNK_Non_template;
|
||||
}
|
||||
|
||||
NestedNameSpecifier *Qualifier = SS.getScopeRep();
|
||||
|
||||
switch (Name.getKind()) {
|
||||
case UnqualifiedIdKind::IK_Identifier:
|
||||
Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier,
|
||||
Name.Identifier));
|
||||
Result = TemplateTy::make(
|
||||
Context.getDependentTemplateName(Qualifier, Name.Identifier));
|
||||
return TNK_Dependent_template_name;
|
||||
|
||||
case UnqualifiedIdKind::IK_OperatorFunctionId:
|
||||
Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier,
|
||||
Name.OperatorFunctionId.Operator));
|
||||
Result = TemplateTy::make(Context.getDependentTemplateName(
|
||||
Qualifier, Name.OperatorFunctionId.Operator));
|
||||
return TNK_Function_template;
|
||||
|
||||
case UnqualifiedIdKind::IK_LiteralOperatorId:
|
||||
llvm_unreachable("literal operator id cannot have a dependent scope");
|
||||
// This is a kind of template name, but can never occur in a dependent
|
||||
// scope (literal operators can only be declared at namespace scope).
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Diag(Name.getBeginLoc(), diag::err_template_kw_refers_to_non_template)
|
||||
// This name cannot possibly name a dependent template. Diagnose this now
|
||||
// rather than building a dependent template name that can never be valid.
|
||||
Diag(Name.getBeginLoc(),
|
||||
diag::err_template_kw_refers_to_dependent_non_template)
|
||||
<< GetNameFromUnqualifiedId(Name).getName() << Name.getSourceRange()
|
||||
<< TemplateKWLoc;
|
||||
<< TemplateKWLoc.isValid() << TemplateKWLoc;
|
||||
return TNK_Non_template;
|
||||
}
|
||||
|
||||
|
|
|
@ -240,8 +240,7 @@ namespace PR17255 {
|
|||
void foo() {
|
||||
typename A::template B<> c; // expected-error {{use of undeclared identifier 'A'}}
|
||||
#if __cplusplus <= 199711L
|
||||
// expected-error@-2 {{'typename' occurs outside of a template}}
|
||||
// expected-error@-3 {{'template' keyword outside of a template}}
|
||||
// expected-error@-2 {{'template' keyword outside of a template}}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,3 +47,7 @@ template <unsigned long long...> void operator "" _invalid(); // expected-error
|
|||
_Complex float operator""if(long double); // expected-warning {{reserved}}
|
||||
_Complex float test_if_1() { return 2.0f + 1.5if; };
|
||||
void test_if_2() { "foo"if; } // expected-error {{no matching literal operator for call to 'operator""if'}}
|
||||
|
||||
template<typename T> void dependent_member_template() {
|
||||
T().template operator""_foo<int>(); // expected-error {{'operator""_foo' following the 'template' keyword cannot refer to a dependent template}}
|
||||
}
|
||||
|
|
|
@ -119,3 +119,54 @@ void test2(Foo d) {
|
|||
d.~Derived(); // expected-error {{member reference type 'dotPointerAccess::Foo' (aka 'dotPointerAccess::Derived *') is a pointer; did you mean to use '->'}}
|
||||
}
|
||||
}
|
||||
|
||||
int pr45294 = 1 .~undeclared_tempate_name<>(); // expected-error {{use of undeclared 'undeclared_tempate_name'}}
|
||||
|
||||
namespace TwoPhaseLookup {
|
||||
namespace NonTemplate {
|
||||
struct Y {};
|
||||
using G = Y;
|
||||
template<typename T> void f(T *p) { p->~G(); } // expected-error {{no member named '~Y'}}
|
||||
void h1(Y *p) { p->~G(); }
|
||||
void h2(Y *p) { f(p); }
|
||||
namespace N { struct G{}; }
|
||||
void h3(N::G *p) { p->~G(); }
|
||||
void h4(N::G *p) { f(p); } // expected-note {{instantiation of}}
|
||||
}
|
||||
|
||||
namespace NonTemplateUndeclared {
|
||||
struct Y {};
|
||||
template<typename T> void f(T *p) { p->~G(); } // expected-error {{undeclared identifier 'G' in destructor name}}
|
||||
using G = Y;
|
||||
void h1(Y *p) { p->~G(); }
|
||||
void h2(Y *p) { f(p); } // expected-note {{instantiation of}}
|
||||
namespace N { struct G{}; }
|
||||
void h3(N::G *p) { p->~G(); }
|
||||
void h4(N::G *p) { f(p); }
|
||||
}
|
||||
|
||||
namespace Template {
|
||||
template<typename T> struct Y {};
|
||||
template<class U> using G = Y<U>;
|
||||
template<typename T> void f(T *p) { p->~G<int>(); } // expected-error {{no member named '~Y'}}
|
||||
void h1(Y<int> *p) { p->~G<int>(); }
|
||||
void h2(Y<int> *p) { f(p); }
|
||||
namespace N { template<typename T> struct G {}; }
|
||||
void h3(N::G<int> *p) { p->~G<int>(); }
|
||||
void h4(N::G<int> *p) { f(p); } // expected-note {{instantiation of}}
|
||||
}
|
||||
|
||||
namespace TemplateUndeclared {
|
||||
template<typename T> struct Y {};
|
||||
// FIXME: Formally, this is ill-formed before we hit any instantiation,
|
||||
// because we aren't supposed to treat the '<' as introducing a template
|
||||
// name.
|
||||
template<typename T> void f(T *p) { p->~G<int>(); } // expected-error {{no member named 'G'}}
|
||||
template<class U> using G = Y<U>;
|
||||
void h1(Y<int> *p) { p->~G<int>(); }
|
||||
void h2(Y<int> *p) { f(p); } // expected-note {{instantiation of}}
|
||||
namespace N { template<typename T> struct G {}; }
|
||||
void h3(N::G<int> *p) { p->~G<int>(); }
|
||||
void h4(N::G<int> *p) { f(p); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,8 +142,7 @@ namespace PR9449 {
|
|||
|
||||
template <typename T>
|
||||
void f() {
|
||||
int s<T>::template n<T>::* f; // expected-error{{implicit instantiation of undefined template 'PR9449::s<int>'}} \
|
||||
// expected-error{{no member named 'n'}}
|
||||
int s<T>::template n<T>::* f; // expected-error{{implicit instantiation of undefined template 'PR9449::s<int>'}}
|
||||
}
|
||||
|
||||
template void f<int>(); // expected-note{{in instantiation of}}
|
||||
|
|
Loading…
Reference in New Issue