aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorKrystian Stasiowski <sdkrystian@gmail.com>2024-04-30 14:25:09 -0400
committerGitHub <noreply@github.com>2024-04-30 14:25:09 -0400
commit8009bbec59d1c5d47ae06c431647ebee6d886ff2 (patch)
tree9c12efdd4faba92fc9fc2198a81ca0a94d98037a /clang/lib/Sema
parentf061a395ffb78215a23e0f503e8ea121ee3b13ad (diff)
downloadllvm-8009bbec59d1c5d47ae06c431647ebee6d886ff2.zip
llvm-8009bbec59d1c5d47ae06c431647ebee6d886ff2.tar.gz
llvm-8009bbec59d1c5d47ae06c431647ebee6d886ff2.tar.bz2
Reapply "[Clang][Sema] Diagnose class member access expressions naming non-existent members of the current instantiation prior to instantiation in the absence of dependent base classes (#84050)" (#90152)
Reapplies #84050, addressing a bug which cases a crash when an expression with the type of the current instantiation is used as the _postfix-expression_ in a class member access expression (arrow form).
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/HLSLExternalSemaSource.cpp7
-rw-r--r--clang/lib/Sema/SemaAttr.cpp2
-rw-r--r--clang/lib/Sema/SemaDecl.cpp7
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp6
-rw-r--r--clang/lib/Sema/SemaExpr.cpp20
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp2
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp270
-rw-r--r--clang/lib/Sema/SemaLookup.cpp114
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp17
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp32
-rw-r--r--clang/lib/Sema/TreeTransform.h20
11 files changed, 276 insertions, 221 deletions
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 1a1febf..bb283c5 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -126,12 +126,15 @@ struct BuiltinTypeDeclBuilder {
static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
StringRef Name) {
- CXXScopeSpec SS;
IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
DeclarationNameInfo NameInfo =
DeclarationNameInfo(DeclarationName(&II), SourceLocation());
LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
- S.LookupParsedName(R, S.getCurScope(), &SS, false);
+ // AllowBuiltinCreation is false but LookupDirect will create
+ // the builtin when searching the global scope anyways...
+ S.LookupName(R, S.getCurScope());
+ // FIXME: If the builtin function was user-declared in global scope,
+ // this assert *will* fail. Should this call LookupBuiltin instead?
assert(R.isSingleResult() &&
"Since this is a builtin it should always resolve!");
auto *VD = cast<ValueDecl>(R.getFoundDecl());
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index a5dd158..a83b1e8 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -837,7 +837,7 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
IdentifierInfo *Name = IdTok.getIdentifierInfo();
LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName);
- LookupParsedName(Lookup, curScope, nullptr, true);
+ LookupName(Lookup, curScope, /*AllowBuiltinCreation=*/true);
if (Lookup.empty()) {
Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 671752b..79fb6c0 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -832,7 +832,7 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
IdentifierInfo *&Name,
SourceLocation NameLoc) {
LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName);
- SemaRef.LookupParsedName(R, S, &SS);
+ SemaRef.LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
if (TagDecl *Tag = R.getAsSingle<TagDecl>()) {
StringRef FixItTagName;
switch (Tag->getTagKind()) {
@@ -869,7 +869,7 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
// Replace lookup results with just the tag decl.
Result.clear(Sema::LookupTagName);
- SemaRef.LookupParsedName(Result, S, &SS);
+ SemaRef.LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType());
return true;
}
@@ -896,7 +896,8 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
}
LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
- LookupParsedName(Result, S, &SS, !CurMethod);
+ LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType(),
+ /*AllowBuiltinCreation=*/!CurMethod);
if (SS.isInvalid())
return NameClassification::Error();
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 83155c3..157d42c 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4519,7 +4519,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
DS.getBeginLoc(), DS.getEllipsisLoc());
} else {
LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName);
- LookupParsedName(R, S, &SS);
+ LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
TypeDecl *TyD = R.getAsSingle<TypeDecl>();
if (!TyD) {
@@ -12270,7 +12270,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc,
// Lookup namespace name.
LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName);
- LookupParsedName(R, S, &SS);
+ LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
if (R.isAmbiguous())
return nullptr;
@@ -13729,7 +13729,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
// Lookup the namespace name.
LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName);
- LookupParsedName(R, S, &SS);
+ LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
if (R.isAmbiguous())
return nullptr;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 50f92c4..0c37f43f7 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -673,8 +673,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
// expressions of certain types in C++.
if (getLangOpts().CPlusPlus &&
(E->getType() == Context.OverloadTy ||
- T->isDependentType() ||
- T->isRecordType()))
+ // FIXME: This is a hack! We want the lvalue-to-rvalue conversion applied
+ // to pointer types even if the pointee type is dependent.
+ (T->isDependentType() && !T->isPointerType()) || T->isRecordType()))
return E;
// The C standard is actually really unclear on this point, and
@@ -2751,8 +2752,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
if (isBoundsAttrContext() && !getLangOpts().CPlusPlus && S->isClassScope()) {
// See if this is reference to a field of struct.
LookupResult R(*this, NameInfo, LookupMemberName);
- // LookupParsedName handles a name lookup from within anonymous struct.
- if (LookupParsedName(R, S, &SS)) {
+ // LookupName handles a name lookup from within anonymous struct.
+ if (LookupName(R, S)) {
if (auto *VD = dyn_cast<ValueDecl>(R.getFoundDecl())) {
QualType type = VD->getType().getNonReferenceType();
// This will eventually be translated into MemberExpr upon
@@ -2773,20 +2774,19 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// lookup to determine that it was a template name in the first place. If
// this becomes a performance hit, we can work harder to preserve those
// results until we get here but it's likely not worth it.
- bool MemberOfUnknownSpecialization;
AssumedTemplateKind AssumedTemplate;
- if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
- MemberOfUnknownSpecialization, TemplateKWLoc,
+ if (LookupTemplateName(R, S, SS, /*ObjectType=*/QualType(),
+ /*EnteringContext=*/false, TemplateKWLoc,
&AssumedTemplate))
return ExprError();
- if (MemberOfUnknownSpecialization ||
- (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation))
+ if (R.wasNotFoundInCurrentInstantiation())
return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
IsAddressOfOperand, TemplateArgs);
} else {
bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl();
- LookupParsedName(R, S, &SS, !IvarLookupFollowUp);
+ LookupParsedName(R, S, &SS, /*ObjectType=*/QualType(),
+ /*AllowBuiltinCreation=*/!IvarLookupFollowUp);
// If the result might be in a dependent base class, this is a dependent
// id-expression.
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 779a416..c1cb03e 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -9157,7 +9157,7 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
// Do the redeclaration lookup in the current scope.
LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName,
RedeclarationKind::NotForRedeclaration);
- LookupParsedName(R, S, &SS);
+ LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
R.suppressDiagnostics();
switch (R.getResultKind()) {
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 6e30716..5facb14 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -667,8 +667,8 @@ namespace {
// classes, one of its base classes.
class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback {
public:
- explicit RecordMemberExprValidatorCCC(const RecordType *RTy)
- : Record(RTy->getDecl()) {
+ explicit RecordMemberExprValidatorCCC(QualType RTy)
+ : Record(RTy->getAsRecordDecl()) {
// Don't add bare keywords to the consumer since they will always fail
// validation by virtue of not being associated with any decls.
WantTypeSpecifiers = false;
@@ -713,58 +713,36 @@ private:
}
static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
- Expr *BaseExpr,
- const RecordType *RTy,
+ Expr *BaseExpr, QualType RTy,
SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS, bool HasTemplateArgs,
SourceLocation TemplateKWLoc,
TypoExpr *&TE) {
SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange();
- RecordDecl *RDecl = RTy->getDecl();
- if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) &&
- SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
- diag::err_typecheck_incomplete_tag,
- BaseRange))
+ if (!RTy->isDependentType() &&
+ !SemaRef.isThisOutsideMemberFunctionBody(RTy) &&
+ SemaRef.RequireCompleteType(
+ OpLoc, RTy, diag::err_typecheck_incomplete_tag, BaseRange))
return true;
- if (HasTemplateArgs || TemplateKWLoc.isValid()) {
- // LookupTemplateName doesn't expect these both to exist simultaneously.
- QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
+ // LookupTemplateName/LookupParsedName don't expect these both to exist
+ // simultaneously.
+ QualType ObjectType = SS.isSet() ? QualType() : RTy;
+ if (HasTemplateArgs || TemplateKWLoc.isValid())
+ return SemaRef.LookupTemplateName(R,
+ /*S=*/nullptr, SS, ObjectType,
+ /*EnteringContext=*/false, TemplateKWLoc);
- bool MOUS;
- return SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS,
- TemplateKWLoc);
- }
-
- DeclContext *DC = RDecl;
- if (SS.isSet()) {
- // If the member name was a qualified-id, look into the
- // nested-name-specifier.
- DC = SemaRef.computeDeclContext(SS, false);
-
- if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
- SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
- << SS.getRange() << DC;
- return true;
- }
-
- assert(DC && "Cannot handle non-computable dependent contexts in lookup");
-
- if (!isa<TypeDecl>(DC)) {
- SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
- << DC << SS.getRange();
- return true;
- }
- }
-
- // The record definition is complete, now look up the member.
- SemaRef.LookupQualifiedName(R, DC, SS);
+ SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
- if (!R.empty())
+ if (!R.empty() || R.wasNotFoundInCurrentInstantiation())
return false;
DeclarationName Typo = R.getLookupName();
SourceLocation TypoLoc = R.getNameLoc();
+ // Recompute the lookup context.
+ DeclContext *DC = SS.isSet() ? SemaRef.computeDeclContext(SS)
+ : SemaRef.computeDeclContext(RTy);
struct QueryState {
Sema &SemaRef;
@@ -788,7 +766,8 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
<< Typo << DC << DroppedSpecifier
<< SS.getRange());
} else {
- SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << DC << BaseRange;
+ SemaRef.Diag(TypoLoc, diag::err_no_member)
+ << Typo << DC << (SS.isSet() ? SS.getRange() : BaseRange);
}
},
[=](Sema &SemaRef, TypoExpr *TE, TypoCorrection TC) mutable {
@@ -814,34 +793,25 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
Decl *ObjCImpDecl, bool HasTemplateArgs,
SourceLocation TemplateKWLoc);
-ExprResult
-Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
- SourceLocation OpLoc, bool IsArrow,
- CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc,
- NamedDecl *FirstQualifierInScope,
- const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs,
- const Scope *S,
- ActOnMemberAccessExtraArgs *ExtraArgs) {
- if (BaseType->isDependentType() ||
- (SS.isSet() && isDependentScopeSpecifier(SS)) ||
- NameInfo.getName().isDependentName())
- return ActOnDependentMemberExpr(Base, BaseType,
- IsArrow, OpLoc,
- SS, TemplateKWLoc, FirstQualifierInScope,
- NameInfo, TemplateArgs);
-
+ExprResult Sema::BuildMemberReferenceExpr(
+ Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow,
+ CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
+ NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
+ ActOnMemberAccessExtraArgs *ExtraArgs) {
LookupResult R(*this, NameInfo, LookupMemberName);
+ if (SS.isInvalid())
+ return ExprError();
+
// Implicit member accesses.
if (!Base) {
TypoExpr *TE = nullptr;
QualType RecordTy = BaseType;
if (IsArrow) RecordTy = RecordTy->castAs<PointerType>()->getPointeeType();
- if (LookupMemberExprInRecord(
- *this, R, nullptr, RecordTy->castAs<RecordType>(), OpLoc, IsArrow,
- SS, TemplateArgs != nullptr, TemplateKWLoc, TE))
+ if (LookupMemberExprInRecord(*this, R, nullptr, RecordTy, OpLoc, IsArrow,
+ SS, TemplateArgs != nullptr, TemplateKWLoc,
+ TE))
return ExprError();
if (TE)
return TE;
@@ -969,19 +939,6 @@ BuildMSPropertyRefExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
}
MemberExpr *Sema::BuildMemberExpr(
- Expr *Base, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec *SS,
- SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl,
- bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo,
- QualType Ty, ExprValueKind VK, ExprObjectKind OK,
- const TemplateArgumentListInfo *TemplateArgs) {
- NestedNameSpecifierLoc NNS =
- SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc();
- return BuildMemberExpr(Base, IsArrow, OpLoc, NNS, TemplateKWLoc, Member,
- FoundDecl, HadMultipleCandidates, MemberNameInfo, Ty,
- VK, OK, TemplateArgs);
-}
-
-MemberExpr *Sema::BuildMemberExpr(
Expr *Base, bool IsArrow, SourceLocation OpLoc, NestedNameSpecifierLoc NNS,
SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl,
bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo,
@@ -1033,6 +990,17 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
const Scope *S,
bool SuppressQualifierCheck,
ActOnMemberAccessExtraArgs *ExtraArgs) {
+ assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid");
+ // If the member wasn't found in the current instantiation, or if the
+ // arrow operator was used with a dependent non-pointer object expression,
+ // build a CXXDependentScopeMemberExpr.
+ if (R.wasNotFoundInCurrentInstantiation() ||
+ (IsArrow && !BaseExprType->isPointerType() &&
+ BaseExprType->isDependentType()))
+ return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
+ TemplateKWLoc, FirstQualifierInScope,
+ R.getLookupNameInfo(), TemplateArgs);
+
QualType BaseType = BaseExprType;
if (IsArrow) {
assert(BaseType->isPointerType());
@@ -1040,6 +1008,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
}
R.setBaseObjectType(BaseType);
+ assert((SS.isEmpty()
+ ? !BaseType->isDependentType() || computeDeclContext(BaseType)
+ : !isDependentScopeSpecifier(SS) || computeDeclContext(SS)) &&
+ "dependent lookup context that isn't the current instantiation?");
+
// C++1z [expr.ref]p2:
// For the first option (dot) the first expression shall be a glvalue [...]
if (!IsArrow && BaseExpr && BaseExpr->isPRValue()) {
@@ -1068,40 +1041,39 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
<< isa<CXXDestructorDecl>(FD);
if (R.empty()) {
- // Rederive where we looked up.
- DeclContext *DC = (SS.isSet()
- ? computeDeclContext(SS, false)
- : BaseType->castAs<RecordType>()->getDecl());
-
- if (ExtraArgs) {
- ExprResult RetryExpr;
- if (!IsArrow && BaseExpr) {
- SFINAETrap Trap(*this, true);
- ParsedType ObjectType;
- bool MayBePseudoDestructor = false;
- RetryExpr = ActOnStartCXXMemberReference(getCurScope(), BaseExpr,
- OpLoc, tok::arrow, ObjectType,
- MayBePseudoDestructor);
- if (RetryExpr.isUsable() && !Trap.hasErrorOccurred()) {
- CXXScopeSpec TempSS(SS);
- RetryExpr = ActOnMemberAccessExpr(
- ExtraArgs->S, RetryExpr.get(), OpLoc, tok::arrow, TempSS,
- TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl);
- }
- if (Trap.hasErrorOccurred())
- RetryExpr = ExprError();
- }
- if (RetryExpr.isUsable()) {
- Diag(OpLoc, diag::err_no_member_overloaded_arrow)
- << MemberName << DC << FixItHint::CreateReplacement(OpLoc, "->");
- return RetryExpr;
+ ExprResult RetryExpr = ExprError();
+ if (ExtraArgs && !IsArrow && BaseExpr && !BaseExpr->isTypeDependent()) {
+ SFINAETrap Trap(*this, true);
+ ParsedType ObjectType;
+ bool MayBePseudoDestructor = false;
+ RetryExpr = ActOnStartCXXMemberReference(getCurScope(), BaseExpr, OpLoc,
+ tok::arrow, ObjectType,
+ MayBePseudoDestructor);
+ if (RetryExpr.isUsable() && !Trap.hasErrorOccurred()) {
+ CXXScopeSpec TempSS(SS);
+ RetryExpr = ActOnMemberAccessExpr(
+ ExtraArgs->S, RetryExpr.get(), OpLoc, tok::arrow, TempSS,
+ TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl);
}
+ if (Trap.hasErrorOccurred())
+ RetryExpr = ExprError();
}
- Diag(R.getNameLoc(), diag::err_no_member)
- << MemberName << DC
- << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
- return ExprError();
+ // Rederive where we looked up.
+ DeclContext *DC =
+ (SS.isSet() ? computeDeclContext(SS) : computeDeclContext(BaseType));
+ assert(DC);
+
+ if (RetryExpr.isUsable())
+ Diag(OpLoc, diag::err_no_member_overloaded_arrow)
+ << MemberName << DC << FixItHint::CreateReplacement(OpLoc, "->");
+ else
+ Diag(R.getNameLoc(), diag::err_no_member)
+ << MemberName << DC
+ << (SS.isSet()
+ ? SS.getRange()
+ : (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()));
+ return RetryExpr;
}
// Diagnose lookups that find only declarations from a non-base
@@ -1186,7 +1158,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
OpLoc);
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
- return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var,
+ return BuildMemberExpr(BaseExpr, IsArrow, OpLoc,
+ SS.getWithLocInContext(Context), TemplateKWLoc, Var,
FoundDecl, /*HadMultipleCandidates=*/false,
MemberNameInfo, Var->getType().getNonReferenceType(),
VK_LValue, OK_Ordinary);
@@ -1203,17 +1176,18 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
type = MemberFn->getType();
}
- return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc,
+ return BuildMemberExpr(BaseExpr, IsArrow, OpLoc,
+ SS.getWithLocInContext(Context), TemplateKWLoc,
MemberFn, FoundDecl, /*HadMultipleCandidates=*/false,
MemberNameInfo, type, valueKind, OK_Ordinary);
}
assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
- return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Enum,
- FoundDecl, /*HadMultipleCandidates=*/false,
- MemberNameInfo, Enum->getType(), VK_PRValue,
- OK_Ordinary);
+ return BuildMemberExpr(
+ BaseExpr, IsArrow, OpLoc, SS.getWithLocInContext(Context),
+ TemplateKWLoc, Enum, FoundDecl, /*HadMultipleCandidates=*/false,
+ MemberNameInfo, Enum->getType(), VK_PRValue, OK_Ordinary);
}
if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
@@ -1237,7 +1211,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
if (!Var->getTemplateSpecializationKind())
Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, MemberLoc);
- return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var,
+ return BuildMemberExpr(BaseExpr, IsArrow, OpLoc,
+ SS.getWithLocInContext(Context), TemplateKWLoc, Var,
FoundDecl, /*HadMultipleCandidates=*/false,
MemberNameInfo, Var->getType().getNonReferenceType(),
VK_LValue, OK_Ordinary, TemplateArgs);
@@ -1330,7 +1305,6 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
return ExprError();
QualType BaseType = BaseExpr.get()->getType();
- assert(!BaseType->isDependentType());
DeclarationName MemberName = R.getLookupName();
SourceLocation MemberLoc = R.getNameLoc();
@@ -1342,29 +1316,31 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
if (IsArrow) {
if (const PointerType *Ptr = BaseType->getAs<PointerType>())
BaseType = Ptr->getPointeeType();
- else if (const ObjCObjectPointerType *Ptr
- = BaseType->getAs<ObjCObjectPointerType>())
+ else if (const ObjCObjectPointerType *Ptr =
+ BaseType->getAs<ObjCObjectPointerType>())
BaseType = Ptr->getPointeeType();
- else if (BaseType->isRecordType()) {
- // Recover from arrow accesses to records, e.g.:
- // struct MyRecord foo;
- // foo->bar
- // This is actually well-formed in C++ if MyRecord has an
- // overloaded operator->, but that should have been dealt with
- // by now--or a diagnostic message already issued if a problem
- // was encountered while looking for the overloaded operator->.
- if (!S.getLangOpts().CPlusPlus) {
- S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, ".");
+ else if (!BaseType->isDependentType()) {
+ if (BaseType->isRecordType()) {
+ // Recover from arrow accesses to records, e.g.:
+ // struct MyRecord foo;
+ // foo->bar
+ // This is actually well-formed in C++ if MyRecord has an
+ // overloaded operator->, but that should have been dealt with
+ // by now--or a diagnostic message already issued if a problem
+ // was encountered while looking for the overloaded operator->.
+ if (!S.getLangOpts().CPlusPlus) {
+ S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateReplacement(OpLoc, ".");
+ }
+ IsArrow = false;
+ } else if (BaseType->isFunctionType()) {
+ goto fail;
+ } else {
+ S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
+ << BaseType << BaseExpr.get()->getSourceRange();
+ return ExprError();
}
- IsArrow = false;
- } else if (BaseType->isFunctionType()) {
- goto fail;
- } else {
- S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
- << BaseType << BaseExpr.get()->getSourceRange();
- return ExprError();
}
}
@@ -1384,10 +1360,10 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
}
// Handle field access to simple records.
- if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
+ if (BaseType->getAsRecordDecl() || BaseType->isDependentType()) {
TypoExpr *TE = nullptr;
- if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, OpLoc, IsArrow, SS,
- HasTemplateArgs, TemplateKWLoc, TE))
+ if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow,
+ SS, HasTemplateArgs, TemplateKWLoc, TE))
return ExprError();
// Returning valid-but-null is how we indicate to the caller that
@@ -1810,7 +1786,6 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
DecomposeUnqualifiedId(Id, TemplateArgsBuffer,
NameInfo, TemplateArgs);
- DeclarationName Name = NameInfo.getName();
bool IsArrow = (OpKind == tok::arrow);
if (getLangOpts().HLSL && IsArrow)
@@ -1824,13 +1799,6 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
if (Result.isInvalid()) return ExprError();
Base = Result.get();
- if (Base->getType()->isDependentType() || Name.isDependentName() ||
- isDependentScopeSpecifier(SS)) {
- return ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS,
- TemplateKWLoc, FirstQualifierInScope,
- NameInfo, TemplateArgs);
- }
-
ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl};
ExprResult Res = BuildMemberReferenceExpr(
Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc,
@@ -1949,10 +1917,10 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
}
}
- return BuildMemberExpr(Base.get(), IsArrow, OpLoc, &SS,
- /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
- /*HadMultipleCandidates=*/false, MemberNameInfo,
- MemberType, VK, OK);
+ return BuildMemberExpr(
+ Base.get(), IsArrow, OpLoc, SS.getWithLocInContext(Context),
+ /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
+ /*HadMultipleCandidates=*/false, MemberNameInfo, MemberType, VK, OK);
}
/// Builds an implicit member access expression. The current context
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 55af414..2f6ad49 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -1282,6 +1282,31 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
if (DeclContext *DC = PreS->getEntity())
DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
}
+ // C++23 [temp.dep.general]p2:
+ // The component name of an unqualified-id is dependent if
+ // - it is a conversion-function-id whose conversion-type-id
+ // is dependent, or
+ // - it is operator= and the current class is a templated entity, or
+ // - the unqualified-id is the postfix-expression in a dependent call.
+ if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
+ Name.getCXXNameType()->isDependentType()) {
+ R.setNotFoundInCurrentInstantiation();
+ return false;
+ }
+
+ // If this is the name of an implicitly-declared special member function,
+ // go through the scope stack to implicitly declare
+ if (isImplicitlyDeclaredMemberFunctionName(Name)) {
+ for (Scope *PreS = S; PreS; PreS = PreS->getParent())
+ if (DeclContext *DC = PreS->getEntity()) {
+ if (DC->isDependentContext() && isa<CXXRecordDecl>(DC) &&
+ Name.getCXXOverloadedOperator() == OO_Equal) {
+ R.setNotFoundInCurrentInstantiation();
+ return false;
+ }
+ DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
+ }
+ }
// Implicitly declare member functions with the name we're looking for, if in
// fact we are in a scope where it matters.
@@ -2446,10 +2471,33 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
}
} QL(LookupCtx);
+ CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx);
+ // FIXME: Per [temp.dep.general]p2, an unqualified name is also dependent
+ // if it's a dependent conversion-function-id or operator= where the current
+ // class is a templated entity. This should be handled in LookupName.
+ if (!InUnqualifiedLookup && !R.isForRedeclaration()) {
+ // C++23 [temp.dep.type]p5:
+ // A qualified name is dependent if
+ // - it is a conversion-function-id whose conversion-type-id
+ // is dependent, or
+ // - [...]
+ // - its lookup context is the current instantiation and it
+ // is operator=, or
+ // - [...]
+ if (DeclarationName Name = R.getLookupName();
+ (Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
+ Name.getCXXNameType()->isDependentType()) ||
+ (Name.getCXXOverloadedOperator() == OO_Equal && LookupRec &&
+ LookupRec->isDependentContext())) {
+ R.setNotFoundInCurrentInstantiation();
+ return false;
+ }
+ }
+
if (LookupDirect(*this, R, LookupCtx)) {
R.resolveKind();
- if (isa<CXXRecordDecl>(LookupCtx))
- R.setNamingClass(cast<CXXRecordDecl>(LookupCtx));
+ if (LookupRec)
+ R.setNamingClass(LookupRec);
return true;
}
@@ -2471,7 +2519,6 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// If this isn't a C++ class, we aren't allowed to look into base
// classes, we're done.
- CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx);
if (!LookupRec || !LookupRec->getDefinition())
return false;
@@ -2718,38 +2765,54 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
///
/// @returns True if any decls were found (but possibly ambiguous)
bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
- bool AllowBuiltinCreation, bool EnteringContext) {
- if (SS && SS->isInvalid()) {
- // When the scope specifier is invalid, don't even look for
- // anything.
+ QualType ObjectType, bool AllowBuiltinCreation,
+ bool EnteringContext) {
+ // When the scope specifier is invalid, don't even look for anything.
+ if (SS && SS->isInvalid())
return false;
- }
- if (SS && SS->isSet()) {
- NestedNameSpecifier *NNS = SS->getScopeRep();
- if (NNS->getKind() == NestedNameSpecifier::Super)
+ // Determine where to perform name lookup
+ DeclContext *DC = nullptr;
+ bool IsDependent = false;
+ 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 || SS->isEmpty()) &&
+ "ObjectType and scope specifier cannot coexist");
+ DC = computeDeclContext(ObjectType);
+ IsDependent = !DC && ObjectType->isDependentType();
+ assert(((!DC && ObjectType->isDependentType()) ||
+ !ObjectType->isIncompleteType() || !ObjectType->getAs<TagType>() ||
+ ObjectType->castAs<TagType>()->isBeingDefined()) &&
+ "Caller should have completed object type");
+ } else if (SS && SS->isNotEmpty()) {
+ if (NestedNameSpecifier *NNS = SS->getScopeRep();
+ NNS->getKind() == NestedNameSpecifier::Super)
return LookupInSuper(R, NNS->getAsRecordDecl());
-
- if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) {
- // We have resolved the scope specifier to a particular declaration
- // contex, and will perform name lookup in that context.
+ // This nested-name-specifier occurs after another nested-name-specifier,
+ // so long into the context associated with the prior nested-name-specifier.
+ if ((DC = computeDeclContext(*SS, EnteringContext))) {
+ // The declaration context must be complete.
if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS, DC))
return false;
-
R.setContextRange(SS->getRange());
- return LookupQualifiedName(R, DC);
}
+ IsDependent = !DC && isDependentScopeSpecifier(*SS);
+ } else {
+ // Perform unqualified name lookup starting in the given scope.
+ return LookupName(R, S, AllowBuiltinCreation);
+ }
+ // If we were able to compute a declaration context, perform qualified name
+ // lookup in that context.
+ if (DC)
+ return LookupQualifiedName(R, DC);
+ else if (IsDependent)
// We could not resolve the scope specified to a specific declaration
// context, which means that SS refers to an unknown specialization.
// Name lookup can't find anything in this case.
R.setNotFoundInCurrentInstantiation();
- R.setContextRange(SS->getRange());
- return false;
- }
-
- // Perform unqualified name lookup starting in the given scope.
- return LookupName(R, S, AllowBuiltinCreation);
+ return false;
}
/// Perform qualified name lookup into all base classes of the given
@@ -5018,8 +5081,9 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
return;
}
- SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false,
- EnteringContext);
+ SemaRef.LookupParsedName(Res, S, SS,
+ /*ObjectType=*/QualType(),
+ /*AllowBuiltinCreation=*/false, EnteringContext);
// Fake ivar lookup; this should really be part of
// LookupParsedName.
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index cee8da4..cf5447f 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3061,7 +3061,9 @@ ExprResult SemaOpenMP::ActOnOpenMPIdExpression(Scope *CurScope,
OpenMPDirectiveKind Kind) {
ASTContext &Context = getASTContext();
LookupResult Lookup(SemaRef, Id, Sema::LookupOrdinaryName);
- SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
+ SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec,
+ /*ObjectType=*/QualType(),
+ /*AllowBuiltinCreation=*/true);
if (Lookup.isAmbiguous())
return ExprError();
@@ -7407,7 +7409,8 @@ void SemaOpenMP::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(
const IdentifierInfo *BaseII = D.getIdentifier();
LookupResult Lookup(SemaRef, DeclarationName(BaseII), D.getIdentifierLoc(),
Sema::LookupOrdinaryName);
- SemaRef.LookupParsedName(Lookup, S, &D.getCXXScopeSpec());
+ SemaRef.LookupParsedName(Lookup, S, &D.getCXXScopeSpec(),
+ /*ObjectType=*/QualType());
TypeSourceInfo *TInfo = SemaRef.GetTypeForDeclarator(D);
QualType FType = TInfo->getType();
@@ -19311,7 +19314,8 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
if (S) {
LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName);
Lookup.suppressDiagnostics();
- while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec)) {
+ while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec,
+ /*ObjectType=*/QualType())) {
NamedDecl *D = Lookup.getRepresentativeDecl();
do {
S = S->getParent();
@@ -22180,7 +22184,8 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName);
Lookup.suppressDiagnostics();
if (S) {
- while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec)) {
+ while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec,
+ /*ObjectType=*/QualType())) {
NamedDecl *D = Lookup.getRepresentativeDecl();
while (S && !S->isDeclScope(D))
S = S->getParent();
@@ -23497,7 +23502,9 @@ void SemaOpenMP::DiagnoseUnterminatedOpenMPDeclareTarget() {
NamedDecl *SemaOpenMP::lookupOpenMPDeclareTargetName(
Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id) {
LookupResult Lookup(SemaRef, Id, Sema::LookupOrdinaryName);
- SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
+ SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec,
+ /*ObjectType=*/QualType(),
+ /*AllowBuiltinCreation=*/true);
if (Lookup.isAmbiguous())
return nullptr;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 3c2a5a4..7f18631 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -210,10 +210,11 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
AssumedTemplateKind AssumedTemplate;
LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName);
if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
- MemberOfUnknownSpecialization, SourceLocation(),
+ /*RequiredTemplate=*/SourceLocation(),
&AssumedTemplate,
/*AllowTypoCorrection=*/!Disambiguation))
return TNK_Non_template;
+ MemberOfUnknownSpecialization = R.wasNotFoundInCurrentInstantiation();
if (AssumedTemplate != AssumedTemplateKind::None) {
TemplateResult = TemplateTy::make(Context.getAssumedTemplateName(TName));
@@ -320,15 +321,12 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name,
SourceLocation NameLoc, CXXScopeSpec &SS,
ParsedTemplateTy *Template /*=nullptr*/) {
- bool MemberOfUnknownSpecialization = false;
-
// We could use redeclaration lookup here, but we don't need to: the
// syntactic form of a deduction guide is enough to identify it even
// if we can't look up the template name at all.
LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName);
if (LookupTemplateName(R, S, SS, /*ObjectType*/ QualType(),
- /*EnteringContext*/ false,
- MemberOfUnknownSpecialization))
+ /*EnteringContext*/ false))
return false;
if (R.empty()) return false;
@@ -374,11 +372,8 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
return true;
}
-bool Sema::LookupTemplateName(LookupResult &Found,
- Scope *S, CXXScopeSpec &SS,
- QualType ObjectType,
- bool EnteringContext,
- bool &MemberOfUnknownSpecialization,
+bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
+ QualType ObjectType, bool EnteringContext,
RequiredTemplateKind RequiredTemplate,
AssumedTemplateKind *ATK,
bool AllowTypoCorrection) {
@@ -391,7 +386,6 @@ bool Sema::LookupTemplateName(LookupResult &Found,
Found.setTemplateNameLookup(true);
// Determine where to perform name lookup
- MemberOfUnknownSpecialization = false;
DeclContext *LookupCtx = nullptr;
bool IsDependent = false;
if (!ObjectType.isNull()) {
@@ -548,7 +542,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup);
if (Found.empty()) {
if (IsDependent) {
- MemberOfUnknownSpecialization = true;
+ Found.setNotFoundInCurrentInstantiation();
return false;
}
@@ -5595,11 +5589,9 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
RequireCompleteDeclContext(SS, DC))
return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
- bool MemberOfUnknownSpecialization;
LookupResult R(*this, NameInfo, LookupOrdinaryName);
if (LookupTemplateName(R, (Scope *)nullptr, SS, QualType(),
- /*Entering*/false, MemberOfUnknownSpecialization,
- TemplateKWLoc))
+ /*Entering*/ false, TemplateKWLoc))
return ExprError();
if (R.isAmbiguous())
@@ -5720,14 +5712,13 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S,
DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name);
LookupResult R(*this, DNI.getName(), Name.getBeginLoc(),
LookupOrdinaryName);
- bool MOUS;
// Tell LookupTemplateName that we require a template so that it diagnoses
// cases where it finds a non-template.
RequiredTemplateKind RTK = TemplateKWLoc.isValid()
? RequiredTemplateKind(TemplateKWLoc)
: TemplateNameIsRequired;
- if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, MOUS,
- RTK, nullptr, /*AllowTypoCorrection=*/false) &&
+ if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, RTK,
+ /*ATK=*/nullptr, /*AllowTypoCorrection=*/false) &&
!R.isAmbiguous()) {
if (LookupCtx)
Diag(Name.getBeginLoc(), diag::err_no_member)
@@ -5816,7 +5807,7 @@ bool Sema::CheckTemplateTypeArgument(
if (auto *II = NameInfo.getName().getAsIdentifierInfo()) {
LookupResult Result(*this, NameInfo, LookupOrdinaryName);
- LookupParsedName(Result, CurScope, &SS);
+ LookupParsedName(Result, CurScope, &SS, /*ObjectType=*/QualType());
if (Result.getAsSingle<TypeDecl>() ||
Result.getResultKind() ==
@@ -11190,7 +11181,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
: TSK_ExplicitInstantiationDeclaration;
LookupResult Previous(*this, NameInfo, LookupOrdinaryName);
- LookupParsedName(Previous, S, &D.getCXXScopeSpec());
+ LookupParsedName(Previous, S, &D.getCXXScopeSpec(),
+ /*ObjectType=*/QualType());
if (!R->isFunctionType()) {
// C++ [temp.explicit]p1:
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index f47bc21..28d3d1b 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13217,6 +13217,26 @@ bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old,
// Resolve a kind, but don't do any further analysis. If it's
// ambiguous, the callee needs to deal with it.
R.resolveKind();
+
+ if (Old->hasTemplateKeyword() && !R.empty()) {
+ NamedDecl *FoundDecl = R.getRepresentativeDecl()->getUnderlyingDecl();
+ getSema().FilterAcceptableTemplateNames(R,
+ /*AllowFunctionTemplates=*/true,
+ /*AllowDependent=*/true);
+ if (R.empty()) {
+ // If a 'template' keyword was used, a lookup that finds only non-template
+ // names is an error.
+ getSema().Diag(R.getNameLoc(),
+ diag::err_template_kw_refers_to_non_template)
+ << R.getLookupName() << Old->getQualifierLoc().getSourceRange()
+ << Old->hasTemplateKeyword() << Old->getTemplateKeywordLoc();
+ getSema().Diag(FoundDecl->getLocation(),
+ diag::note_template_kw_refers_to_non_template)
+ << R.getLookupName();
+ return true;
+ }
+ }
+
return false;
}