Skip to content

Commit aa80f3e

Browse files
authored
Reapply "[Clang][Sema] Fix crash when 'this' is used in a dependent class scope function template specialization that instantiates to a static member function (#87541)" (#88311)
Reapplies #87541 and addresses the bug which caused expressions naming overload sets to be incorrectly rebuilt.
1 parent 20ed5b1 commit aa80f3e

9 files changed

+252
-99
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,8 @@ Bug Fixes to C++ Support
526526
- Fix an issue caused by not handling invalid cases when substituting into the parameter mapping of a constraint. Fixes (#GH86757).
527527
- Fixed a bug that prevented member function templates of class templates declared with a deduced return type
528528
from being explicitly specialized for a given implicit instantiation of the class template.
529+
- Fixed a crash when ``this`` is used in a dependent class scope function template specialization
530+
that instantiates to a static member function.
529531

530532
- Fix crash when inheriting from a cv-qualified type. Fixes:
531533
(`#35603 <https://github.com/llvm/llvm-project/issues/35603>`_)

clang/include/clang/Sema/Sema.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5447,7 +5447,8 @@ class Sema final : public SemaBase {
54475447

54485448
ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R,
54495449
bool NeedsADL,
5450-
bool AcceptInvalidDecl = false);
5450+
bool AcceptInvalidDecl = false,
5451+
bool NeedUnresolved = false);
54515452
ExprResult BuildDeclarationNameExpr(
54525453
const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
54535454
NamedDecl *FoundD = nullptr,
@@ -6590,7 +6591,10 @@ class Sema final : public SemaBase {
65906591
SourceLocation RParenLoc);
65916592

65926593
//// ActOnCXXThis - Parse 'this' pointer.
6593-
ExprResult ActOnCXXThis(SourceLocation loc);
6594+
ExprResult ActOnCXXThis(SourceLocation Loc);
6595+
6596+
/// Check whether the type of 'this' is valid in the current context.
6597+
bool CheckCXXThisType(SourceLocation Loc, QualType Type);
65946598

65956599
/// Build a CXXThisExpr and mark it referenced in the current context.
65966600
Expr *BuildCXXThisExpr(SourceLocation Loc, QualType Type, bool IsImplicit);
@@ -7013,10 +7017,14 @@ class Sema final : public SemaBase {
70137017
///@{
70147018

70157019
public:
7020+
/// Check whether an expression might be an implicit class member access.
7021+
bool isPotentialImplicitMemberAccess(const CXXScopeSpec &SS, LookupResult &R,
7022+
bool IsAddressOfOperand);
7023+
70167024
ExprResult BuildPossibleImplicitMemberExpr(
70177025
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R,
7018-
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
7019-
UnresolvedLookupExpr *AsULE = nullptr);
7026+
const TemplateArgumentListInfo *TemplateArgs, const Scope *S);
7027+
70207028
ExprResult
70217029
BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
70227030
LookupResult &R,

clang/lib/Sema/SemaExpr.cpp

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2912,26 +2912,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
29122912
// to get this right here so that we don't end up making a
29132913
// spuriously dependent expression if we're inside a dependent
29142914
// instance method.
2915-
if (getLangOpts().CPlusPlus && !R.empty() &&
2916-
(*R.begin())->isCXXClassMember()) {
2917-
bool MightBeImplicitMember;
2918-
if (!IsAddressOfOperand)
2919-
MightBeImplicitMember = true;
2920-
else if (!SS.isEmpty())
2921-
MightBeImplicitMember = false;
2922-
else if (R.isOverloadedResult())
2923-
MightBeImplicitMember = false;
2924-
else if (R.isUnresolvableResult())
2925-
MightBeImplicitMember = true;
2926-
else
2927-
MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()) ||
2928-
isa<IndirectFieldDecl>(R.getFoundDecl()) ||
2929-
isa<MSPropertyDecl>(R.getFoundDecl());
2930-
2931-
if (MightBeImplicitMember)
2932-
return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc,
2933-
R, TemplateArgs, S);
2934-
}
2915+
if (isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand))
2916+
return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs,
2917+
S);
29352918

