Skip to content

Commit 4ae259b

Browse files
committed
[Clang][Sema] Don't build CXXDependentScopeMemberExprs for potentially implicit class member access expressions
1 parent da928c6 commit 4ae259b

File tree

9 files changed

+206
-109
lines changed

9 files changed

+206
-109
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5366,11 +5366,9 @@ class Sema final : public SemaBase {
53665366
bool UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R,
53675367
bool HasTrailingLParen);
53685368

5369-
ExprResult
5370-
BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
5371-
const DeclarationNameInfo &NameInfo,
5372-
bool IsAddressOfOperand, const Scope *S,
5373-
TypeSourceInfo **RecoveryTSI = nullptr);
5369+
ExprResult BuildQualifiedDeclarationNameExpr(
5370+
CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
5371+
bool IsAddressOfOperand, TypeSourceInfo **RecoveryTSI = nullptr);
53745372

53755373
ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R,
53765374
bool NeedsADL,
@@ -8982,7 +8980,8 @@ class Sema final : public SemaBase {
89828980
ExprResult
89838981
BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
89848982
const DeclarationNameInfo &NameInfo,
8985-
const TemplateArgumentListInfo *TemplateArgs);
8983+
const TemplateArgumentListInfo *TemplateArgs,
8984+
bool IsAddressOfOperand);
89868985

89878986
TemplateNameKind ActOnTemplateName(Scope *S, CXXScopeSpec &SS,
89888987
SourceLocation TemplateKWLoc,

clang/lib/Sema/SemaCXXScopeSpec.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,14 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
796796
Diag(IdInfo.IdentifierLoc,
797797
diag::ext_undeclared_unqual_id_with_dependent_base)
798798
<< IdInfo.Identifier << ContainingClass;
799+
// Fake up a nested-name-specifier that starts with the
800+
// injected-class-name of the enclosing class.
801+
QualType T = Context.getTypeDeclType(ContainingClass);
802+
TypeLocBuilder TLB;
803+
TLB.pushTrivial(Context, T, IdInfo.IdentifierLoc);
804+
SS.Extend(Context, /*TemplateKWLoc=*/SourceLocation(),
805+
TLB.getTypeLocInContext(Context, T), IdInfo.IdentifierLoc);
806+
// Add the identifier to form a dependent name.
799807
SS.Extend(Context, IdInfo.Identifier, IdInfo.IdentifierLoc,
800808
IdInfo.CCLoc);
801809
return false;

clang/lib/Sema/SemaExpr.cpp

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2946,26 +2946,14 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
29462946
/// this path.
29472947
ExprResult Sema::BuildQualifiedDeclarationNameExpr(
29482948
CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
2949-
bool IsAddressOfOperand, const Scope *S, TypeSourceInfo **RecoveryTSI) {
2950-
if (NameInfo.getName().isDependentName())
2951-
return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
2952-
NameInfo, /*TemplateArgs=*/nullptr);
2953-
2954-
DeclContext *DC = computeDeclContext(SS, false);
2955-
if (!DC)
2956-
return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
2957-
NameInfo, /*TemplateArgs=*/nullptr);
2958-
2959-
if (RequireCompleteDeclContext(SS, DC))
2960-
return ExprError();
2961-
2949+
bool IsAddressOfOperand, TypeSourceInfo **RecoveryTSI) {
29622950
LookupResult R(*this, NameInfo, LookupOrdinaryName);
2963-
LookupQualifiedName(R, DC);
2951+
LookupParsedName(R, /*S=*/nullptr, &SS, /*ObjectType=*/QualType());
29642952

29652953
if (R.isAmbiguous())
29662954
return ExprError();
29672955

2968-
if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)
2956+
if (R.wasNotFoundInCurrentInstantiation() || SS.isInvalid())
29692957
return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
29702958
NameInfo, /*TemplateArgs=*/nullptr);
29712959

@@ -2974,6 +2962,7 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
29742962
// diagnostic during template instantiation is likely bogus, e.g. if a class
29752963
// is invalid because it's derived from an invalid base class, then missing
29762964
// members were likely supposed to be inherited.
2965+
DeclContext *DC = computeDeclContext(SS);
29772966
if (const auto *CD = dyn_cast<CXXRecordDecl>(DC))
29782967
if (CD->isInvalidDecl())
29792968
return ExprError();
@@ -3017,16 +3006,14 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
30173006
return ExprEmpty();
30183007
}
30193008

