[clang] [Clang][Sema] Don't build CXXDependentScopeMemberExprs for potentially implicit class member access expressions (PR #92318)
Krystian Stasiowski via cfe-commits
cfe-commits at lists.llvm.org
Fri May 17 14:05:40 PDT 2024
https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/92318
>From db264c719dfae25a536fb2452328d9aaeeea7b6f Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Wed, 15 May 2024 16:13:03 -0400
Subject: [PATCH 1/4] [Clang][Sema] Don't build CXXDependentScopeMemberExprs
for potentially implicit class member access expressions
---
clang/include/clang/Sema/Sema.h | 11 +--
clang/lib/Sema/SemaCXXScopeSpec.cpp | 8 ++
clang/lib/Sema/SemaExpr.cpp | 31 ++----
clang/lib/Sema/SemaTemplate.cpp | 98 ++++++-------------
clang/lib/Sema/TreeTransform.h | 6 +-
.../class.mfct/class.mfct.non-static/p3.cpp | 91 ++++++++++++++++-
...ms-function-specialization-class-scope.cpp | 52 ++++++++++
.../ms-lookup-template-base-classes.cpp | 12 +--
.../ASTMatchers/ASTMatchersNodeTest.cpp | 6 +-
9 files changed, 206 insertions(+), 109 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d4d4a82525a02..fcc60a2ee4bca 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -5374,11 +5374,9 @@ class Sema final : public SemaBase {
bool UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R,
bool HasTrailingLParen);
- ExprResult
- BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo,
- bool IsAddressOfOperand, const Scope *S,
- TypeSourceInfo **RecoveryTSI = nullptr);
+ ExprResult BuildQualifiedDeclarationNameExpr(
+ CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
+ bool IsAddressOfOperand, TypeSourceInfo **RecoveryTSI = nullptr);
ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R,
bool NeedsADL,
@@ -8990,7 +8988,8 @@ class Sema final : public SemaBase {
ExprResult
BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs);
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool IsAddressOfOperand);
TemplateNameKind ActOnTemplateName(Scope *S, CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index fca5bd131bbc0..c405fbc0aa421 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -796,6 +796,14 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
Diag(IdInfo.IdentifierLoc,
diag::ext_undeclared_unqual_id_with_dependent_base)
<< IdInfo.Identifier << ContainingClass;
+ // Fake up a nested-name-specifier that starts with the
+ // injected-class-name of the enclosing class.
+ QualType T = Context.getTypeDeclType(ContainingClass);
+ TypeLocBuilder TLB;
+ TLB.pushTrivial(Context, T, IdInfo.IdentifierLoc);
+ SS.Extend(Context, /*TemplateKWLoc=*/SourceLocation(),
+ TLB.getTypeLocInContext(Context, T), IdInfo.IdentifierLoc);
+ // Add the identifier to form a dependent name.
SS.Extend(Context, IdInfo.Identifier, IdInfo.IdentifierLoc,
IdInfo.CCLoc);
return false;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 5ecfdee21f09d..ebf02ae566044 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2946,26 +2946,14 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
/// this path.
ExprResult Sema::BuildQualifiedDeclarationNameExpr(
CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
- bool IsAddressOfOperand, const Scope *S, TypeSourceInfo **RecoveryTSI) {
- if (NameInfo.getName().isDependentName())
- return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
- NameInfo, /*TemplateArgs=*/nullptr);
-
- DeclContext *DC = computeDeclContext(SS, false);
- if (!DC)
- return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
- NameInfo, /*TemplateArgs=*/nullptr);
-
- if (RequireCompleteDeclContext(SS, DC))
- return ExprError();
-
+ bool IsAddressOfOperand, TypeSourceInfo **RecoveryTSI) {
LookupResult R(*this, NameInfo, LookupOrdinaryName);
- LookupQualifiedName(R, DC);
+ LookupParsedName(R, /*S=*/nullptr, &SS, /*ObjectType=*/QualType());
if (R.isAmbiguous())
return ExprError();
- if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)
+ if (R.wasNotFoundInCurrentInstantiation() || SS.isInvalid())
return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
NameInfo, /*TemplateArgs=*/nullptr);
@@ -2974,6 +2962,7 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
// diagnostic during template instantiation is likely bogus, e.g. if a class
// is invalid because it's derived from an invalid base class, then missing
// members were likely supposed to be inherited.
+ DeclContext *DC = computeDeclContext(SS);
if (const auto *CD = dyn_cast<CXXRecordDecl>(DC))
if (CD->isInvalidDecl())
return ExprError();
@@ -3017,16 +3006,14 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
return ExprEmpty();
}
- // Defend against this resolving to an implicit member access. We usually
- // won't get here if this might be a legitimate a class member (we end up in
- // BuildMemberReferenceExpr instead), but this can be valid if we're forming
- // a pointer-to-member or in an unevaluated context in C++11.
- if (!R.empty() && (*R.begin())->isCXXClassMember() && !IsAddressOfOperand)
+ // If necessary, build an implicit class member access.
+ if (isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand))
return BuildPossibleImplicitMemberExpr(SS,
/*TemplateKWLoc=*/SourceLocation(),
- R, /*TemplateArgs=*/nullptr, S);
+ R, /*TemplateArgs=*/nullptr,
+ /*S=*/nullptr);
- return BuildDeclarationNameExpr(SS, R, /* ADL */ false);
+ return BuildDeclarationNameExpr(SS, R, /*ADL=*/false);
}
/// Cast a base object to a member's actual type.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 4937cce4621f0..8fbd174c603c5 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -726,44 +726,18 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo,
bool isAddressOfOperand,
const TemplateArgumentListInfo *TemplateArgs) {
- DeclContext *DC = getFunctionLevelDeclContext();
-
- // C++11 [expr.prim.general]p12:
- // An id-expression that denotes a non-static data member or non-static
- // member function of a class can only be used:
- // (...)
- // - if that id-expression denotes a non-static data member and it
- // appears in an unevaluated operand.
- //
- // If this might be the case, form a DependentScopeDeclRefExpr instead of a
- // CXXDependentScopeMemberExpr. The former can instantiate to either
- // DeclRefExpr or MemberExpr depending on lookup results, while the latter is
- // always a MemberExpr.
- bool MightBeCxx11UnevalField =
- getLangOpts().CPlusPlus11 && isUnevaluatedContext();
-
- // Check if the nested name specifier is an enum type.
- bool IsEnum = false;
- if (NestedNameSpecifier *NNS = SS.getScopeRep())
- IsEnum = isa_and_nonnull<EnumType>(NNS->getAsType());
-
- if (!MightBeCxx11UnevalField && !isAddressOfOperand && !IsEnum &&
- isa<CXXMethodDecl>(DC) &&
- cast<CXXMethodDecl>(DC)->isImplicitObjectMemberFunction()) {
- QualType ThisType =
- cast<CXXMethodDecl>(DC)->getThisType().getNonReferenceType();
-
- // Since the 'this' expression is synthesized, we don't need to
- // perform the double-lookup check.
- NamedDecl *FirstQualifierInScope = nullptr;
+ if (SS.isEmpty()) {
+ QualType ThisType = getCurrentThisType();
+ if (ThisType.isNull())
+ return ExprError();
return CXXDependentScopeMemberExpr::Create(
- Context, /*This=*/nullptr, ThisType,
+ Context, /*Base=*/nullptr, ThisType,
/*IsArrow=*/!Context.getLangOpts().HLSL,
- /*Op=*/SourceLocation(), SS.getWithLocInContext(Context), TemplateKWLoc,
- FirstQualifierInScope, NameInfo, TemplateArgs);
+ /*OperatorLoc=*/SourceLocation(),
+ /*QualifierLoc*/ NestedNameSpecifierLoc(), TemplateKWLoc,
+ /*FirstQualifierFoundInScope*/ nullptr, NameInfo, TemplateArgs);
}
-
return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
}
@@ -772,13 +746,15 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
- // DependentScopeDeclRefExpr::Create requires a valid QualifierLoc
- NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
- if (!QualifierLoc)
- return ExprError();
+ // DependentScopeDeclRefExpr::Create requires a valid NestedNameSpecifierLoc
+ if (!SS.isValid())
+ return CreateRecoveryExpr(
+ SS.getBeginLoc(),
+ TemplateArgs ? TemplateArgs->getRAngleLoc() : NameInfo.getEndLoc(), {});
return DependentScopeDeclRefExpr::Create(
- Context, QualifierLoc, TemplateKWLoc, NameInfo, TemplateArgs);
+ Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo,
+ TemplateArgs);
}
@@ -5747,50 +5723,36 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
}
// We actually only call this from template instantiation.
-ExprResult
-Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc,
- const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs) {
-
+ExprResult Sema::BuildQualifiedTemplateIdExpr(
+ CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
+ const DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *TemplateArgs, bool IsAddressOfOperand) {
assert(TemplateArgs || TemplateKWLoc.isValid());
- DeclContext *DC;
- if (!(DC = computeDeclContext(SS, false)) ||
- DC->isDependentContext() ||
- RequireCompleteDeclContext(SS, DC))
- return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
LookupResult R(*this, NameInfo, LookupOrdinaryName);
- if (LookupTemplateName(R, (Scope *)nullptr, SS, QualType(),
- /*Entering*/ false, TemplateKWLoc))
+ if (LookupTemplateName(R, /*S=*/nullptr, SS, /*ObjectType=*/QualType(),
+ /*EnteringContext=*/false, TemplateKWLoc))
return ExprError();
if (R.isAmbiguous())
return ExprError();
+ if (R.wasNotFoundInCurrentInstantiation() || SS.isInvalid())
+ return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
+
if (R.empty()) {
+ DeclContext *DC = computeDeclContext(SS);
Diag(NameInfo.getLoc(), diag::err_no_member)
<< NameInfo.getName() << DC << SS.getRange();
return ExprError();
}
- auto DiagnoseTypeTemplateDecl = [&](TemplateDecl *Temp,
- bool isTypeAliasTemplateDecl) {
- Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template)
- << SS.getScopeRep() << NameInfo.getName().getAsString() << SS.getRange()
- << isTypeAliasTemplateDecl;
- Diag(Temp->getLocation(), diag::note_referenced_type_template)
- << isTypeAliasTemplateDecl;
- return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {});
- };
-
- if (ClassTemplateDecl *Temp = R.getAsSingle<ClassTemplateDecl>())
- return DiagnoseTypeTemplateDecl(Temp, false);
-
- if (TypeAliasTemplateDecl *Temp = R.getAsSingle<TypeAliasTemplateDecl>())
- return DiagnoseTypeTemplateDecl(Temp, true);
+ // If necessary, build an implicit class member access.
+ if (isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand))
+ return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs,
+ /*S=*/nullptr);
- return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL*/ false, TemplateArgs);
+ return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL=*/false, TemplateArgs);
}
/// Form a template name from a name that is syntactically required to name a
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 29444f0edc2ae..0d565fe6cc7a7 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3478,11 +3478,11 @@ class TreeTransform {
SS.Adopt(QualifierLoc);
if (TemplateArgs || TemplateKWLoc.isValid())
- return getSema().BuildQualifiedTemplateIdExpr(SS, TemplateKWLoc, NameInfo,
- TemplateArgs);
+ return getSema().BuildQualifiedTemplateIdExpr(
+ SS, TemplateKWLoc, NameInfo, TemplateArgs, IsAddressOfOperand);
return getSema().BuildQualifiedDeclarationNameExpr(
- SS, NameInfo, IsAddressOfOperand, /*S*/nullptr, RecoveryTSI);
+ SS, NameInfo, IsAddressOfOperand, RecoveryTSI);
}
/// Build a new template-id expression.
diff --git a/clang/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp b/clang/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp
index 9116e7146f812..01fa923dd1715 100644
--- a/clang/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp
+++ b/clang/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp
@@ -70,7 +70,7 @@ namespace test2 {
}
void test1() {
- B<T>::foo();
+ B<T>::foo(); // expected-error {{call to non-static member function without an object argument}}
}
static void test2() {
@@ -91,8 +91,95 @@ namespace test2 {
int test() {
A<int> a;
a.test0(); // no instantiation note here, decl is ill-formed
- a.test1();
+ a.test1(); // expected-note {{in instantiation}}
a.test2(); // expected-note {{in instantiation}}
a.test3(); // expected-note {{in instantiation}}
}
}
+
+namespace test3 {
+ struct A {
+ void f0();
+
+ template<typename T>
+ void f1();
+
+ static void f2();
+
+ template<typename T>
+ static void f3();
+
+ int x0;
+
+ static constexpr int x1 = 0;
+
+ template<typename T>
+ static constexpr int x2 = 0;
+ };
+
+ template<typename T>
+ struct B : T {
+ auto g0() -> decltype(T::f0());
+
+ auto g1() -> decltype(T::template f1<int>());
+
+ auto g2() -> decltype(T::f2());
+
+ auto g3() -> decltype(T::template f3<int>());
+
+ auto g4() -> decltype(T::x0);
+
+ auto g5() -> decltype(T::x1);
+
+ auto g6() -> decltype(T::template x2<int>);
+
+ decltype(T::f0()) g7(); // expected-error {{call to non-static member function without an object argument}}
+
+ decltype(T::template f1<int>()) g8(); // expected-error {{call to non-static member function without an object argument}}
+
+ decltype(T::f2()) g9();
+
+ decltype(T::template f3<int>()) g10();
+
+ decltype(T::x0) g11();
+
+ decltype(T::x1) g12();
+
+ decltype(T::template x2<int>) g13();
+ };
+
+ template struct B<A>; // expected-note {{in instantiation of}}
+
+ template<typename T>
+ struct C : T {
+ static auto g0() -> decltype(T::f0()); // expected-error {{'this' cannot be implicitly used in a static member function declaration}}
+
+ static auto g1() -> decltype(T::template f1<int>()); // expected-error {{'this' cannot be implicitly used in a static member function declaration}}
+
+ static auto g2() -> decltype(T::f2());
+
+ static auto g3() -> decltype(T::template f3<int>());
+
+ static auto g4() -> decltype(T::x0); // expected-error {{'this' cannot be implicitly used in a static member function declaration}}
+
+ static auto g5() -> decltype(T::x1);
+
+ static auto g6() -> decltype(T::template x2<int>);
+
+ static decltype(T::f0()) g7(); // expected-error {{call to non-static member function without an object argument}}
+
+ static decltype(T::template f1<int>()) g8(); // expected-error {{call to non-static member function without an object argument}}
+
+ static decltype(T::f2()) g9();
+
+ static decltype(T::template f3<int>()) g10();
+
+ static decltype(T::x0) g11();
+
+ static decltype(T::x1) g12();
+
+ static decltype(T::template x2<int>) g13();
+ };
+
+ template struct C<A>; // expected-note {{in instantiation of}}
+}
diff --git a/clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp b/clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp
index c49d2cb2422fa..e1f3ab37ad947 100644
--- a/clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp
+++ b/clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp
@@ -464,6 +464,32 @@ namespace UsesThis {
g1(x1);
g1(y0);
g1(y1);
+
+ T::f0(0);
+ T::f0(z);
+ T::f0(x0);
+ T::f0(x1);
+ T::f0(y0);
+ T::f0(y1);
+ T::g0(0);
+ T::g0(z);
+ T::g0(x0);
+ T::g0(x1);
+ T::g0(y0);
+ T::g0(y1);
+
+ E::f1(0);
+ E::f1(z);
+ E::f1(x0);
+ E::f1(x1);
+ E::f1(y0);
+ E::f1(y1);
+ E::g1(0);
+ E::g1(z);
+ E::g1(x0);
+ E::g1(x1);
+ E::g1(y0);
+ E::g1(y1);
}
template<>
@@ -519,6 +545,32 @@ namespace UsesThis {
g1(x1); // expected-error {{invalid use of member 'x1' in static member function}}
g1(y0);
g1(y1);
+
+ T::f0(0); // expected-error {{call to non-static member function without an object argument}}
+ T::f0(z); // expected-error {{call to non-static member function without an object argument}}
+ T::f0(x0); // expected-error {{call to non-static member function without an object argument}}
+ T::f0(x1); // expected-error {{call to non-static member function without an object argument}}
+ T::f0(y0); // expected-error {{call to non-static member function without an object argument}}
+ T::f0(y1); // expected-error {{call to non-static member function without an object argument}}
+ T::g0(0);
+ T::g0(z);
+ T::g0(x0); // expected-error {{invalid use of member 'x0' in static member function}}
+ T::g0(x1); // expected-error {{invalid use of member 'x1' in static member function}}
+ T::g0(y0);
+ T::g0(y1);
+
+ E::f1(0); // expected-error {{call to non-static member function without an object argument}}
+ E::f1(z); // expected-error {{call to non-static member function without an object argument}}
+ E::f1(x0); // expected-error {{call to non-static member function without an object argument}}
+ E::f1(x1); // expected-error {{call to non-static member function without an object argument}}
+ E::f1(y0); // expected-error {{call to non-static member function without an object argument}}
+ E::f1(y1); // expected-error {{call to non-static member function without an object argument}}
+ E::g1(0);
+ E::g1(z);
+ E::g1(x0); // expected-error {{invalid use of member 'x0' in static member function}}
+ E::g1(x1); // expected-error {{invalid use of member 'x1' in static member function}}
+ E::g1(y0);
+ E::g1(y1);
}
};
diff --git a/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp
index 534a5dc9ddc10..547e5945ac6bc 100644
--- a/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp
+++ b/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp
@@ -102,7 +102,7 @@ class B : public A<T> {
};
template class B<int>; // expected-note {{requested here}}
-}
+}
@@ -111,8 +111,8 @@ namespace lookup_dependent_base_class_default_argument {
template<class T>
class A {
public:
- static int f1(); // expected-note {{must qualify identifier to find this declaration in dependent base class}}
- int f2(); // expected-note {{must qualify identifier to find this declaration in dependent base class}}
+ static int f1(); // expected-note {{must qualify identifier to find this declaration in dependent base class}}
+ int f2(); // expected-note {{must qualify identifier to find this declaration in dependent base class}}
};
template<class T>
@@ -137,7 +137,7 @@ namespace lookup_dependent_base_class_friend {
template <class T>
class B {
public:
- static void g(); // expected-note {{must qualify identifier to find this declaration in dependent base class}}
+ static void g(); // expected-note {{must qualify identifier to find this declaration in dependent base class}}
};
template <class T>
@@ -228,7 +228,7 @@ template <typename T> struct C : T {
int *bar() { return &b; } // expected-error {{no member named 'b' in 'PR16014::C<A>'}} expected-warning {{lookup into dependent bases}}
int baz() { return T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}}
int T::*qux() { return &T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}}
- int T::*fuz() { return &U::a; } // expected-error {{use of undeclared identifier 'U'}} \
+ int T::*fuz() { return &U::a; } // expected-error {{no member named 'U' in 'PR16014::C<A>'}} \
// expected-warning {{unqualified lookup into dependent bases of class template 'C'}}
};
@@ -258,7 +258,7 @@ struct A : T {
::UndefClass::undef(); // expected-error {{no member named 'UndefClass' in the global namespace}}
}
void baz() {
- B::qux(); // expected-error {{use of undeclared identifier 'B'}} \
+ B::qux(); // expected-error {{no member named 'B' in 'PR19233::A<D>'}} \
// expected-warning {{unqualified lookup into dependent bases of class template 'A'}}
}
};
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index 65df513d27137..2e42b85808953 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -614,8 +614,10 @@ TEST_P(ASTMatchersTest, MemberExpr_MatchesVariable) {
EXPECT_TRUE(matches("template <class T>"
"class X : T { void f() { this->T::v; } };",
cxxDependentScopeMemberExpr()));
- EXPECT_TRUE(matches("template <class T> class X : T { void f() { T::v; } };",
- cxxDependentScopeMemberExpr()));
+ // FIXME: Add a matcher for DependentScopeDeclRefExpr.
+ EXPECT_TRUE(
+ notMatches("template <class T> class X : T { void f() { T::v; } };",
+ cxxDependentScopeMemberExpr()));
EXPECT_TRUE(matches("template <class T> void x() { T t; t.v; }",
cxxDependentScopeMemberExpr()));
}
>From 8bf66e9efbf03f152bb27b27a5f80b995b60c650 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Wed, 15 May 2024 18:02:14 -0400
Subject: [PATCH 2/4] [FOLD] comment fixup
---
clang/lib/Sema/SemaTemplate.cpp | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 8fbd174c603c5..5c8ebe3569b9c 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -727,6 +727,10 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
bool isAddressOfOperand,
const TemplateArgumentListInfo *TemplateArgs) {
if (SS.isEmpty()) {
+ // FIXME: This codepath is only used by dependent unqualified names
+ // (e.g. a dependent conversion-function-id, or operator= once we support
+ // it). It doesn't quite do the right thing, and it will silently fail if
+ // getCurrentThisType() returns null.
QualType ThisType = getCurrentThisType();
if (ThisType.isNull())
return ExprError();
@@ -735,8 +739,8 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
Context, /*Base=*/nullptr, ThisType,
/*IsArrow=*/!Context.getLangOpts().HLSL,
/*OperatorLoc=*/SourceLocation(),
- /*QualifierLoc*/ NestedNameSpecifierLoc(), TemplateKWLoc,
- /*FirstQualifierFoundInScope*/ nullptr, NameInfo, TemplateArgs);
+ /*QualifierLoc=*/NestedNameSpecifierLoc(), TemplateKWLoc,
+ /*FirstQualifierFoundInScope=*/nullptr, NameInfo, TemplateArgs);
}
return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
}
>From 91a0808b4fe22c778868c13be8f7aa09ded8ad34 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 16 May 2024 07:42:36 -0400
Subject: [PATCH 3/4] [FOLD] replace uses of
LookupResult::NotFoundInCurrentInstantiation with
wasNotFoundInCurrentInstantiation()
---
clang/lib/Sema/SemaExpr.cpp | 2 +-
clang/lib/Sema/SemaTemplate.cpp | 3 +--
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ebf02ae566044..9d84ddb99d0ff 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2791,7 +2791,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// If the result might be in a dependent base class, this is a dependent
// id-expression.
- if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)
+ if (R.wasNotFoundInCurrentInstantiation())
return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
IsAddressOfOperand, TemplateArgs);
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 5c8ebe3569b9c..4df12e07a33ba 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5948,8 +5948,7 @@ bool Sema::CheckTemplateTypeArgument(
LookupParsedName(Result, CurScope, &SS, /*ObjectType=*/QualType());
if (Result.getAsSingle<TypeDecl>() ||
- Result.getResultKind() ==
- LookupResult::NotFoundInCurrentInstantiation) {
+ Result.wasNotFoundInCurrentInstantiation()) {
assert(SS.getScopeRep() && "dependent scope expr must has a scope!");
// Suggest that the user add 'typename' before the NNS.
SourceLocation Loc = AL.getSourceRange().getBegin();
>From 862c80dd6b0eeb7173764bf41283ebbfbadeb506 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 16 May 2024 17:41:08 -0400
Subject: [PATCH 4/4] [FOLD] add release note
---
clang/docs/ReleaseNotes.rst | 2 ++
1 file changed, 2 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2f83f5c6d54e9..5206c5867fca4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -758,6 +758,8 @@ Bug Fixes to C++ Support
- Fix a bug with checking constrained non-type template parameters for equivalence. Fixes (#GH77377).
- Fix a bug where the last argument was not considered when considering the most viable function for
explicit object argument member functions. Fixes (#GH92188).
+- Clang no longer transforms dependent qualified names into implicit class member access expressions
+ until it can be determined whether the name is that of a non-static member.
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
More information about the cfe-commits
mailing list