29362919
if (TemplateArgs || TemplateKWLoc.isValid()) {
29372920

@@ -3442,10 +3425,11 @@ static bool ShouldLookupResultBeMultiVersionOverload(const LookupResult &R) {
34423425

34433426
ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
34443427
LookupResult &R, bool NeedsADL,
3445-
bool AcceptInvalidDecl) {
3428+
bool AcceptInvalidDecl,
3429+
bool NeedUnresolved) {
34463430
// If this is a single, fully-resolved result and we don't need ADL,
34473431
// just build an ordinary singleton decl ref.
3448-
if (!NeedsADL && R.isSingleResult() &&
3432+
if (!NeedUnresolved && !NeedsADL && R.isSingleResult() &&
34493433
!R.getAsSingle<FunctionTemplateDecl>() &&
34503434
!ShouldLookupResultBeMultiVersionOverload(R))
34513435
return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(),

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,26 +1414,42 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
14141414
}
14151415

14161416
ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
1417-
/// C++ 9.3.2: In the body of a non-static member function, the keyword this
1418-
/// is a non-lvalue expression whose value is the address of the object for
1419-
/// which the function is called.
1417+
// C++20 [expr.prim.this]p1:
1418+
// The keyword this names a pointer to the object for which an
1419+
// implicit object member function is invoked or a non-static
1420+
// data member's initializer is evaluated.
14201421
QualType ThisTy = getCurrentThisType();
14211422

1422-
if (ThisTy.isNull()) {
1423-
DeclContext *DC = getFunctionLevelDeclContext();
1423+
if (CheckCXXThisType(Loc, ThisTy))
1424+
return ExprError();
14241425

1425-
if (const auto *Method = dyn_cast<CXXMethodDecl>(DC);
1426-
Method && Method->isExplicitObjectMemberFunction()) {
1427-
return Diag(Loc, diag::err_invalid_this_use) << 1;
1428-
}
1426+
return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
1427+
}
14291428

1430-
if (isLambdaCallWithExplicitObjectParameter(CurContext))
1431-
return Diag(Loc, diag::err_invalid_this_use) << 1;
1429+
bool Sema::CheckCXXThisType(SourceLocation Loc, QualType Type) {
1430+
if (!Type.isNull())
1431+
return false;
14321432

1433-
return Diag(Loc, diag::err_invalid_this_use) << 0;
1433+
// C++20 [expr.prim.this]p3:
1434+
// If a declaration declares a member function or member function template
1435+
// of a class X, the expression this is a prvalue of type
1436+
// "pointer to cv-qualifier-seq X" wherever X is the current class between
1437+
// the optional cv-qualifier-seq and the end of the function-definition,
1438+
// member-declarator, or declarator. It shall not appear within the
1439+
// declaration of either a static member function or an explicit object
1440+
// member function of the current class (although its type and value
1441+
// category are defined within such member functions as they are within
1442+
// an implicit object member function).
1443+
DeclContext *DC = getFunctionLevelDeclContext();
1444+
if (const auto *Method = dyn_cast<CXXMethodDecl>(DC);
1445+
Method && Method->isExplicitObjectMemberFunction()) {
1446+
Diag(Loc, diag::err_invalid_this_use) << 1;
1447+
} else if (isLambdaCallWithExplicitObjectParameter(CurContext)) {
1448+
Diag(Loc, diag::err_invalid_this_use) << 1;
1449+
} else {
1450+
Diag(Loc, diag::err_invalid_this_use) << 0;
14341451
}
1435-
1436-
return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
1452+
return true;
14371453
}
14381454

14391455
Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type,
@@ -8626,21 +8642,8 @@ static ExprResult attemptRecovery(Sema &SemaRef,
86268642

86278643
// Detect and handle the case where the decl might be an implicit
86288644
// member.
8629-
bool MightBeImplicitMember;
8630-
if (!Consumer.isAddressOfOperand())
8631-
MightBeImplicitMember = true;
8632-
else if (!NewSS.isEmpty())
8633-
MightBeImplicitMember = false;
8634-
else if (R.isOverloadedResult())
8635-
MightBeImplicitMember = false;
8636-
else if (R.isUnresolvableResult())
8637-
MightBeImplicitMember = true;
8638-
else
8639-
MightBeImplicitMember = isa<FieldDecl>(ND) ||
8640-
isa<IndirectFieldDecl>(ND) ||
8641-
isa<MSPropertyDecl>(ND);
8642-
8643-
if (MightBeImplicitMember)
8645+
if (SemaRef.isPotentialImplicitMemberAccess(
8646+
NewSS, R, Consumer.isAddressOfOperand()))
86448647
return SemaRef.BuildPossibleImplicitMemberExpr(
86458648
NewSS, /*TemplateKWLoc*/ SourceLocation(), R,
86468649
/*TemplateArgs*/ nullptr, /*S*/ nullptr);

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ enum IMAKind {
6161
/// The reference is a contextually-permitted abstract member reference.
6262
IMA_Abstract,
6363

64+
/// Whether the context is static is dependent on the enclosing template (i.e.
65+
/// in a dependent class scope explicit specialization).
66+
IMA_Dependent,
67+
6468
/// The reference may be to an unresolved using declaration and the
6569
/// context is not an instance method.
6670
IMA_Unresolved_StaticOrExplicitContext,
@@ -91,10 +95,18 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
9195

9296
DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
9397

94-
bool isStaticOrExplicitContext =
95-
SemaRef.CXXThisTypeOverride.isNull() &&
96-
(!isa<CXXMethodDecl>(DC) || cast<CXXMethodDecl>(DC)->isStatic() ||
97-
cast<CXXMethodDecl>(DC)->isExplicitObjectMemberFunction());
98+
bool couldInstantiateToStatic = false;
99+
bool isStaticOrExplicitContext = SemaRef.CXXThisTypeOverride.isNull();
100+
101+
if (auto *MD = dyn_cast<CXXMethodDecl>(DC)) {
102+
if (MD->isImplicitObjectMemberFunction()) {
103+
isStaticOrExplicitContext = false;
104+
// A dependent class scope function template explicit specialization
105+
// that is neither declared 'static' nor with an explicit object
106+
// parameter could instantiate to a static or non-static member function.
107+
couldInstantiateToStatic = MD->getDependentSpecializationInfo();
108+
}
109+
}
98110

99111
if (R.isUnresolvableResult())
100112
return isStaticOrExplicitContext ? IMA_Unresolved_StaticOrExplicitContext
@@ -123,6 +135,9 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
123135
if (Classes.empty())
124136
return IMA_Static;
125137

138+
if (couldInstantiateToStatic)
139+
return IMA_Dependent;
140+
126141
// C++11 [expr.prim.general]p12:
127142
// An id-expression that denotes a non-static data member or non-static
128143
// member function of a class can only be used:
@@ -263,32 +278,52 @@ static void diagnoseInstanceReference(Sema &SemaRef,
263278
}
264279
}
265280

281+
bool Sema::isPotentialImplicitMemberAccess(const CXXScopeSpec &SS,
282+
LookupResult &R,
283+
bool IsAddressOfOperand) {
284+
if (!getLangOpts().CPlusPlus)
285+
return false;
286+
else if (R.empty() || !R.begin()->isCXXClassMember())
287+
return false;
288+
else if (!IsAddressOfOperand)
289+
return true;
290+
else if (!SS.isEmpty())
291+
return false;
292+
else if (R.isOverloadedResult())
293+
return false;
294+
else if (R.isUnresolvableResult())
295+
return true;
296+
else
297+
return isa<FieldDecl, IndirectFieldDecl, MSPropertyDecl>(R.getFoundDecl());
298+
}
299+
266300
/// Builds an expression which might be an implicit member expression.
267301
ExprResult Sema::BuildPossibleImplicitMemberExpr(
268302
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R,
269-
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
270-
UnresolvedLookupExpr *AsULE) {
271-
switch (ClassifyImplicitMemberAccess(*this, R)) {
303+
const TemplateArgumentListInfo *TemplateArgs, const Scope *S) {
304+
switch (IMAKind Classification = ClassifyImplicitMemberAccess(*this, R)) {
272305
case IMA_Instance:
273-
return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true, S);
274-
275306
case IMA_Mixed:
276307
case IMA_Mixed_Unrelated:
277308
case IMA_Unresolved:
278-
return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, false,
279-
S);
280-
309+
return BuildImplicitMemberExpr(
310+
SS, TemplateKWLoc, R, TemplateArgs,
311+
/*IsKnownInstance=*/Classification == IMA_Instance, S);
281312
case IMA_Field_Uneval_Context:
282313
Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use)
283314
<< R.getLookupNameInfo().getName();
284315
[[fallthrough]];
285316
case IMA_Static:
286317
case IMA_Abstract:
318+
case IMA_Dependent:
287319
case IMA_Mixed_StaticOrExplicitContext:
288320
case IMA_Unresolved_StaticOrExplicitContext:
289321
if (TemplateArgs || TemplateKWLoc.isValid())
290-
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, TemplateArgs);
291-
return AsULE ? AsULE : BuildDeclarationNameExpr(SS, R, false);
322+
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*RequiresADL=*/false,
323+
TemplateArgs);
324+
return BuildDeclarationNameExpr(
325+
SS, R, /*NeedsADL=*/false, /*AcceptInvalidDecl=*/false,
326+
/*NeedUnresolved=*/Classification == IMA_Dependent);
292327

293328
case IMA_Error_StaticOrExplicitContext:
294329
case IMA_Error_Unrelated:

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5095,6 +5095,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
50955095
EnterExpressionEvaluationContext EvalContext(
50965096
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
50975097

5098+
Qualifiers ThisTypeQuals;
5099+
CXXRecordDecl *ThisContext = nullptr;
5100+
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
5101+
ThisContext = Method->getParent();
5102+
ThisTypeQuals = Method->getMethodQualifiers();
5103+
}
5104+
CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals);
5105+
50985106
// Introduce a new scope where local variable instantiations will be
50995107
// recorded, unless we're actually a member function within a local
51005108
// class, in which case we need to merge our results with the parent

0 commit comments

Comments
 (0)