3020-
// Defend against this resolving to an implicit member access. We usually
3021-
// won't get here if this might be a legitimate a class member (we end up in
3022-
// BuildMemberReferenceExpr instead), but this can be valid if we're forming
3023-
// a pointer-to-member or in an unevaluated context in C++11.
3024-
if (!R.empty() && (*R.begin())->isCXXClassMember() && !IsAddressOfOperand)
3009+
// If necessary, build an implicit class member access.
3010+
if (isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand))
30253011
return BuildPossibleImplicitMemberExpr(SS,
30263012
/*TemplateKWLoc=*/SourceLocation(),
3027-
R, /*TemplateArgs=*/nullptr, S);
3013+
R, /*TemplateArgs=*/nullptr,
3014+
/*S=*/nullptr);
30283015

3029-
return BuildDeclarationNameExpr(SS, R, /* ADL */ false);
3016+
return BuildDeclarationNameExpr(SS, R, /*ADL=*/false);
30303017
}
30313018

30323019
/// Cast a base object to a member's actual type.

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 30 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -726,44 +726,18 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
726726
const DeclarationNameInfo &NameInfo,
727727
bool isAddressOfOperand,
728728
const TemplateArgumentListInfo *TemplateArgs) {
729-
DeclContext *DC = getFunctionLevelDeclContext();
730-
731-
// C++11 [expr.prim.general]p12:
732-
// An id-expression that denotes a non-static data member or non-static
733-
// member function of a class can only be used:
734-
// (...)
735-
// - if that id-expression denotes a non-static data member and it
736-
// appears in an unevaluated operand.
737-
//
738-
// If this might be the case, form a DependentScopeDeclRefExpr instead of a
739-
// CXXDependentScopeMemberExpr. The former can instantiate to either
740-
// DeclRefExpr or MemberExpr depending on lookup results, while the latter is
741-
// always a MemberExpr.
742-
bool MightBeCxx11UnevalField =
743-
getLangOpts().CPlusPlus11 && isUnevaluatedContext();
744-
745-
// Check if the nested name specifier is an enum type.
746-
bool IsEnum = false;
747-
if (NestedNameSpecifier *NNS = SS.getScopeRep())
748-
IsEnum = isa_and_nonnull<EnumType>(NNS->getAsType());
749-
750-
if (!MightBeCxx11UnevalField && !isAddressOfOperand && !IsEnum &&
751-
isa<CXXMethodDecl>(DC) &&
752-
cast<CXXMethodDecl>(DC)->isImplicitObjectMemberFunction()) {
753-
QualType ThisType =
754-
cast<CXXMethodDecl>(DC)->getThisType().getNonReferenceType();
755-
756-
// Since the 'this' expression is synthesized, we don't need to
757-
// perform the double-lookup check.
758-
NamedDecl *FirstQualifierInScope = nullptr;
729+
if (SS.isEmpty()) {
730+
QualType ThisType = getCurrentThisType();
731+
if (ThisType.isNull())
732+
return ExprError();
759733

760734
return CXXDependentScopeMemberExpr::Create(
761-
Context, /*This=*/nullptr, ThisType,
735+
Context, /*Base=*/nullptr, ThisType,
762736
/*IsArrow=*/!Context.getLangOpts().HLSL,
763-
/*Op=*/SourceLocation(), SS.getWithLocInContext(Context), TemplateKWLoc,
764-
FirstQualifierInScope, NameInfo, TemplateArgs);
737+
/*OperatorLoc=*/SourceLocation(),
738+
/*QualifierLoc*/ NestedNameSpecifierLoc(), TemplateKWLoc,
739+
/*FirstQualifierFoundInScope*/ nullptr, NameInfo, TemplateArgs);
765740
}
766-
767741
return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
768742
}
769743

