[clang] [clang-tools-extra] [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 (PR #84050)
Krystian Stasiowski via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 8 04:24:09 PDT 2024
https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/84050
>From 5bf340c85b1a64d2c7f0e9b96cef638e9bd1e358 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 1 Mar 2024 08:08:52 -0500
Subject: [PATCH 01/18] [Clang][Sema] Earlier resolution of class member access
expressions naming member of the current instantiation
---
clang/lib/AST/Expr.cpp | 2 +-
clang/lib/Sema/SemaExpr.cpp | 4 +-
clang/lib/Sema/SemaExprMember.cpp | 121 ++++++++++++++------
clang/lib/Sema/SemaOverload.cpp | 3 +
clang/test/SemaTemplate/dependent-names.cpp | 4 +-
5 files changed, 93 insertions(+), 41 deletions(-)
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 07c9f287dd0767..9945b9e549e10c 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -103,7 +103,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
}
} else if (const auto *ME = dyn_cast<MemberExpr>(E)) {
if (!ME->isArrow()) {
- assert(ME->getBase()->getType()->isRecordType());
+ assert(ME->getBase()->getType()->getAsRecordDecl());
if (const auto *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
if (!Field->isBitField() && !Field->getType()->isReferenceType()) {
E = ME->getBase();
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 6b2eb245d58263..3ba88f9b4473da 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -667,7 +667,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
// expressions of certain types in C++.
if (getLangOpts().CPlusPlus &&
(E->getType() == Context.OverloadTy ||
- T->isDependentType() ||
+ // 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;
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 32998ae60eafe2..fd55e6f46a1066 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -624,8 +624,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;
@@ -671,33 +671,55 @@ class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback {
static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
Expr *BaseExpr,
- const RecordType *RTy,
+ QualType RTy,
SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS, bool HasTemplateArgs,
SourceLocation TemplateKWLoc,
TypoExpr *&TE) {
+ RecordDecl *RDecl = RTy->getAsRecordDecl();
+ DeclContext *DC = SemaRef.computeDeclContext(RTy);
+ // If the object expression is dependent and isn't the current instantiation,
+ // lookup will not find anything and we must defer until instantiation.
+ if (!DC) {
+ R.setNotFoundInCurrentInstantiation();
+ return false;
+ }
+
+ // FIXME: Should this use Name.isDependentName()?
+ if (DeclarationName Name = R.getLookupName();
+ Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
+ Name.getCXXNameType()->isDependentType()) {
+ R.setNotFoundInCurrentInstantiation();
+ return false;
+ }
+
SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange();
- RecordDecl *RDecl = RTy->getDecl();
- if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) &&
- SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
+ 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);
+ QualType ObjectType = SS.isSet() ? QualType() : RTy;
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);
+ // We tried to look into a dependent context that is not the current
+ // instantiation. Defer lookup until instantiation.
+ if (!DC) {
+ R.setNotFoundInCurrentInstantiation();
+ return false;
+ }
if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
@@ -717,7 +739,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
// The record definition is complete, now look up the member.
SemaRef.LookupQualifiedName(R, DC, SS);
- if (!R.empty())
+ if (!R.empty() || R.wasNotFoundInCurrentInstantiation())
return false;
DeclarationName Typo = R.getLookupName();
@@ -781,6 +803,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
const TemplateArgumentListInfo *TemplateArgs,
const Scope *S,
ActOnMemberAccessExtraArgs *ExtraArgs) {
+ #if 0
if (BaseType->isDependentType() ||
(SS.isSet() && isDependentScopeSpecifier(SS)) ||
NameInfo.getName().isDependentName())
@@ -788,6 +811,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
IsArrow, OpLoc,
SS, TemplateKWLoc, FirstQualifierInScope,
NameInfo, TemplateArgs);
+ #endif
LookupResult R(*this, NameInfo, LookupMemberName);
@@ -797,7 +821,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
QualType RecordTy = BaseType;
if (IsArrow) RecordTy = RecordTy->castAs<PointerType>()->getPointeeType();
if (LookupMemberExprInRecord(
- *this, R, nullptr, RecordTy->castAs<RecordType>(), OpLoc, IsArrow,
+ *this, R, nullptr, RecordTy, OpLoc, IsArrow,
SS, TemplateArgs != nullptr, TemplateKWLoc, TE))
return ExprError();
if (TE)
@@ -990,6 +1014,14 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
const Scope *S,
bool SuppressQualifierCheck,
ActOnMemberAccessExtraArgs *ExtraArgs) {
+
+ if (R.wasNotFoundInCurrentInstantiation() || (SS.isValid() && !computeDeclContext(SS, false))) {
+ return ActOnDependentMemberExpr(BaseExpr, BaseExprType,
+ IsArrow, OpLoc,
+ SS, TemplateKWLoc, FirstQualifierInScope,
+ R.getLookupNameInfo(), TemplateArgs);
+ }
+
QualType BaseType = BaseExprType;
if (IsArrow) {
assert(BaseType->isPointerType());
@@ -1028,11 +1060,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
// Rederive where we looked up.
DeclContext *DC = (SS.isSet()
? computeDeclContext(SS, false)
- : BaseType->castAs<RecordType>()->getDecl());
+ : BaseType->getAsRecordDecl());
if (ExtraArgs) {
ExprResult RetryExpr;
- if (!IsArrow && BaseExpr) {
+ if (!IsArrow && BaseExpr && !BaseExpr->isTypeDependent()) {
SFINAETrap Trap(*this, true);
ParsedType ObjectType;
bool MayBePseudoDestructor = false;
@@ -1055,9 +1087,16 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
}
}
- Diag(R.getNameLoc(), diag::err_no_member)
- << MemberName << DC
- << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
+ if(DC) {
+ Diag(R.getNameLoc(), diag::err_no_member)
+ << MemberName << DC
+ << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
+ } else {
+ // FIXME: Is this needed?
+ Diag(R.getNameLoc(), diag::err_no_member)
+ << MemberName << BaseExprType
+ << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
+ }
return ExprError();
}
@@ -1287,7 +1326,10 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
return ExprError();
QualType BaseType = BaseExpr.get()->getType();
+
+ #if 0
assert(!BaseType->isDependentType());
+ #endif
DeclarationName MemberName = R.getLookupName();
SourceLocation MemberLoc = R.getNameLoc();
@@ -1299,29 +1341,32 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
if (IsArrow) {
if (const PointerType *Ptr = BaseType->getAs<PointerType>())
BaseType = Ptr->getPointeeType();
- else if (const ObjCObjectPointerType *Ptr
+ else if (!BaseType->isDependentType()) {
+ 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->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();
+
}
}
@@ -1341,9 +1386,9 @@ 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,
+ if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow, SS,
HasTemplateArgs, TemplateKWLoc, TE))
return ExprError();
@@ -1781,12 +1826,14 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
if (Result.isInvalid()) return ExprError();
Base = Result.get();
+ #if 0
if (Base->getType()->isDependentType() || Name.isDependentName() ||
isDependentScopeSpecifier(SS)) {
return ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS,
TemplateKWLoc, FirstQualifierInScope,
NameInfo, TemplateArgs);
}
+ #endif
ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl};
ExprResult Res = BuildMemberReferenceExpr(
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 0c913bc700f4a1..be667c0c961f32 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -5803,7 +5803,10 @@ static ImplicitConversionSequence TryObjectArgumentInitialization(
return ICS;
}
+ // FIXME: Should this check getAsRecordDecl instead?
+ #if 0
assert(FromType->isRecordType());
+ #endif
QualType ClassType = S.Context.getTypeDeclType(ActingContext);
// C++98 [class.dtor]p2:
diff --git a/clang/test/SemaTemplate/dependent-names.cpp b/clang/test/SemaTemplate/dependent-names.cpp
index 641ec950054f57..a661f14af80d34 100644
--- a/clang/test/SemaTemplate/dependent-names.cpp
+++ b/clang/test/SemaTemplate/dependent-names.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
typedef double A;
template<typename T> class B {
@@ -334,7 +334,7 @@ int arr[sizeof(Sub)];
namespace PR11421 {
template < unsigned > struct X {
static const unsigned dimension = 3;
- template<unsigned dim=dimension>
+ template<unsigned dim=dimension>
struct Y: Y<dim> { }; // expected-error{{circular inheritance between 'Y<dim>' and 'Y<dim>'}}
};
typedef X<3> X3;
>From 9609595f075ac2355cf065e855a3fe3a91a1ba9e Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 1 Mar 2024 11:54:23 -0500
Subject: [PATCH 02/18] [FOLD] update tests
---
.../temp.res/temp.dep/temp.dep.type/p4.cpp | 110 ++++++++++++++++++
.../SemaTemplate/instantiate-function-1.cpp | 14 +--
2 files changed, 117 insertions(+), 7 deletions(-)
create mode 100644 clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
new file mode 100644
index 00000000000000..7b36e3ad3b0131
--- /dev/null
+++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
@@ -0,0 +1,110 @@
+// RUN: %clang_cc1 -Wno-unused-value -verify %s
+
+namespace N0 {
+ template<typename T>
+ struct A {
+ int x;
+ void f();
+ using X = int;
+
+ void not_instantiated(A *a, A &b) {
+ x;
+ f();
+ new X;
+
+ this->x;
+ this->f();
+ this->A::x;
+ this->A::f();
+
+ a->x;
+ a->f();
+ a->A::x;
+ a->A::f();
+
+ (*this).x;
+ (*this).f();
+ (*this).A::x;
+ (*this).A::f();
+
+ b.x;
+ b.f();
+ b.A::x;
+ b.A::f();
+
+ A::x;
+ A::f();
+ new A::X;
+
+ y; // expected-error{{use of undeclared identifier 'y'}}
+ g(); // expected-error{{use of undeclared identifier 'g'}}
+ new Y; // expected-error{{unknown type name 'Y'}}
+
+ this->y; // expected-error{{no member named 'y' in 'A<T>'}}
+ this->g(); // expected-error{{no member named 'g' in 'A<T>'}}
+ this->A::y; // expected-error{{no member named 'y' in 'A<T>'}}
+ this->A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
+
+ a->y; // expected-error{{no member named 'y' in 'A<T>'}}
+ a->g(); // expected-error{{no member named 'g' in 'A<T>'}}
+ a->A::y; // expected-error{{no member named 'y' in 'A<T>'}}
+ a->A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
+
+ // FIXME: An overloaded unary 'operator*' is built for these
+ // even though the operand is a pointer (to a dependent type).
+ // Type::isOverloadableType should return false for such cases.
+ (*this).y;
+ (*this).g();
+ (*this).A::y;
+ (*this).A::g();
+
+ b.y; // expected-error{{no member named 'y' in 'A<T>'}}
+ b.g(); // expected-error{{no member named 'g' in 'A<T>'}}
+ b.A::y; // expected-error{{no member named 'y' in 'A<T>'}}
+ b.A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
+
+ A::y; // expected-error{{no member named 'y' in 'A<T>'}}
+ A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
+ new A::Y; // expected-error{{no type named 'Y' in 'A<T>'}}
+ }
+ };
+} // namespace N0
+
+namespace N1 {
+ struct A {
+ template<int I>
+ void f();
+ };
+
+ template<typename T>
+ struct B {
+ template<int I>
+ void f();
+
+ A x;
+ A g();
+
+ void not_instantiated(B *a, B &b) {
+ f<0>();
+ this->f<0>();
+ a->f<0>();
+ // FIXME: This should not require 'template'!
+ (*this).f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+ b.f<0>();
+
+ x.f<0>();
+ this->x.f<0>();
+ a->x.f<0>();
+ // FIXME: This should not require 'template'!
+ (*this).x.f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+ b.x.f<0>();
+
+ // FIXME: None of these should require 'template'!
+ g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+ this->g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+ a->g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+ (*this).g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+ b.g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+ }
+ };
+} // namespace N1
diff --git a/clang/test/SemaTemplate/instantiate-function-1.cpp b/clang/test/SemaTemplate/instantiate-function-1.cpp
index ceef2743774805..a4967264c654b7 100644
--- a/clang/test/SemaTemplate/instantiate-function-1.cpp
+++ b/clang/test/SemaTemplate/instantiate-function-1.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
template<typename T, typename U>
struct X0 {
- void f(T x, U y) {
+ void f(T x, U y) {
(void)(x + y); // expected-error{{invalid operands}}
}
};
@@ -41,7 +41,7 @@ template <typename T> struct X4 {
T f() const {
return; // expected-error{{non-void function 'f' should return a value}}
}
-
+
T g() const {
return 1; // expected-error{{void function 'g' should not return a value}}
}
@@ -64,7 +64,7 @@ template<typename T, typename U, typename V> struct X6 {
// IfStmt
if (t > 0)
return u;
- else {
+ else {
if (t < 0)
return v; // expected-error{{cannot initialize return object of type}}
}
@@ -131,12 +131,12 @@ template<typename T> struct Member0 {
t;
t.f;
t->f;
-
+
T* tp;
tp.f; // expected-error{{member reference base type 'T *' is not a structure or union}}
tp->f;
- this->f;
+ this->f; // expected-error{{reference to non-static member function must be called}}
this.f; // expected-error{{member reference base type 'Member0<T> *' is not a structure or union}}
}
};
@@ -239,11 +239,11 @@ namespace PR9880 {
static yes_tag check(char[sizeof(&U::luaIndex)]);
enum { value = sizeof(check<T>(0)) == sizeof(yes_tag) };
};
-
+
class SomeClass {
public:
int luaIndex(lua_State* L);
};
-
+
int i = HasIndexMetamethod<SomeClass>::value;
}
>From 9307f5d7fdb7aa9192ed87614408e4298155983f Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 4 Mar 2024 06:59:58 -0500
Subject: [PATCH 03/18] [FOLD] build DependentMemberExpr for
LookupResult::FoundUnresolved
---
clang/lib/Sema/SemaExprMember.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index fd55e6f46a1066..95ad16571de8d6 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -676,7 +676,6 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
CXXScopeSpec &SS, bool HasTemplateArgs,
SourceLocation TemplateKWLoc,
TypoExpr *&TE) {
- RecordDecl *RDecl = RTy->getAsRecordDecl();
DeclContext *DC = SemaRef.computeDeclContext(RTy);
// If the object expression is dependent and isn't the current instantiation,
// lookup will not find anything and we must defer until instantiation.
@@ -1015,7 +1014,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
bool SuppressQualifierCheck,
ActOnMemberAccessExtraArgs *ExtraArgs) {
- if (R.wasNotFoundInCurrentInstantiation() || (SS.isValid() && !computeDeclContext(SS, false))) {
+ if (R.wasNotFoundInCurrentInstantiation() ||
+ (SS.isValid() && !computeDeclContext(SS, false)) ||
+ (R.isUnresolvableResult() && R.isClassLookup() && R.getNamingClass()->isDependentContext())) {
return ActOnDependentMemberExpr(BaseExpr, BaseExprType,
IsArrow, OpLoc,
SS, TemplateKWLoc, FirstQualifierInScope,
>From c71b7dd0919dab2e2cbc3d8d17873b50e311644b Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 5 Mar 2024 10:03:05 -0500
Subject: [PATCH 04/18] [FOLD] TransformOverloadExprDecls filters template
names
---
clang/lib/Sema/SemaExprMember.cpp | 3 +--
clang/lib/Sema/TreeTransform.h | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 95ad16571de8d6..fd3f8860d46f98 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -1015,8 +1015,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
ActOnMemberAccessExtraArgs *ExtraArgs) {
if (R.wasNotFoundInCurrentInstantiation() ||
- (SS.isValid() && !computeDeclContext(SS, false)) ||
- (R.isUnresolvableResult() && R.isClassLookup() && R.getNamingClass()->isDependentContext())) {
+ (SS.isValid() && !computeDeclContext(SS, false))) {
return ActOnDependentMemberExpr(BaseExpr, BaseExprType,
IsArrow, OpLoc,
SS, TemplateKWLoc, FirstQualifierInScope,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index a2568ad0f82cc2..b494179a70d46c 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -12984,6 +12984,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;
}
>From 4352ba0d89f0338bf4d4127fdf2ce8faaab9c349 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 5 Mar 2024 10:50:53 -0500
Subject: [PATCH 05/18] [FOLD] update tests
---
clang/test/AST/HLSL/this-reference-template.hlsl | 2 +-
clang/test/CodeGenCXX/mangle.cpp | 8 --------
clang/test/Index/annotate-nested-name-specifier.cpp | 4 ++--
clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp | 4 ++--
4 files changed, 5 insertions(+), 13 deletions(-)
diff --git a/clang/test/AST/HLSL/this-reference-template.hlsl b/clang/test/AST/HLSL/this-reference-template.hlsl
index 60e057986ebf80..d427e73044b788 100644
--- a/clang/test/AST/HLSL/this-reference-template.hlsl
+++ b/clang/test/AST/HLSL/this-reference-template.hlsl
@@ -24,7 +24,7 @@ void main() {
// CHECK: -CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:8:3, line:10:3> line:8:5 getFirst 'K ()' implicit-inline
// CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:16, line:10:3>
// CHECK-NEXT:-ReturnStmt 0x{{[0-9A-Fa-f]+}} <line:9:4, col:16>
-// CHECK-NEXT:-CXXDependentScopeMemberExpr 0x{{[0-9A-Fa-f]+}} <col:11, col:16> '<dependent type>' lvalue .First
+// CHECK-NEXT:-MemberExpr 0x{{[0-9A-Fa-f]+}} <col:11, col:16> 'K' lvalue .First 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT:-CXXThisExpr 0x{{[0-9A-Fa-f]+}} <col:11> 'Pair<K, V>' lvalue this
// CHECK-NEXT:-CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:12:3, line:14:3> line:12:5 getSecond 'V ()' implicit-inline
// CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:17, line:14:3>
diff --git a/clang/test/CodeGenCXX/mangle.cpp b/clang/test/CodeGenCXX/mangle.cpp
index 31467d943840e0..d0800af55c87e8 100644
--- a/clang/test/CodeGenCXX/mangle.cpp
+++ b/clang/test/CodeGenCXX/mangle.cpp
@@ -1032,10 +1032,6 @@ namespace test51 {
template <typename T>
decltype(S1<T>().~S1<T>(), S1<T>().~S1<T>()) fun4() {};
template <typename T>
- decltype(S1<int>().~S1<T>()) fun5(){};
- template <template <typename T> class U>
- decltype(S1<int>().~U<int>()) fun6(){};
- template <typename T>
decltype(E().E::~T()) fun7() {}
template <template <typename> class U>
decltype(X<int>::Y().U<int>::Y::~Y()) fun8() {}
@@ -1047,10 +1043,6 @@ namespace test51 {
// CHECK-LABEL: @_ZN6test514fun3I2S1IiEiEEDTcldtcvS1_IT0_E_EdnT_EEv
template void fun4<int>();
// CHECK-LABEL: @_ZN6test514fun4IiEEDTcmcldtcv2S1IT_E_Edn2S1IS2_EEcldtcvS3__Edn2S1IS2_EEEv
- template void fun5<int>();
- // CHECK-LABEL: @_ZN6test514fun5IiEEDTcldtcv2S1IiE_Edn2S1IT_EEEv
- template void fun6<S1>();
- // CHECK-LABEL: @_ZN6test514fun6I2S1EEDTcldtcvS1_IiE_EdnT_IiEEEv
template void fun7<E>();
// CHECK-LABEL: @_ZN6test514fun7INS_1EEEEDTcldtcvS1__Esr1EEdnT_EEv
template void fun8<X>();
diff --git a/clang/test/Index/annotate-nested-name-specifier.cpp b/clang/test/Index/annotate-nested-name-specifier.cpp
index a7338db6b05b77..3181497258407f 100644
--- a/clang/test/Index/annotate-nested-name-specifier.cpp
+++ b/clang/test/Index/annotate-nested-name-specifier.cpp
@@ -132,7 +132,7 @@ struct X8 {
struct X9 : X8 {
typedef X8 inherited;
- void f() {
+ void f() {
inherited::f();
}
};
@@ -299,7 +299,7 @@ struct X9 : X8 {
// CHECK: Identifier: "type" [77:16 - 77:20] TypeRef=X4::type:70:13
// CHECK: Punctuation: ">" [77:20 - 77:21] MemberRefExpr=
// CHECK: Punctuation: "::" [77:21 - 77:23] MemberRefExpr=
-// CHECK: Identifier: "g" [77:23 - 77:24] MemberRefExpr=
+// CHECK: Identifier: "g" [77:23 - 77:24] OverloadedDeclRef=
// CHECK: Punctuation: "(" [77:24 - 77:25] CallExpr=
// CHECK: Identifier: "t" [77:25 - 77:26] DeclRefExpr=t:74:12
// CHECK: Punctuation: ")" [77:26 - 77:27] CallExpr=
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 87774b00956a5a..739f495510dee5 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1569,8 +1569,8 @@ TEST_P(ASTMatchersTest, IsArrow_MatchesMemberVariablesViaArrow) {
matches("class Y { void x() { y; } int y; };", memberExpr(isArrow())));
EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } int y; };",
memberExpr(isArrow())));
- EXPECT_TRUE(matches("template <class T> class Y { void x() { this->m; } };",
- cxxDependentScopeMemberExpr(isArrow())));
+ EXPECT_TRUE(matches("template <class T> class Y { void x() { this->m; } int m; };",
+ memberExpr(isArrow())));
EXPECT_TRUE(
notMatches("template <class T> class Y { void x() { (*this).m; } };",
cxxDependentScopeMemberExpr(isArrow())));
>From 865dcffd227ba5203c34839ca5c9b7951e487252 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 5 Mar 2024 12:33:40 -0500
Subject: [PATCH 06/18] [FOLD] cleanup
---
clang/lib/Sema/SemaExprMember.cpp | 19 -------------------
clang/test/SemaTemplate/dependent-names.cpp | 4 ++--
2 files changed, 2 insertions(+), 21 deletions(-)
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index fd3f8860d46f98..eb87e0edda0128 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -802,16 +802,6 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
const TemplateArgumentListInfo *TemplateArgs,
const Scope *S,
ActOnMemberAccessExtraArgs *ExtraArgs) {
- #if 0
- if (BaseType->isDependentType() ||
- (SS.isSet() && isDependentScopeSpecifier(SS)) ||
- NameInfo.getName().isDependentName())
- return ActOnDependentMemberExpr(Base, BaseType,
- IsArrow, OpLoc,
- SS, TemplateKWLoc, FirstQualifierInScope,
- NameInfo, TemplateArgs);
- #endif
-
LookupResult R(*this, NameInfo, LookupMemberName);
// Implicit member accesses.
@@ -1826,15 +1816,6 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
if (Result.isInvalid()) return ExprError();
Base = Result.get();
- #if 0
- if (Base->getType()->isDependentType() || Name.isDependentName() ||
- isDependentScopeSpecifier(SS)) {
- return ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS,
- TemplateKWLoc, FirstQualifierInScope,
- NameInfo, TemplateArgs);
- }
- #endif
-
ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl};
ExprResult Res = BuildMemberReferenceExpr(
Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc,
diff --git a/clang/test/SemaTemplate/dependent-names.cpp b/clang/test/SemaTemplate/dependent-names.cpp
index a661f14af80d34..641ec950054f57 100644
--- a/clang/test/SemaTemplate/dependent-names.cpp
+++ b/clang/test/SemaTemplate/dependent-names.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
typedef double A;
template<typename T> class B {
@@ -334,7 +334,7 @@ int arr[sizeof(Sub)];
namespace PR11421 {
template < unsigned > struct X {
static const unsigned dimension = 3;
- template<unsigned dim=dimension>
+ template<unsigned dim=dimension>
struct Y: Y<dim> { }; // expected-error{{circular inheritance between 'Y<dim>' and 'Y<dim>'}}
};
typedef X<3> X3;
>From c2a00b519f365ac8aef1f064e0042e38c3cf2cd1 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 5 Mar 2024 13:03:00 -0500
Subject: [PATCH 07/18] [FOLD] format
---
clang/lib/Sema/SemaExpr.cpp | 7 +--
clang/lib/Sema/SemaExprMember.cpp | 59 ++++++++-----------
clang/lib/Sema/SemaOverload.cpp | 6 +-
clang/lib/Sema/TreeTransform.h | 14 ++---
.../ASTMatchers/ASTMatchersNarrowingTest.cpp | 5 +-
5 files changed, 41 insertions(+), 50 deletions(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 3ba88f9b4473da..910defe6fff30f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -667,10 +667,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
// expressions of certain types in C++.
if (getLangOpts().CPlusPlus &&
(E->getType() == Context.OverloadTy ||
- // 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()))
+ // 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
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index eb87e0edda0128..da32ea251aeee1 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -670,8 +670,7 @@ class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback {
}
static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
- Expr *BaseExpr,
- QualType RTy,
+ Expr *BaseExpr, QualType RTy,
SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS, bool HasTemplateArgs,
SourceLocation TemplateKWLoc,
@@ -695,9 +694,8 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange();
if (!RTy->isDependentType() &&
!SemaRef.isThisOutsideMemberFunctionBody(RTy) &&
- SemaRef.RequireCompleteType(OpLoc, RTy,
- diag::err_typecheck_incomplete_tag,
- BaseRange))
+ SemaRef.RequireCompleteType(
+ OpLoc, RTy, diag::err_typecheck_incomplete_tag, BaseRange))
return true;
if (HasTemplateArgs || TemplateKWLoc.isValid()) {
@@ -792,16 +790,12 @@ 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) {
+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);
// Implicit member accesses.
@@ -809,9 +803,9 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
TypoExpr *TE = nullptr;
QualType RecordTy = BaseType;
if (IsArrow) RecordTy = RecordTy->castAs<PointerType>()->getPointeeType();
- if (LookupMemberExprInRecord(
- *this, R, nullptr, RecordTy, 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;
@@ -1006,9 +1000,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
if (R.wasNotFoundInCurrentInstantiation() ||
(SS.isValid() && !computeDeclContext(SS, false))) {
- return ActOnDependentMemberExpr(BaseExpr, BaseExprType,
- IsArrow, OpLoc,
- SS, TemplateKWLoc, FirstQualifierInScope,
+ return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
+ TemplateKWLoc, FirstQualifierInScope,
R.getLookupNameInfo(), TemplateArgs);
}
@@ -1048,9 +1041,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
if (R.empty()) {
// Rederive where we looked up.
- DeclContext *DC = (SS.isSet()
- ? computeDeclContext(SS, false)
- : BaseType->getAsRecordDecl());
+ DeclContext *DC = (SS.isSet() ? computeDeclContext(SS, false)
+ : BaseType->getAsRecordDecl());
if (ExtraArgs) {
ExprResult RetryExpr;
@@ -1077,7 +1069,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
}
}
- if(DC) {
+ if (DC) {
Diag(R.getNameLoc(), diag::err_no_member)
<< MemberName << DC
<< (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
@@ -1317,9 +1309,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
QualType BaseType = BaseExpr.get()->getType();
- #if 0
+#if 0
assert(!BaseType->isDependentType());
- #endif
+#endif
DeclarationName MemberName = R.getLookupName();
SourceLocation MemberLoc = R.getNameLoc();
@@ -1332,12 +1324,12 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
if (const PointerType *Ptr = BaseType->getAs<PointerType>())
BaseType = Ptr->getPointeeType();
else if (!BaseType->isDependentType()) {
- if (const ObjCObjectPointerType *Ptr
- = BaseType->getAs<ObjCObjectPointerType>())
- BaseType = Ptr->getPointeeType();
+ 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;
+ // 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
@@ -1356,7 +1348,6 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
<< BaseType << BaseExpr.get()->getSourceRange();
return ExprError();
}
-
}
}
@@ -1378,8 +1369,8 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
// Handle field access to simple records.
if (BaseType->getAsRecordDecl() || BaseType->isDependentType()) {
TypoExpr *TE = nullptr;
- if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, 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
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index be667c0c961f32..4a2df219b5ea11 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -5803,10 +5803,10 @@ static ImplicitConversionSequence TryObjectArgumentInitialization(
return ICS;
}
- // FIXME: Should this check getAsRecordDecl instead?
- #if 0
+// FIXME: Should this check getAsRecordDecl instead?
+#if 0
assert(FromType->isRecordType());
- #endif
+#endif
QualType ClassType = S.Context.getTypeDeclType(ActingContext);
// C++98 [class.dtor]p2:
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index b494179a70d46c..53dc0a1ca5c875 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -12993,14 +12993,14 @@ bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old,
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)
+ 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 true;
}
}
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 739f495510dee5..c08deb903f129b 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1569,8 +1569,9 @@ TEST_P(ASTMatchersTest, IsArrow_MatchesMemberVariablesViaArrow) {
matches("class Y { void x() { y; } int y; };", memberExpr(isArrow())));
EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } int y; };",
memberExpr(isArrow())));
- EXPECT_TRUE(matches("template <class T> class Y { void x() { this->m; } int m; };",
- memberExpr(isArrow())));
+ EXPECT_TRUE(
+ matches("template <class T> class Y { void x() { this->m; } int m; };",
+ memberExpr(isArrow())));
EXPECT_TRUE(
notMatches("template <class T> class Y { void x() { (*this).m; } };",
cxxDependentScopeMemberExpr(isArrow())));
>From b4ac4df1ccb6a8437d0a92933a978d540e31e763 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 7 Mar 2024 12:43:15 -0500
Subject: [PATCH 08/18] [FOLD] more tests
---
.../temp.res/temp.dep/temp.dep.type/p4.cpp | 383 +++++++++++++++---
1 file changed, 323 insertions(+), 60 deletions(-)
diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
index 7b36e3ad3b0131..2649addf1175ac 100644
--- a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
+++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
@@ -1,71 +1,334 @@
// RUN: %clang_cc1 -Wno-unused-value -verify %s
namespace N0 {
- template<typename T>
struct A {
- int x;
- void f();
- using X = int;
-
- void not_instantiated(A *a, A &b) {
- x;
- f();
- new X;
-
- this->x;
- this->f();
- this->A::x;
- this->A::f();
-
- a->x;
- a->f();
- a->A::x;
- a->A::f();
-
- (*this).x;
- (*this).f();
- (*this).A::x;
- (*this).A::f();
-
- b.x;
- b.f();
- b.A::x;
- b.A::f();
-
- A::x;
- A::f();
- new A::X;
-
- y; // expected-error{{use of undeclared identifier 'y'}}
- g(); // expected-error{{use of undeclared identifier 'g'}}
- new Y; // expected-error{{unknown type name 'Y'}}
-
- this->y; // expected-error{{no member named 'y' in 'A<T>'}}
- this->g(); // expected-error{{no member named 'g' in 'A<T>'}}
- this->A::y; // expected-error{{no member named 'y' in 'A<T>'}}
- this->A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
-
- a->y; // expected-error{{no member named 'y' in 'A<T>'}}
- a->g(); // expected-error{{no member named 'g' in 'A<T>'}}
- a->A::y; // expected-error{{no member named 'y' in 'A<T>'}}
- a->A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
+ int x0;
+ static int x1;
+ int x2;
+ static int x3;
+
+ void f0();
+ static void f1();
+ void f2();
+ static void f3();
+
+ using M0 = int;
+ using M1 = int;
+
+ struct C0 { };
+ struct C1 { };
+ };
+
+ template<typename T>
+ struct B : A {
+ int x4;
+ static int x5;
+
+ using A::x2;
+ using A::x3;
+
+ void f4();
+ static void f5();
+
+ using A::f2;
+ using A::f3;
+
+ using M2 = int;
+
+ using A::M1;
+
+ struct C2 { };
+
+ using A::C1;
+
+ void not_instantiated(B *a, B &b) {
+ // All of the following should be found in the current instantiation.
+
+ new M0;
+ new B::M0;
+ new A::M0;
+ new B::A::M0;
+ new C0;
+ new B::C0;
+ new A::C0;
+ new B::A::C0;
+ new M1;
+ new B::M1;
+ new A::M1;
+ new B::A::M1;
+ new C1;
+ new B::C1;
+ new A::C1;
+ new B::A::C1;
+ new M2;
+ new B::M2;
+ new C2;
+ new B::C2;
+
+ x0;
+ B::x0;
+ A::x0;
+ B::A::x0;
+ x1;
+ B::x1;
+ A::x1;
+ B::A::x1;
+ x2;
+ B::x2;
+ A::x2;
+ B::A::x2;
+ x3;
+ B::x3;
+ A::x3;
+ B::A::x3;
+ x4;
+ B::x4;
+ x5;
+ B::x5;
+
+ f0();
+ B::f0();
+ A::f0();
+ B::A::f0();
+ f1();
+ B::f1();
+ A::f1();
+ B::A::f1();
+ f2();
+ B::f2();
+ A::f2();
+ B::A::f2();
+ f3();
+ B::f3();
+ A::f3();
+ B::A::f3();
+ f4();
+ B::f4();
+ f5();
+ B::f5();
+
+ this->x0;
+ this->B::x0;
+ this->A::x0;
+ this->B::A::x0;
+ this->x1;
+ this->B::x1;
+ this->A::x1;
+ this->B::A::x1;
+ this->x2;
+ this->B::x2;
+ this->A::x2;
+ this->B::A::x2;
+ this->x3;
+ this->B::x3;
+ this->A::x3;
+ this->B::A::x3;
+ this->x4;
+ this->B::x4;
+ this->x5;
+ this->B::x5;
+
+ this->f0();
+ this->B::f0();
+ this->A::f0();
+ this->B::A::f0();
+ this->f1();
+ this->B::f1();
+ this->A::f1();
+ this->B::A::f1();
+ this->f2();
+ this->B::f2();
+ this->A::f2();
+ this->B::A::f2();
+ this->f3();
+ this->B::f3();
+ this->A::f3();
+ this->B::A::f3();
+ this->f4();
+ this->B::f4();
+ this->f5();
+ this->B::f5();
+
+ a->x0;
+ a->B::x0;
+ a->A::x0;
+ a->B::A::x0;
+ a->x1;
+ a->B::x1;
+ a->A::x1;
+ a->B::A::x1;
+ a->x2;
+ a->B::x2;
+ a->A::x2;
+ a->B::A::x2;
+ a->x3;
+ a->B::x3;
+ a->A::x3;
+ a->B::A::x3;
+ a->x4;
+ a->B::x4;
+ a->x5;
+ a->B::x5;
+
+ a->f0();
+ a->B::f0();
+ a->A::f0();
+ a->B::A::f0();
+ a->f1();
+ a->B::f1();
+ a->A::f1();
+ a->B::A::f1();
+ a->f2();
+ a->B::f2();
+ a->A::f2();
+ a->B::A::f2();
+ a->f3();
+ a->B::f3();
+ a->A::f3();
+ a->B::A::f3();
+ a->f4();
+ a->B::f4();
+ a->f5();
+ a->B::f5();
+
+ (*this).x0;
+ (*this).B::x0;
+ (*this).A::x0;
+ (*this).B::A::x0;
+ (*this).x1;
+ (*this).B::x1;
+ (*this).A::x1;
+ (*this).B::A::x1;
+ (*this).x2;
+ (*this).B::x2;
+ (*this).A::x2;
+ (*this).B::A::x2;
+ (*this).x3;
+ (*this).B::x3;
+ (*this).A::x3;
+ (*this).B::A::x3;
+ (*this).x4;
+ (*this).B::x4;
+ (*this).x5;
+ (*this).B::x5;
+
+ (*this).f0();
+ (*this).B::f0();
+ (*this).A::f0();
+ (*this).B::A::f0();
+ (*this).f1();
+ (*this).B::f1();
+ (*this).A::f1();
+ (*this).B::A::f1();
+ (*this).f2();
+ (*this).B::f2();
+ (*this).A::f2();
+ (*this).B::A::f2();
+ (*this).f3();
+ (*this).B::f3();
+ (*this).A::f3();
+ (*this).B::A::f3();
+ (*this).f4();
+ (*this).B::f4();
+ (*this).f5();
+ (*this).B::f5();
+
+ b.x0;
+ b.B::x0;
+ b.A::x0;
+ b.B::A::x0;
+ b.x1;
+ b.B::x1;
+ b.A::x1;
+ b.B::A::x1;
+ b.x2;
+ b.B::x2;
+ b.A::x2;
+ b.B::A::x2;
+ b.x3;
+ b.B::x3;
+ b.A::x3;
+ b.B::A::x3;
+ b.x4;
+ b.B::x4;
+ b.x5;
+ b.B::x5;
+
+ b.f0();
+ b.B::f0();
+ b.A::f0();
+ b.B::A::f0();
+ b.f1();
+ b.B::f1();
+ b.A::f1();
+ b.B::A::f1();
+ b.f2();
+ b.B::f2();
+ b.A::f2();
+ b.B::A::f2();
+ b.f3();
+ b.B::f3();
+ b.A::f3();
+ b.B::A::f3();
+ b.f4();
+ b.B::f4();
+ b.f5();
+ b.B::f5();
+
+ // None of the following should be found in the current instantiation.
+
+ new M3; // expected-error{{unknown type name 'M3'}}
+ new B::M3; // expected-error{{no type named 'M3' in 'B<T>'}}
+ new A::M3; // expected-error{{no type named 'M3' in 'N0::A'}}
+ new B::A::M3; // expected-error{{no type named 'M3' in 'N0::A'}}
+
+ x6; // expected-error{{use of undeclared identifier 'x6'}}
+ B::x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+ A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+ B::A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+ f6(); // expected-error{{use of undeclared identifier 'f6'}}
+ B::f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+ A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
+ B::A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
+
+ this->x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+ this->B::x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+ this->A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+ this->B::A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+ this->f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+ this->B::f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+ this->A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
+ this->B::A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
+
+ a->x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+ a->B::x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+ a->A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+ a->B::A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+ a->f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+ a->B::f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+ a->A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
+ a->B::A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
// FIXME: An overloaded unary 'operator*' is built for these
// even though the operand is a pointer (to a dependent type).
// Type::isOverloadableType should return false for such cases.
- (*this).y;
- (*this).g();
- (*this).A::y;
- (*this).A::g();
-
- b.y; // expected-error{{no member named 'y' in 'A<T>'}}
- b.g(); // expected-error{{no member named 'g' in 'A<T>'}}
- b.A::y; // expected-error{{no member named 'y' in 'A<T>'}}
- b.A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
-
- A::y; // expected-error{{no member named 'y' in 'A<T>'}}
- A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
- new A::Y; // expected-error{{no type named 'Y' in 'A<T>'}}
+ (*this).x6;
+ (*this).B::x6;
+ (*this).A::x6;
+ (*this).B::A::x6;
+ (*this).f6();
+ (*this).B::f6();
+ (*this).A::f6();
+ (*this).B::A::f6();
+
+ b.x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+ b.B::x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+ b.A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+ b.B::A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+ b.f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+ b.B::f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+ b.A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
+ b.B::A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
}
};
} // namespace N0
>From cc604a94eb0936c54626924a584327335ee1b4aa Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 7 Mar 2024 14:21:10 -0500
Subject: [PATCH 09/18] [FOLD] LookupParsedName takes ObjectType
---
clang/include/clang/Sema/Sema.h | 5 +-
clang/lib/Parse/ParseDecl.cpp | 2 +-
clang/lib/Sema/HLSLExternalSemaSource.cpp | 4 +-
clang/lib/Sema/SemaAttr.cpp | 5 +-
clang/lib/Sema/SemaDecl.cpp | 6 +--
clang/lib/Sema/SemaDeclCXX.cpp | 6 +--
clang/lib/Sema/SemaExpr.cpp | 5 +-
clang/lib/Sema/SemaExprCXX.cpp | 2 +-
clang/lib/Sema/SemaExprMember.cpp | 24 +++++++--
clang/lib/Sema/SemaLookup.cpp | 62 +++++++++++++++--------
clang/lib/Sema/SemaOpenMP.cpp | 14 +++--
clang/lib/Sema/SemaTemplate.cpp | 4 +-
12 files changed, 93 insertions(+), 46 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 8c98d8c7fef7a7..14ac5e568ec163 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7739,7 +7739,10 @@ class Sema final {
bool InUnqualifiedLookup = false);
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
CXXScopeSpec &SS);
- bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
+ bool LookupParsedName(LookupResult &R,
+ Scope *S,
+ CXXScopeSpec *SS,
+ QualType ObjectType,
bool AllowBuiltinCreation = false,
bool EnteringContext = false);
ObjCProtocolDecl *
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 0aa14b0510746b..ed3acbe984a2fd 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2998,7 +2998,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
<< TokenName << TagName << getLangOpts().CPlusPlus
<< FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName);
- if (Actions.LookupParsedName(R, getCurScope(), SS)) {
+ if (Actions.LookupParsedName(R, getCurScope(), SS, /*ObjectType=*/QualType())) {
for (LookupResult::iterator I = R.begin(), IEnd = R.end();
I != IEnd; ++I)
Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 1a1febf7a35241..f6a93c378acf4b 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -131,7 +131,9 @@ struct BuiltinTypeDeclBuilder {
DeclarationNameInfo NameInfo =
DeclarationNameInfo(DeclarationName(&II), SourceLocation());
LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
- S.LookupParsedName(R, S.getCurScope(), &SS, false);
+ S.LookupParsedName(R, S.getCurScope(), &SS,
+ /*ObjectType=*/QualType(),
+ /*AllowBuiltinCreation*/false);
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 a5dd158808f26b..adbcf8eba9d114 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -837,7 +837,10 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
IdentifierInfo *Name = IdTok.getIdentifierInfo();
LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName);
- LookupParsedName(Lookup, curScope, nullptr, true);
+ LookupParsedName(Lookup, curScope,
+ /*SS=*/nullptr,
+ /*ObjectType=*/QualType(),
+ /*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 5c1152896559b5..575d345f268515 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -828,7 +828,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()) {
@@ -865,7 +865,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;
}
@@ -892,7 +892,7 @@ 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 f32ff396f8a543..e4199edf20a6bd 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4514,7 +4514,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) {
@@ -12225,7 +12225,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;
@@ -13684,7 +13684,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 910defe6fff30f..895d0e02940a3b 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2770,7 +2770,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// results until we get here but it's likely not worth it.
bool MemberOfUnknownSpecialization;
AssumedTemplateKind AssumedTemplate;
- if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
+ if (LookupTemplateName(R, S, SS, /*ObjectType=*/QualType(),
+ /*EnteringContext=*/false,
MemberOfUnknownSpecialization, TemplateKWLoc,
&AssumedTemplate))
return ExprError();
@@ -2781,7 +2782,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
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 76bb78aa8b5458..5023276b66379d 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -9081,7 +9081,7 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
// Do the redeclaration lookup in the current scope.
LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName,
Sema::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 da32ea251aeee1..bb58bf6c7ca55f 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -675,6 +675,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
CXXScopeSpec &SS, bool HasTemplateArgs,
SourceLocation TemplateKWLoc,
TypoExpr *&TE) {
+ #if 1
DeclContext *DC = SemaRef.computeDeclContext(RTy);
// If the object expression is dependent and isn't the current instantiation,
// lookup will not find anything and we must defer until instantiation.
@@ -682,6 +683,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
R.setNotFoundInCurrentInstantiation();
return false;
}
+ #endif
// FIXME: Should this use Name.isDependentName()?
if (DeclarationName Name = R.getLookupName();
@@ -698,15 +700,21 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
OpLoc, RTy, diag::err_typecheck_incomplete_tag, BaseRange))
return true;
+ // LookupTemplateName/LookupParsedName don't expect these both to exist simultaneously.
+ QualType ObjectType = SS.isSet() ? QualType() : RTy;
if (HasTemplateArgs || TemplateKWLoc.isValid()) {
- // LookupTemplateName doesn't expect these both to exist simultaneously.
- QualType ObjectType = SS.isSet() ? QualType() : RTy;
-
bool MOUS;
- return SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS,
+ return SemaRef.LookupTemplateName(R,
+ /*S=*/nullptr,
+ SS,
+ ObjectType,
+ /*EnteringContext=*/false,
+ MOUS,
TemplateKWLoc);
}
-
+ #if 0
+ SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
+ #else
if (SS.isSet()) {
// If the member name was a qualified-id, look into the
// nested-name-specifier.
@@ -735,12 +743,18 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
// The record definition is complete, now look up the member.
SemaRef.LookupQualifiedName(R, DC, SS);
+ #endif
if (!R.empty() || R.wasNotFoundInCurrentInstantiation())
return false;
DeclarationName Typo = R.getLookupName();
SourceLocation TypoLoc = R.getNameLoc();
+ #if 0
+ DeclContext *DC = SS.isSet()
+ ? SemaRef.computeDeclContext(SS)
+ : SemaRef.computeDeclContext(RTy);
+ #endif
struct QueryState {
Sema &SemaRef;
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 38237ee578079d..1c024261dbdf7a 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2716,39 +2716,57 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
/// context of the scope-specifier SS (if present).
///
/// @returns True if any decls were found (but possibly ambiguous)
-bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
- bool AllowBuiltinCreation, bool EnteringContext) {
+bool Sema::LookupParsedName(LookupResult &R,
+ Scope *S,
+ CXXScopeSpec *SS,
+ QualType ObjectType,
+ bool AllowBuiltinCreation,
+ bool EnteringContext) {
if (SS && SS->isInvalid()) {
// When the scope specifier is invalid, don't even look for
// anything.
return false;
}
- if (SS && SS->isSet()) {
- NestedNameSpecifier *NNS = SS->getScopeRep();
- if (NNS->getKind() == NestedNameSpecifier::Super)
+ // Determine where to perform name lookup
+ DeclContext *DC = nullptr;
+ 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);
+ 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);
}
-
- // 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;
+ } else {
+ // Perform unqualified name lookup starting in the given scope.
+ return LookupName(R, S, AllowBuiltinCreation);
}
- // 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);
+
+ // 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();
+ return false;
}
/// Perform qualified name lookup into all base classes of the given
@@ -5015,7 +5033,9 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
return;
}
- SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false,
+ SemaRef.LookupParsedName(Res, S, SS,
+ /*ObjectType=*/QualType(),
+ /*AllowBuiltinCreation=*/false,
EnteringContext);
// Fake ivar lookup; this should really be part of
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 0ba54a3a9cae35..1e9cea600f1551 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3052,7 +3052,9 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
const DeclarationNameInfo &Id,
OpenMPDirectiveKind Kind) {
LookupResult Lookup(*this, Id, LookupOrdinaryName);
- LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
+ LookupParsedName(Lookup, CurScope, &ScopeSpec,
+ /*ObjectType=*/QualType(),
+ /*AllowBuiltinCreation=*/true);
if (Lookup.isAmbiguous())
return ExprError();
@@ -7303,7 +7305,7 @@ void Sema::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(
IdentifierInfo *BaseII = D.getIdentifier();
LookupResult Lookup(*this, DeclarationName(BaseII), D.getIdentifierLoc(),
LookupOrdinaryName);
- LookupParsedName(Lookup, S, &D.getCXXScopeSpec());
+ LookupParsedName(Lookup, S, &D.getCXXScopeSpec(), /*ObjectType=*/QualType());
TypeSourceInfo *TInfo = GetTypeForDeclarator(D);
QualType FType = TInfo->getType();
@@ -19157,7 +19159,7 @@ 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();
@@ -22010,7 +22012,7 @@ 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();
@@ -23317,7 +23319,9 @@ NamedDecl *Sema::lookupOpenMPDeclareTargetName(Scope *CurScope,
CXXScopeSpec &ScopeSpec,
const DeclarationNameInfo &Id) {
LookupResult Lookup(*this, Id, LookupOrdinaryName);
- LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
+ 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 d3def13f495d2b..e022586c2a17be 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5696,7 +5696,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() ==
@@ -11058,7 +11058,7 @@ 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:
>From 7329eb3ee8a70a228bfbabc9eeff23d6012e1da2 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 8 Mar 2024 10:09:40 -0500
Subject: [PATCH 10/18] [FOLD] use LookupParsedName for class member access
---
clang/lib/Sema/SemaExprMember.cpp | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index bb58bf6c7ca55f..2af37e8b635241 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -675,7 +675,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
CXXScopeSpec &SS, bool HasTemplateArgs,
SourceLocation TemplateKWLoc,
TypoExpr *&TE) {
- #if 1
+ #if 0
DeclContext *DC = SemaRef.computeDeclContext(RTy);
// If the object expression is dependent and isn't the current instantiation,
// lookup will not find anything and we must defer until instantiation.
@@ -704,15 +704,18 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
QualType ObjectType = SS.isSet() ? QualType() : RTy;
if (HasTemplateArgs || TemplateKWLoc.isValid()) {
bool MOUS;
- return SemaRef.LookupTemplateName(R,
+ bool Invalid = SemaRef.LookupTemplateName(R,
/*S=*/nullptr,
SS,
ObjectType,
/*EnteringContext=*/false,
MOUS,
TemplateKWLoc);
+ if (MOUS)
+ R.setNotFoundInCurrentInstantiation();
+ return Invalid;
}
- #if 0
+ #if 1
SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
#else
if (SS.isSet()) {
@@ -750,7 +753,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
DeclarationName Typo = R.getLookupName();
SourceLocation TypoLoc = R.getNameLoc();
- #if 0
+ #if 1
DeclContext *DC = SS.isSet()
? SemaRef.computeDeclContext(SS)
: SemaRef.computeDeclContext(RTy);
>From 2d8a13783bb4f480809aa8fb0058331343235a15 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 8 Mar 2024 11:45:40 -0500
Subject: [PATCH 11/18] [FOLD] update tests
---
clang/test/CXX/drs/dr2xx.cpp | 12 ++++++------
clang/test/CXX/drs/dr3xx.cpp | 26 +++++++++++++-------------
clang/test/SemaCXX/member-expr.cpp | 4 ++--
3 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/clang/test/CXX/drs/dr2xx.cpp b/clang/test/CXX/drs/dr2xx.cpp
index cbb8734e10c649..e321dbfe95d4ff 100644
--- a/clang/test/CXX/drs/dr2xx.cpp
+++ b/clang/test/CXX/drs/dr2xx.cpp
@@ -556,9 +556,9 @@ namespace dr244 { // dr244: 11
B_ptr->B_alias::~B();
B_ptr->B_alias::~B_alias();
B_ptr->dr244::~B();
- // expected-error at -1 {{qualified member access refers to a member in namespace 'dr244'}}
+ // expected-error at -1 {{no member named '~B' in namespace 'dr244'}}
B_ptr->dr244::~B_alias();
- // expected-error at -1 {{qualified member access refers to a member in namespace 'dr244'}}
+ // expected-error at -1 {{no member named '~B' in namespace 'dr244'}}
}
template<typename T, typename U>
@@ -724,7 +724,7 @@ namespace dr252 { // dr252: 3.1
struct E {
void operator delete(void*, int);
void operator delete(void*) = delete; // #dr252-E
- // cxx98-error at -1 {{deleted function definitions are a C++11 extension}}
+ // cxx98-error at -1 {{deleted function definitions are a C++11 extension}}
virtual ~E();
};
E::~E() {}
@@ -831,7 +831,7 @@ namespace dr258 { // dr258: 2.8
namespace dr259 { // dr259: 4
template<typename T> struct A {};
- template struct A<int>; // #dr259-A-int
+ template struct A<int>; // #dr259-A-int
template struct A<int>;
// expected-error at -1 {{duplicate explicit instantiation of 'A<int>'}}
// expected-note@#dr259-A-int {{previous explicit instantiation is here}}
@@ -992,7 +992,7 @@ namespace dr275 { // dr275: no
// expected-error at -1 {{no function template matches function template specialization 'f'}}
}
- template <class T> void g(T) {} // #dr275-g
+ template <class T> void g(T) {} // #dr275-g
template <> void N::f(char) {}
template <> void f(int) {}
@@ -1159,7 +1159,7 @@ namespace dr285 { // dr285: yes
namespace dr286 { // dr286: 2.8
template<class T> struct A {
class C {
- template<class T2> struct B {}; // #dr286-B
+ template<class T2> struct B {}; // #dr286-B
};
};
diff --git a/clang/test/CXX/drs/dr3xx.cpp b/clang/test/CXX/drs/dr3xx.cpp
index 4584801f9f9714..fde4e186e6c033 100644
--- a/clang/test/CXX/drs/dr3xx.cpp
+++ b/clang/test/CXX/drs/dr3xx.cpp
@@ -23,7 +23,7 @@ namespace dr301 { // dr301: 3.5
bool b = (void(*)(S, S))operator- < (void(*)(S, S))operator-;
// cxx98-17-warning at -1 {{ordered comparison of function pointers ('void (*)(S, S)' and 'void (*)(S, S)')}}
// cxx20-23-error at -2 {{expected '>'}}
- // cxx20-23-note at -3 {{to match this '<'}}
+ // cxx20-23-note at -3 {{to match this '<'}}
bool c = (void(*)(S, S))operator+ < (void(*)(S, S))operator-;
// expected-error at -1 {{expected '>'}}
// expected-note at -2 {{to match this '<'}}
@@ -432,7 +432,7 @@ namespace dr329 { // dr329: 3.5
// expected-note@#dr329-b {{in instantiation of template class 'dr329::A<char>' requested here}}
// expected-note@#dr329-i {{previous definition is here}}
};
- A<int> a;
+ A<int> a;
A<char> b; // #dr329-b
void test() {
@@ -631,7 +631,7 @@ namespace dr339 { // dr339: 2.8
char xxx(int);
char (&xxx(float))[2];
- template<class T> A<sizeof(xxx((T)0))> f(T) {} // #dr339-f
+ template<class T> A<sizeof(xxx((T)0))> f(T) {} // #dr339-f
void test() {
A<1> a = f(0);
@@ -673,9 +673,9 @@ namespace dr341 { // dr341: sup 1708
namespace B {
extern "C" int &dr341_a = dr341_a;
// expected-error at -1 {{redefinition of 'dr341_a'}}
- // expected-note@#dr341_a {{previous definition is here}}
+ // expected-note@#dr341_a {{previous definition is here}}
}
- extern "C" void dr341_b(); // #dr341_b
+ extern "C" void dr341_b(); // #dr341_b
}
int dr341_a;
// expected-error at -1 {{declaration of 'dr341_a' in global scope conflicts with declaration with C language linkage}}
@@ -693,7 +693,7 @@ namespace dr341 {
// expected-error at -1 {{declaration of 'dr341_d' with C language linkage conflicts with declaration in global scope}}
// expected-note@#dr341_d {{declared in global scope here}}
- namespace A { extern "C" int dr341_e; } // #dr341_e
+ namespace A { extern "C" int dr341_e; } // #dr341_e
namespace B { extern "C" void dr341_e(); }
// expected-error at -1 {{redefinition of 'dr341_e' as different kind of symbol}}
// expected-note@#dr341_e {{previous definition is here}}
@@ -817,7 +817,7 @@ namespace dr352 { // dr352: 2.8
void g(A::E e) {
foo(e, &arg);
// expected-error at -1 {{no matching function for call to 'foo'}}
- // expected-note@#dr352-foo {{candidate template ignored: couldn't infer template argument 'R'}}
+ // expected-note@#dr352-foo {{candidate template ignored: couldn't infer template argument 'R'}}
using A::foo;
foo<int, int>(e, &arg); // ok, uses non-template
@@ -918,7 +918,7 @@ namespace dr352 { // dr352: 2.8
namespace example5 {
template<int I> class A {};
- template<int I> void g(A<I+1>); // #dr352-g
+ template<int I> void g(A<I+1>); // #dr352-g
template<int I> void f(A<I>, A<I+1>);
void h(A<1> a1, A<2> a2) {
g(a1);
@@ -1095,7 +1095,7 @@ namespace dr364 { // dr364: yes
}
// dr366: yes
-#if "foo" // expected-error {{invalid token at start of a preprocessor expression}}
+#if "foo" // expected-error {{invalid token at start of a preprocessor expression}}
#endif
namespace dr367 { // dr367: yes
@@ -1252,7 +1252,7 @@ namespace dr373 { // dr373: 5
}
};
- struct A { struct B {}; }; // #dr373-A
+ struct A { struct B {}; }; // #dr373-A
namespace X = A::B;
// expected-error at -1 {{expected namespace name}}
// expected-note@#dr373-A {{'A' declared here}}
@@ -1585,7 +1585,7 @@ namespace dr395 { // dr395: 3.0
// expected-error at -2 {{conversion function cannot have any parameters}}
// expected-error at -3 {{cannot specify any part of a return type in the declaration of a conversion function}}
// expected-error at -4 {{conversion function cannot convert to a function type}}
-
+
};
struct null1_t {
@@ -1698,9 +1698,9 @@ namespace dr399 { // dr399: 11
B_ptr->B_alias::~B();
B_ptr->B_alias::~B_alias();
B_ptr->dr399::~B();
- // expected-error at -1 {{qualified member access refers to a member in namespace 'dr399'}}
+ // expected-error at -1 {{no member named '~B' in namespace 'dr399'}}
B_ptr->dr399::~B_alias();
- // expected-error at -1 {{qualified member access refers to a member in namespace 'dr399'}}
+ // expected-error at -1 {{no member named '~B' in namespace 'dr399'}}
}
template<typename T, typename U>
diff --git a/clang/test/SemaCXX/member-expr.cpp b/clang/test/SemaCXX/member-expr.cpp
index 75c9ef0caa2e00..0596e40f6c2f6a 100644
--- a/clang/test/SemaCXX/member-expr.cpp
+++ b/clang/test/SemaCXX/member-expr.cpp
@@ -40,8 +40,8 @@ namespace C {
}
void test2(X *xp) {
- xp->::i = 7; // expected-error{{qualified member access refers to a member in the global namespace}}
- xp->C::i = 7; // expected-error{{qualified member access refers to a member in namespace 'C'}}
+ xp->::i = 7; // expected-error{{'i' is not a member of class 'X'}}
+ xp->C::i = 7; // expected-error{{'C::i' is not a member of class 'X'}}
}
>From aa41e28788700766ce251ada559ac45770de1204 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 8 Mar 2024 11:47:20 -0500
Subject: [PATCH 12/18] [FOLD] discard invalid nested-name-specifiers
---
clang/include/clang/Sema/Lookup.h | 2 +-
clang/lib/Sema/SemaExprMember.cpp | 23 ++++++++++++++++++++---
2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h
index 2f2f2607a937fe..16c23dd903e86a 100644
--- a/clang/include/clang/Sema/Lookup.h
+++ b/clang/include/clang/Sema/Lookup.h
@@ -496,7 +496,7 @@ class LookupResult {
/// Note that while no result was found in the current instantiation,
/// there were dependent base classes that could not be searched.
void setNotFoundInCurrentInstantiation() {
- assert(ResultKind == NotFound && Decls.empty());
+ assert((ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation) && Decls.empty());
ResultKind = NotFoundInCurrentInstantiation;
}
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 2af37e8b635241..086730bfec3b02 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -815,6 +815,9 @@ ExprResult Sema::BuildMemberReferenceExpr(
ActOnMemberAccessExtraArgs *ExtraArgs) {
LookupResult R(*this, NameInfo, LookupMemberName);
+ if (SS.isInvalid())
+ SS.clear();
+
// Implicit member accesses.
if (!Base) {
TypoExpr *TE = nullptr;
@@ -1014,7 +1017,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
const Scope *S,
bool SuppressQualifierCheck,
ActOnMemberAccessExtraArgs *ExtraArgs) {
-
+ assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid");
if (R.wasNotFoundInCurrentInstantiation() ||
(SS.isValid() && !computeDeclContext(SS, false))) {
return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
@@ -1059,7 +1062,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
if (R.empty()) {
// Rederive where we looked up.
DeclContext *DC = (SS.isSet() ? computeDeclContext(SS, false)
- : BaseType->getAsRecordDecl());
+ : computeDeclContext(BaseType));
+ // : BaseType->getAsRecordDecl());
if (ExtraArgs) {
ExprResult RetryExpr;
@@ -1086,7 +1090,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
}
}
- if (DC) {
+ if (SS.isInvalid() || (SS.isNotEmpty() && !DC)) {
+ Diag(R.getNameLoc(), diag::err_undeclared_use)
+ << MemberName << SS.getRange();
+ } else if (DC) {
Diag(R.getNameLoc(), diag::err_no_member)
<< MemberName << DC
<< (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
@@ -1096,6 +1103,16 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
<< MemberName << BaseExprType
<< (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
}
+
+ if (DC) {
+ } else {
+ #if 0
+ // FIXME: Is this needed?
+ Diag(R.getNameLoc(), diag::err_no_member)
+ << MemberName << BaseExprType
+ << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
+ #endif
+ }
return ExprError();
}
>From fdc7dee9a9088b02e816d3ab872151d9fbdd801a Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 8 Mar 2024 13:58:04 -0500
Subject: [PATCH 13/18] [FOLD]
---
clang/include/clang/Sema/Sema.h | 6 ++++++
clang/lib/Sema/SemaLookup.cpp | 19 ++++++++++---------
clang/lib/Sema/SemaTemplate.cpp | 26 +++++++++++++++++---------
3 files changed, 33 insertions(+), 18 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 14ac5e568ec163..77203ffcbd0b30 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -9152,6 +9152,12 @@ class Sema final {
bool EnteringContext, bool &MemberOfUnknownSpecialization,
RequiredTemplateKind RequiredTemplate = SourceLocation(),
AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);
+
+ bool LookupTemplateName(
+ LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType,
+ bool EnteringContext,
+ RequiredTemplateKind RequiredTemplate = SourceLocation(),
+ AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);
TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS,
bool hasTemplateKeyword,
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 1c024261dbdf7a..f9ea644d9344ed 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2722,19 +2722,19 @@ bool Sema::LookupParsedName(LookupResult &R,
QualType ObjectType,
bool AllowBuiltinCreation,
bool EnteringContext) {
- if (SS && SS->isInvalid()) {
- // When the scope specifier is invalid, don't even look for
- // anything.
+ // When the scope specifier is invalid, don't even look for anything.
+ if (SS && SS->isInvalid())
return false;
- }
// 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>() ||
@@ -2752,6 +2752,7 @@ bool Sema::LookupParsedName(LookupResult &R,
return false;
R.setContextRange(SS->getRange());
}
+ IsDependent = !DC && isDependentScopeSpecifier(*SS);
} else {
// Perform unqualified name lookup starting in the given scope.
return LookupName(R, S, AllowBuiltinCreation);
@@ -2761,11 +2762,11 @@ bool Sema::LookupParsedName(LookupResult &R,
// lookup in that context.
if (DC)
return LookupQualifiedName(R, DC);
-
- // 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();
+ 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();
return false;
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index e022586c2a17be..ddd7d66b1bc81a 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -319,15 +319,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;
@@ -373,6 +370,19 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
return true;
}
+bool Sema::LookupTemplateName(LookupResult &Found,
+ Scope *S, CXXScopeSpec &SS,
+ QualType ObjectType,
+ bool EnteringContext,
+ RequiredTemplateKind RequiredTemplate,
+ AssumedTemplateKind *ATK,
+ bool AllowTypoCorrection) {
+ bool MemberOfUnknownSpecialization;
+ return LookupTemplateName(Found, S, SS, ObjectType, EnteringContext,
+ MemberOfUnknownSpecialization, RequiredTemplate,
+ ATK, AllowTypoCorrection);
+}
+
bool Sema::LookupTemplateName(LookupResult &Found,
Scope *S, CXXScopeSpec &SS,
QualType ObjectType,
@@ -5475,10 +5485,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,
+ /*Entering*/false,
TemplateKWLoc))
return ExprError();
@@ -5600,14 +5609,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)
>From f4280124fed18abf7f02fcb6847afc38dfeca937 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 11 Mar 2024 07:20:00 -0400
Subject: [PATCH 14/18] [FOLD]
---
clang/lib/Sema/SemaExpr.cpp | 3 +--
clang/lib/Sema/SemaExprMember.cpp | 5 +----
clang/lib/Sema/SemaTemplate.cpp | 2 ++
3 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 895d0e02940a3b..9a70406687cb60 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2776,8 +2776,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
&AssumedTemplate))
return ExprError();
- if (MemberOfUnknownSpecialization ||
- (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation))
+ if (R.wasNotFoundInCurrentInstantiation())
return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
IsAddressOfOperand, TemplateArgs);
} else {
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 086730bfec3b02..260a6a203334fd 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -704,16 +704,13 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
QualType ObjectType = SS.isSet() ? QualType() : RTy;
if (HasTemplateArgs || TemplateKWLoc.isValid()) {
bool MOUS;
- bool Invalid = SemaRef.LookupTemplateName(R,
+ return SemaRef.LookupTemplateName(R,
/*S=*/nullptr,
SS,
ObjectType,
/*EnteringContext=*/false,
MOUS,
TemplateKWLoc);
- if (MOUS)
- R.setNotFoundInCurrentInstantiation();
- return Invalid;
}
#if 1
SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index ddd7d66b1bc81a..b0773b528f9592 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -213,6 +213,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
&AssumedTemplate,
/*AllowTypoCorrection=*/!Disambiguation))
return TNK_Non_template;
+ MemberOfUnknownSpecialization = R.wasNotFoundInCurrentInstantiation();
if (AssumedTemplate != AssumedTemplateKind::None) {
TemplateResult = TemplateTy::make(Context.getAssumedTemplateName(TName));
@@ -558,6 +559,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
if (Found.empty()) {
if (IsDependent) {
MemberOfUnknownSpecialization = true;
+ Found.setNotFoundInCurrentInstantiation();
return false;
}
>From be7f3f0865d7eb1431e382d96871b7a41d3d8f18 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 19 Mar 2024 08:03:18 -0400
Subject: [PATCH 15/18] [FOLD] cleanup
---
clang/lib/Sema/SemaExprMember.cpp | 63 ++++---------------------------
1 file changed, 7 insertions(+), 56 deletions(-)
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 260a6a203334fd..89bb77ba4ac751 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -675,16 +675,6 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
CXXScopeSpec &SS, bool HasTemplateArgs,
SourceLocation TemplateKWLoc,
TypoExpr *&TE) {
- #if 0
- DeclContext *DC = SemaRef.computeDeclContext(RTy);
- // If the object expression is dependent and isn't the current instantiation,
- // lookup will not find anything and we must defer until instantiation.
- if (!DC) {
- R.setNotFoundInCurrentInstantiation();
- return false;
- }
- #endif
-
// FIXME: Should this use Name.isDependentName()?
if (DeclarationName Name = R.getLookupName();
Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
@@ -712,49 +702,18 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
MOUS,
TemplateKWLoc);
}
- #if 1
- SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
- #else
- if (SS.isSet()) {
- // If the member name was a qualified-id, look into the
- // nested-name-specifier.
- DC = SemaRef.computeDeclContext(SS, false);
- // We tried to look into a dependent context that is not the current
- // instantiation. Defer lookup until instantiation.
- if (!DC) {
- R.setNotFoundInCurrentInstantiation();
- return 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);
- #endif
+ SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
if (!R.empty() || R.wasNotFoundInCurrentInstantiation())
return false;
DeclarationName Typo = R.getLookupName();
SourceLocation TypoLoc = R.getNameLoc();
- #if 1
+ // Recompute the lookup context.
DeclContext *DC = SS.isSet()
? SemaRef.computeDeclContext(SS)
: SemaRef.computeDeclContext(RTy);
- #endif
struct QueryState {
Sema &SemaRef;
@@ -1016,7 +975,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
ActOnMemberAccessExtraArgs *ExtraArgs) {
assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid");
if (R.wasNotFoundInCurrentInstantiation() ||
+ #if 0
(SS.isValid() && !computeDeclContext(SS, false))) {
+ #else
+ false) {
+ #endif
return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
TemplateKWLoc, FirstQualifierInScope,
R.getLookupNameInfo(), TemplateArgs);
@@ -1060,8 +1023,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
// Rederive where we looked up.
DeclContext *DC = (SS.isSet() ? computeDeclContext(SS, false)
: computeDeclContext(BaseType));
- // : BaseType->getAsRecordDecl());
-
if (ExtraArgs) {
ExprResult RetryExpr;
if (!IsArrow && BaseExpr && !BaseExpr->isTypeDependent()) {
@@ -1087,7 +1048,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
}
}
- if (SS.isInvalid() || (SS.isNotEmpty() && !DC)) {
+ if (SS.isNotEmpty() && !DC) {
Diag(R.getNameLoc(), diag::err_undeclared_use)
<< MemberName << SS.getRange();
} else if (DC) {
@@ -1100,16 +1061,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
<< MemberName << BaseExprType
<< (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
}
-
- if (DC) {
- } else {
- #if 0
- // FIXME: Is this needed?
- Diag(R.getNameLoc(), diag::err_no_member)
- << MemberName << BaseExprType
- << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
- #endif
- }
return ExprError();
}
>From 49df7fdca06e355bb85dd58a39bd96ee39f643f6 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 19 Mar 2024 08:03:43 -0400
Subject: [PATCH 16/18] [FOLD] format
---
clang/include/clang/Sema/Lookup.h | 4 +++-
clang/include/clang/Sema/Sema.h | 20 +++++++++-----------
clang/lib/Parse/ParseDecl.cpp | 3 ++-
clang/lib/Sema/HLSLExternalSemaSource.cpp | 2 +-
clang/lib/Sema/SemaAttr.cpp | 2 +-
clang/lib/Sema/SemaDecl.cpp | 3 ++-
clang/lib/Sema/SemaExpr.cpp | 3 ++-
clang/lib/Sema/SemaExprMember.cpp | 23 ++++++++++-------------
clang/lib/Sema/SemaLookup.cpp | 16 ++++++----------
clang/lib/Sema/SemaOpenMP.cpp | 6 ++++--
clang/lib/Sema/SemaTemplate.cpp | 16 +++++++---------
11 files changed, 47 insertions(+), 51 deletions(-)
diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h
index 16c23dd903e86a..ab9896d7f9d80e 100644
--- a/clang/include/clang/Sema/Lookup.h
+++ b/clang/include/clang/Sema/Lookup.h
@@ -496,7 +496,9 @@ class LookupResult {
/// Note that while no result was found in the current instantiation,
/// there were dependent base classes that could not be searched.
void setNotFoundInCurrentInstantiation() {
- assert((ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation) && Decls.empty());
+ assert((ResultKind == NotFound ||
+ ResultKind == NotFoundInCurrentInstantiation) &&
+ Decls.empty());
ResultKind = NotFoundInCurrentInstantiation;
}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 77203ffcbd0b30..48f64f20b01340 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7739,11 +7739,8 @@ class Sema final {
bool InUnqualifiedLookup = false);
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
CXXScopeSpec &SS);
- bool LookupParsedName(LookupResult &R,
- Scope *S,
- CXXScopeSpec *SS,
- QualType ObjectType,
- bool AllowBuiltinCreation = false,
+ bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
+ QualType ObjectType, bool AllowBuiltinCreation = false,
bool EnteringContext = false);
ObjCProtocolDecl *
LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc,
@@ -9152,12 +9149,13 @@ class Sema final {
bool EnteringContext, bool &MemberOfUnknownSpecialization,
RequiredTemplateKind RequiredTemplate = SourceLocation(),
AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);
-
- bool LookupTemplateName(
- LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType,
- bool EnteringContext,
- RequiredTemplateKind RequiredTemplate = SourceLocation(),
- AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);
+
+ bool
+ LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
+ QualType ObjectType, bool EnteringContext,
+ RequiredTemplateKind RequiredTemplate = SourceLocation(),
+ AssumedTemplateKind *ATK = nullptr,
+ bool AllowTypoCorrection = true);
TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS,
bool hasTemplateKeyword,
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index ed3acbe984a2fd..702084b1b730e1 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2998,7 +2998,8 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
<< TokenName << TagName << getLangOpts().CPlusPlus
<< FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName);
- if (Actions.LookupParsedName(R, getCurScope(), SS, /*ObjectType=*/QualType())) {
+ if (Actions.LookupParsedName(R, getCurScope(), SS,
+ /*ObjectType=*/QualType())) {
for (LookupResult::iterator I = R.begin(), IEnd = R.end();
I != IEnd; ++I)
Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index f6a93c378acf4b..f3556792127305 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -133,7 +133,7 @@ struct BuiltinTypeDeclBuilder {
LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
S.LookupParsedName(R, S.getCurScope(), &SS,
/*ObjectType=*/QualType(),
- /*AllowBuiltinCreation*/false);
+ /*AllowBuiltinCreation*/ false);
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 adbcf8eba9d114..8b788376cdcca7 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -840,7 +840,7 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
LookupParsedName(Lookup, curScope,
/*SS=*/nullptr,
/*ObjectType=*/QualType(),
- /*AllowBuiltinCreation*/true);
+ /*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 575d345f268515..4406f3e66a7efd 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -892,7 +892,8 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
}
LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
- LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType(), /*AllowBuiltinCreation*/!CurMethod);
+ LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType(),
+ /*AllowBuiltinCreation*/ !CurMethod);
if (SS.isInvalid())
return NameClassification::Error();
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 9a70406687cb60..2df39e4dd5094f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2781,7 +2781,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
IsAddressOfOperand, TemplateArgs);
} else {
bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl();
- LookupParsedName(R, S, &SS, /*ObjectType=*/QualType(), /*AllowBuiltinCreation=*/!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/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 89bb77ba4ac751..093d758554bf2a 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -690,16 +690,14 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
OpLoc, RTy, diag::err_typecheck_incomplete_tag, BaseRange))
return true;
- // LookupTemplateName/LookupParsedName don't expect these both to exist simultaneously.
+ // LookupTemplateName/LookupParsedName don't expect these both to exist
+ // simultaneously.
QualType ObjectType = SS.isSet() ? QualType() : RTy;
if (HasTemplateArgs || TemplateKWLoc.isValid()) {
bool MOUS;
return SemaRef.LookupTemplateName(R,
- /*S=*/nullptr,
- SS,
- ObjectType,
- /*EnteringContext=*/false,
- MOUS,
+ /*S=*/nullptr, SS, ObjectType,
+ /*EnteringContext=*/false, MOUS,
TemplateKWLoc);
}
@@ -711,9 +709,8 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
DeclarationName Typo = R.getLookupName();
SourceLocation TypoLoc = R.getNameLoc();
// Recompute the lookup context.
- DeclContext *DC = SS.isSet()
- ? SemaRef.computeDeclContext(SS)
- : SemaRef.computeDeclContext(RTy);
+ DeclContext *DC = SS.isSet() ? SemaRef.computeDeclContext(SS)
+ : SemaRef.computeDeclContext(RTy);
struct QueryState {
Sema &SemaRef;
@@ -975,11 +972,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
ActOnMemberAccessExtraArgs *ExtraArgs) {
assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid");
if (R.wasNotFoundInCurrentInstantiation() ||
- #if 0
+#if 0
(SS.isValid() && !computeDeclContext(SS, false))) {
- #else
+#else
false) {
- #endif
+#endif
return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
TemplateKWLoc, FirstQualifierInScope,
R.getLookupNameInfo(), TemplateArgs);
@@ -1050,7 +1047,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
if (SS.isNotEmpty() && !DC) {
Diag(R.getNameLoc(), diag::err_undeclared_use)
- << MemberName << SS.getRange();
+ << MemberName << SS.getRange();
} else if (DC) {
Diag(R.getNameLoc(), diag::err_no_member)
<< MemberName << DC
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index f9ea644d9344ed..cf38fe884aadcd 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2716,11 +2716,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
/// context of the scope-specifier SS (if present).
///
/// @returns True if any decls were found (but possibly ambiguous)
-bool Sema::LookupParsedName(LookupResult &R,
- Scope *S,
- CXXScopeSpec *SS,
- QualType ObjectType,
- bool AllowBuiltinCreation,
+bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
+ QualType ObjectType, bool AllowBuiltinCreation,
bool EnteringContext) {
// When the scope specifier is invalid, don't even look for anything.
if (SS && SS->isInvalid())
@@ -2732,12 +2729,12 @@ bool Sema::LookupParsedName(LookupResult &R,
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");
+ 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->isIncompleteType() || !ObjectType->getAs<TagType>() ||
ObjectType->castAs<TagType>()->isBeingDefined()) &&
"Caller should have completed object type");
} else if (SS && SS->isNotEmpty()) {
@@ -5036,8 +5033,7 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
SemaRef.LookupParsedName(Res, S, SS,
/*ObjectType=*/QualType(),
- /*AllowBuiltinCreation=*/false,
- EnteringContext);
+ /*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 1e9cea600f1551..a7870bf723fa0f 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -19159,7 +19159,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, /*ObjectType=*/QualType())) {
+ while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec,
+ /*ObjectType=*/QualType())) {
NamedDecl *D = Lookup.getRepresentativeDecl();
do {
S = S->getParent();
@@ -22012,7 +22013,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, /*ObjectType=*/QualType())) {
+ while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec,
+ /*ObjectType=*/QualType())) {
NamedDecl *D = Lookup.getRepresentativeDecl();
while (S && !S->isDeclScope(D))
S = S->getParent();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index b0773b528f9592..c2194c4a0bdb56 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -371,10 +371,8 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
return true;
}
-bool Sema::LookupTemplateName(LookupResult &Found,
- Scope *S, CXXScopeSpec &SS,
- QualType ObjectType,
- bool EnteringContext,
+bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
+ QualType ObjectType, bool EnteringContext,
RequiredTemplateKind RequiredTemplate,
AssumedTemplateKind *ATK,
bool AllowTypoCorrection) {
@@ -5489,8 +5487,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
LookupResult R(*this, NameInfo, LookupOrdinaryName);
if (LookupTemplateName(R, (Scope *)nullptr, SS, QualType(),
- /*Entering*/false,
- TemplateKWLoc))
+ /*Entering*/ false, TemplateKWLoc))
return ExprError();
if (R.isAmbiguous())
@@ -5616,8 +5613,8 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S,
RequiredTemplateKind RTK = TemplateKWLoc.isValid()
? RequiredTemplateKind(TemplateKWLoc)
: TemplateNameIsRequired;
- if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext,
- RTK, /*ATK=*/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)
@@ -11068,7 +11065,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
: TSK_ExplicitInstantiationDeclaration;
LookupResult Previous(*this, NameInfo, LookupOrdinaryName);
- LookupParsedName(Previous, S, &D.getCXXScopeSpec(), /*ObjectType=*/QualType());
+ LookupParsedName(Previous, S, &D.getCXXScopeSpec(),
+ /*ObjectType=*/QualType());
if (!R->isFunctionType()) {
// C++ [temp.explicit]p1:
>From d0cb69bc1595ce9d99e140dcc2bd1afb92337f61 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 4 Apr 2024 15:34:40 -0400
Subject: [PATCH 17/18] [FOLD] cleanups
---
clang/lib/Parse/ParseDecl.cpp | 3 +--
clang/lib/Sema/HLSLExternalSemaSource.cpp | 9 +++++----
clang/lib/Sema/SemaAttr.cpp | 5 +----
clang/lib/Sema/SemaDecl.cpp | 2 +-
clang/lib/Sema/SemaExpr.cpp | 8 +++-----
clang/lib/Sema/SemaExprMember.cpp | 24 ++++++++---------------
clang/lib/Sema/SemaOverload.cpp | 3 ---
7 files changed, 19 insertions(+), 35 deletions(-)
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 702084b1b730e1..71c51a065e2f03 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2998,8 +2998,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
<< TokenName << TagName << getLangOpts().CPlusPlus
<< FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName);
- if (Actions.LookupParsedName(R, getCurScope(), SS,
- /*ObjectType=*/QualType())) {
+ if (Actions.LookupName(R, getCurScope())) {
for (LookupResult::iterator I = R.begin(), IEnd = R.end();
I != IEnd; ++I)
Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index f3556792127305..bb283c54b3d29c 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -126,14 +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,
- /*ObjectType=*/QualType(),
- /*AllowBuiltinCreation*/ 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 8b788376cdcca7..a83b1e8afadbc6 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -837,10 +837,7 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
IdentifierInfo *Name = IdTok.getIdentifierInfo();
LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName);
- LookupParsedName(Lookup, curScope,
- /*SS=*/nullptr,
- /*ObjectType=*/QualType(),
- /*AllowBuiltinCreation*/ 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 4406f3e66a7efd..4caf4ce152cff8 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -893,7 +893,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType(),
- /*AllowBuiltinCreation*/ !CurMethod);
+ /*AllowBuiltinCreation=*/!CurMethod);
if (SS.isInvalid())
return NameClassification::Error();
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 2df39e4dd5094f..e39ac2e36678a4 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2746,8 +2746,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
@@ -2768,11 +2768,9 @@ 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, /*ObjectType=*/QualType(),
- /*EnteringContext=*/false,
- MemberOfUnknownSpecialization, TemplateKWLoc,
+ /*EnteringContext=*/false, TemplateKWLoc,
&AssumedTemplate))
return ExprError();
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 093d758554bf2a..8692439702e15c 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -693,13 +693,10 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
// LookupTemplateName/LookupParsedName don't expect these both to exist
// simultaneously.
QualType ObjectType = SS.isSet() ? QualType() : RTy;
- if (HasTemplateArgs || TemplateKWLoc.isValid()) {
- bool MOUS;
+ if (HasTemplateArgs || TemplateKWLoc.isValid())
return SemaRef.LookupTemplateName(R,
/*S=*/nullptr, SS, ObjectType,
- /*EnteringContext=*/false, MOUS,
- TemplateKWLoc);
- }
+ /*EnteringContext=*/false, TemplateKWLoc);
SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
@@ -971,16 +968,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
bool SuppressQualifierCheck,
ActOnMemberAccessExtraArgs *ExtraArgs) {
assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid");
- if (R.wasNotFoundInCurrentInstantiation() ||
-#if 0
- (SS.isValid() && !computeDeclContext(SS, false))) {
-#else
- false) {
-#endif
+ if (R.wasNotFoundInCurrentInstantiation())
return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
TemplateKWLoc, FirstQualifierInScope,
R.getLookupNameInfo(), TemplateArgs);
- }
QualType BaseType = BaseExprType;
if (IsArrow) {
@@ -989,6 +980,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()) {
@@ -1288,10 +1284,6 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
QualType BaseType = BaseExpr.get()->getType();
-#if 0
- assert(!BaseType->isDependentType());
-#endif
-
DeclarationName MemberName = R.getLookupName();
SourceLocation MemberLoc = R.getNameLoc();
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 4a2df219b5ea11..0c913bc700f4a1 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -5803,10 +5803,7 @@ static ImplicitConversionSequence TryObjectArgumentInitialization(
return ICS;
}
-// FIXME: Should this check getAsRecordDecl instead?
-#if 0
assert(FromType->isRecordType());
-#endif
QualType ClassType = S.Context.getTypeDeclType(ActingContext);
// C++98 [class.dtor]p2:
>From dede5cd1192cd3e1b1f38c284027535927ad4687 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 8 Apr 2024 07:23:49 -0400
Subject: [PATCH 18/18] [FOLD] update clang-tidy tests
---
.../checkers/cppcoreguidelines/owning-memory.cpp | 2 ++
.../checkers/modernize/use-equals-default-copy.cpp | 12 ++++++++++++
2 files changed, 14 insertions(+)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp
index 574efe7bd91478..a7bc567c37fcc3 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp
@@ -309,6 +309,8 @@ struct HeapArray { // Ok, since destruc
HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok
other._data = nullptr; // Ok
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'std::nullptr_t'
+ // FIXME: Assigning nullptr should be valid?
other.size = 0;
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp
index 559031cf4d9bda..4abb9c8555970e 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp
@@ -260,6 +260,8 @@ template <class T>
struct Template {
Template() = default;
Template(const Template &Other) : Field(Other.Field) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: Template(const Template &Other) = default;
Template &operator=(const Template &Other);
void foo(const T &t);
int Field;
@@ -269,8 +271,12 @@ Template<T> &Template<T>::operator=(const Template<T> &Other) {
Field = Other.Field;
return *this;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:27: warning: use '= default'
+// CHECK-FIXES: Template<T> &Template<T>::operator=(const Template<T> &Other) = default;
+
Template<int> T1;
+
// Dependent types.
template <class T>
struct DT1 {
@@ -284,6 +290,9 @@ DT1<T> &DT1<T>::operator=(const DT1<T> &Other) {
Field = Other.Field;
return *this;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:17: warning: use '= default'
+// CHECK-FIXES: DT1<T> &DT1<T>::operator=(const DT1<T> &Other) = default;
+
DT1<int> Dt1;
template <class T>
@@ -303,6 +312,9 @@ DT2<T> &DT2<T>::operator=(const DT2<T> &Other) {
struct T {
typedef int TT;
};
+// CHECK-MESSAGES: :[[@LINE-8]]:17: warning: use '= default'
+// CHECK-FIXES: DT2<T> &DT2<T>::operator=(const DT2<T> &Other) = default;
+
DT2<T> Dt2;
// Default arguments.
More information about the cfe-commits
mailing list