@@ -772,13 +746,15 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
772746
SourceLocation TemplateKWLoc,
773747
const DeclarationNameInfo &NameInfo,
774748
const TemplateArgumentListInfo *TemplateArgs) {
775-
// DependentScopeDeclRefExpr::Create requires a valid QualifierLoc
776-
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
777-
if (!QualifierLoc)
778-
return ExprError();
749+
// DependentScopeDeclRefExpr::Create requires a valid NestedNameSpecifierLoc
750+
if (!SS.isValid())
751+
return CreateRecoveryExpr(
752+
SS.getBeginLoc(),
753+
TemplateArgs ? TemplateArgs->getRAngleLoc() : NameInfo.getEndLoc(), {});
779754

780755
return DependentScopeDeclRefExpr::Create(
781-
Context, QualifierLoc, TemplateKWLoc, NameInfo, TemplateArgs);
756+
Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo,
757+
TemplateArgs);
782758
}
783759

784760

@@ -5745,50 +5721,36 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
57455721
}
57465722

57475723
// We actually only call this from template instantiation.
5748-
ExprResult
5749-
Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
5750-
SourceLocation TemplateKWLoc,
5751-
const DeclarationNameInfo &NameInfo,
5752-
const TemplateArgumentListInfo *TemplateArgs) {
5753-
5724+
ExprResult Sema::BuildQualifiedTemplateIdExpr(
5725+
CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
5726+
const DeclarationNameInfo &NameInfo,
5727+
const TemplateArgumentListInfo *TemplateArgs, bool IsAddressOfOperand) {
57545728
assert(TemplateArgs || TemplateKWLoc.isValid());
5755-
DeclContext *DC;
5756-
if (!(DC = computeDeclContext(SS, false)) ||
5757-
DC->isDependentContext() ||
5758-
RequireCompleteDeclContext(SS, DC))
5759-
return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
57605729

57615730
LookupResult R(*this, NameInfo, LookupOrdinaryName);
5762-
if (LookupTemplateName(R, (Scope *)nullptr, SS, QualType(),
5763-
/*Entering*/ false, TemplateKWLoc))
5731+
if (LookupTemplateName(R, /*S=*/nullptr, SS, /*ObjectType=*/QualType(),
5732+
/*EnteringContext=*/false, TemplateKWLoc))
57645733
return ExprError();
57655734

57665735
if (R.isAmbiguous())
57675736
return ExprError();
57685737

5738+
if (R.wasNotFoundInCurrentInstantiation() || SS.isInvalid())
5739+
return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
5740+
57695741
if (R.empty()) {
5742+
DeclContext *DC = computeDeclContext(SS);
57705743
Diag(NameInfo.getLoc(), diag::err_no_member)
57715744
<< NameInfo.getName() << DC << SS.getRange();
57725745
return ExprError();
57735746
}
57745747

5775-
auto DiagnoseTypeTemplateDecl = [&](TemplateDecl *Temp,
5776-
bool isTypeAliasTemplateDecl) {
5777-
Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template)
5778-
<< SS.getScopeRep() << NameInfo.getName().getAsString() << SS.getRange()
5779-
<< isTypeAliasTemplateDecl;
5780-
Diag(Temp->getLocation(), diag::note_referenced_type_template)
5781-
<< isTypeAliasTemplateDecl;
5782-
return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {});
5783-
};
5784-
5785-
if (ClassTemplateDecl *Temp = R.getAsSingle<ClassTemplateDecl>())
5786-
return DiagnoseTypeTemplateDecl(Temp, false);
5787-
5788-
if (TypeAliasTemplateDecl *Temp = R.getAsSingle<TypeAliasTemplateDecl>())
5789-
return DiagnoseTypeTemplateDecl(Temp, true);
5748+
// If necessary, build an implicit class member access.
5749+
if (isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand))
5750+
return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs,
5751+
/*S=*/nullptr);
57905752

5791-
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL*/ false, TemplateArgs);
5753+
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL=*/false, TemplateArgs);
57925754
}
57935755

57945756
/// Form a template name from a name that is syntactically required to name a

clang/lib/Sema/TreeTransform.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3478,11 +3478,11 @@ class TreeTransform {
34783478
SS.Adopt(QualifierLoc);
34793479

34803480
if (TemplateArgs || TemplateKWLoc.isValid())
3481-
return getSema().BuildQualifiedTemplateIdExpr(SS, TemplateKWLoc, NameInfo,
3482-
TemplateArgs);
3481+
return getSema().BuildQualifiedTemplateIdExpr(
3482+
SS, TemplateKWLoc, NameInfo, TemplateArgs, IsAddressOfOperand);
34833483

34843484
return getSema().BuildQualifiedDeclarationNameExpr(
3485-
SS, NameInfo, IsAddressOfOperand, /*S*/nullptr, RecoveryTSI);
3485+
SS, NameInfo, IsAddressOfOperand, RecoveryTSI);
34863486
}
34873487

34883488
/// Build a new template-id expression.

clang/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ namespace test2 {
7070
}
7171

7272
void test1() {
73-
B<T>::foo();
73+
B<T>::foo(); // expected-error {{call to non-static member function without an object argument}}
7474
}
7575

7676
static void test2() {
@@ -91,8 +91,95 @@ namespace test2 {
9191
int test() {
9292
A<int> a;
9393
a.test0(); // no instantiation note here, decl is ill-formed
94-
a.test1();
94+
a.test1(); // expected-note {{in instantiation}}
9595
a.test2(); // expected-note {{in instantiation}}
9696
a.test3(); // expected-note {{in instantiation}}
9797
}
9898
}
99+
100+
namespace test3 {
101+
struct A {
102+
void f0();
103+
104+
template<typename T>
105+
void f1();
106+
107+
static void f2();
108+
109+
template<typename T>
110+
static void f3();
111+
112+
int x0;
113+
114+
static constexpr int x1 = 0;
115+
116+
template<typename T>
117+
static constexpr int x2 = 0;
118+
};
119+
120+
template<typename T>
121+
struct B : T {
122+
auto g0() -> decltype(T::f0());
123+
124+
auto g1() -> decltype(T::template f1<int>());
125+
126+
auto g2() -> decltype(T::f2());
127+
128+
auto g3() -> decltype(T::template f3<int>());
129+
130+
auto g4() -> decltype(T::x0);
131+
132+
auto g5() -> decltype(T::x1);
133+
134+
auto g6() -> decltype(T::template x2<int>);
135+
136+
decltype(T::f0()) g7(); // expected-error {{call to non-static member function without an object argument}}
137+
138+
decltype(T::template f1<int>()) g8(); // expected-error {{call to non-static member function without an object argument}}
139+
140+
decltype(T::f2()) g9();
141+
142+
decltype(T::template f3<int>()) g10();
143+
144+
decltype(T::x0) g11();
145+
146+
decltype(T::x1) g12();
147+
148+
decltype(T::template x2<int>) g13();
149+
};
150+
151+
template struct B<A>; // expected-note {{in instantiation of}}
152+
153+
template<typename T>
154+
struct C : T {
155+
static auto g0() -> decltype(T::f0()); // expected-error {{'this' cannot be implicitly used in a static member function declaration}}
156+
157+
static auto g1() -> decltype(T::template f1<int>()); // expected-error {{'this' cannot be implicitly used in a static member function declaration}}
158+
159+
static auto g2() -> decltype(T::f2());
160+
161+
static auto g3() -> decltype(T::template f3<int>());
162+
163+
static auto g4() -> decltype(T::x0); // expected-error {{'this' cannot be implicitly used in a static member function declaration}}
164+
165+
static auto g5() -> decltype(T::x1);
166+
167+
static auto g6() -> decltype(T::template x2<int>);
168+
169+
static decltype(T::f0()) g7(); // expected-error {{call to non-static member function without an object argument}}
170+
171+
static decltype(T::template f1<int>()) g8(); // expected-error {{call to non-static member function without an object argument}}
172+
173+
static decltype(T::f2()) g9();
174+
175+
static decltype(T::template f3<int>()) g10();
176+
177+
static decltype(T::x0) g11();
178+
179+
static decltype(T::x1) g12();
180+
181+
static decltype(T::template x2<int>) g13();
182+
};
183+
184+
template struct C<A>; // expected-note {{in instantiation of}}
185+
}

0 commit comments

Comments
 (0)