Skip to content

Commit 5c4b923

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)" (#88731)
Reapplies #87541 and #88311 (again) addressing the bug which caused expressions naming overload sets to be incorrectly rebuilt, as well as the bug which caused base class members to always be treated as overload sets. The primary change since #88311 is `UnresolvedLookupExpr::Create` is called directly in `BuildPossibleImplicitMemberExpr` with `KnownDependent` as `true` (which causes the expression type to be set to `ASTContext::DependentTy`). This ensures that any further semantic analysis involving the type of the potentially implicit class member access expression is deferred until instantiation.
1 parent 6bd29d6 commit 5c4b923

20 files changed

+646
-153
lines changed

clang/docs/ReleaseNotes.rst

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

542544
- Fix crash when inheriting from a cv-qualified type. Fixes #GH35603
543545
- Fix a crash when the using enum declaration uses an anonymous enumeration. Fixes (#GH86790).

clang/include/clang/AST/ExprCXX.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3198,7 +3198,6 @@ class UnresolvedLookupExpr final
31983198
NestedNameSpecifierLoc QualifierLoc,
31993199
SourceLocation TemplateKWLoc,
32003200
const DeclarationNameInfo &NameInfo, bool RequiresADL,
3201-
bool Overloaded,
32023201
const TemplateArgumentListInfo *TemplateArgs,
32033202
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
32043203
bool KnownDependent);
@@ -3218,8 +3217,9 @@ class UnresolvedLookupExpr final
32183217
static UnresolvedLookupExpr *
32193218
Create(const ASTContext &Context, CXXRecordDecl *NamingClass,
32203219
NestedNameSpecifierLoc QualifierLoc,
3221-
const DeclarationNameInfo &NameInfo, bool RequiresADL, bool Overloaded,
3222-
UnresolvedSetIterator Begin, UnresolvedSetIterator End);
3220+
const DeclarationNameInfo &NameInfo, bool RequiresADL,
3221+
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
3222+
bool KnownDependent);
32233223

32243224
// After canonicalization, there may be dependent template arguments in
32253225
// CanonicalConverted But none of Args is dependent. When any of
@@ -3240,9 +3240,6 @@ class UnresolvedLookupExpr final
32403240
/// argument-dependent lookup.
32413241
bool requiresADL() const { return UnresolvedLookupExprBits.RequiresADL; }
32423242

3243-
/// True if this lookup is overloaded.
3244-
bool isOverloaded() const { return UnresolvedLookupExprBits.Overloaded; }
3245-
32463243
/// Gets the 'naming class' (in the sense of C++0x
32473244
/// [class.access.base]p5) of the lookup. This is the scope
32483245
/// that was looked in to find these results.

clang/include/clang/AST/Stmt.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,11 +1067,6 @@ class alignas(void *) Stmt {
10671067
/// argument-dependent lookup if this is the operand of a function call.
10681068
LLVM_PREFERRED_TYPE(bool)
10691069
unsigned RequiresADL : 1;
1070-
1071-
/// True if these lookup results are overloaded. This is pretty trivially
1072-
/// rederivable if we urgently need to kill this field.
1073-
LLVM_PREFERRED_TYPE(bool)
1074-
unsigned Overloaded : 1;
10751070
};
10761071
static_assert(sizeof(UnresolvedLookupExprBitfields) <= 4,
10771072
"UnresolvedLookupExprBitfields must be <= than 4 bytes to"

clang/include/clang/Sema/Sema.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6527,7 +6527,10 @@ class Sema final : public SemaBase {
65276527
SourceLocation RParenLoc);
65286528

65296529
//// ActOnCXXThis - Parse 'this' pointer.
6530-
ExprResult ActOnCXXThis(SourceLocation loc);
6530+
ExprResult ActOnCXXThis(SourceLocation Loc);
6531+
6532+
/// Check whether the type of 'this' is valid in the current context.
6533+
bool CheckCXXThisType(SourceLocation Loc, QualType Type);
65316534

65326535
/// Build a CXXThisExpr and mark it referenced in the current context.
65336536
Expr *BuildCXXThisExpr(SourceLocation Loc, QualType Type, bool IsImplicit);
@@ -6949,10 +6952,14 @@ class Sema final : public SemaBase {
69496952
///@{
69506953

69516954
public:
6955+
/// Check whether an expression might be an implicit class member access.
6956+
bool isPotentialImplicitMemberAccess(const CXXScopeSpec &SS, LookupResult &R,
6957+
bool IsAddressOfOperand);
6958+
69526959
ExprResult BuildPossibleImplicitMemberExpr(
69536960
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R,
6954-
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
6955-
UnresolvedLookupExpr *AsULE = nullptr);
6961+
const TemplateArgumentListInfo *TemplateArgs, const Scope *S);
6962+
69566963
ExprResult
69576964
BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
69586965
LookupResult &R,

clang/lib/AST/ASTImporter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8574,8 +8574,8 @@ ASTNodeImporter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
85748574

85758575
return UnresolvedLookupExpr::Create(
85768576
Importer.getToContext(), *ToNamingClassOrErr, *ToQualifierLocOrErr,
8577-
ToNameInfo, E->requiresADL(), E->isOverloaded(), ToDecls.begin(),
8578-
ToDecls.end());
8577+
ToNameInfo, E->requiresADL(), ToDecls.begin(), ToDecls.end(),
8578+
/*KnownDependent=*/E->isTypeDependent());
85798579
}
85808580

85818581
ExpectedStmt

clang/lib/AST/ExprCXX.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -353,15 +353,14 @@ SourceLocation CXXPseudoDestructorExpr::getEndLoc() const {
353353
UnresolvedLookupExpr::UnresolvedLookupExpr(
354354
const ASTContext &Context, CXXRecordDecl *NamingClass,
355355
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
356-
const DeclarationNameInfo &NameInfo, bool RequiresADL, bool Overloaded,
356+
const DeclarationNameInfo &NameInfo, bool RequiresADL,
357357
const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin,
358358
UnresolvedSetIterator End, bool KnownDependent)
359359
: OverloadExpr(UnresolvedLookupExprClass, Context, QualifierLoc,
360360
TemplateKWLoc, NameInfo, TemplateArgs, Begin, End,
361361
KnownDependent, false, false),
362362
NamingClass(NamingClass) {
363363
UnresolvedLookupExprBits.RequiresADL = RequiresADL;
364-
UnresolvedLookupExprBits.Overloaded = Overloaded;
365364
}
366365

367366
UnresolvedLookupExpr::UnresolvedLookupExpr(EmptyShell Empty,
@@ -373,15 +372,16 @@ UnresolvedLookupExpr::UnresolvedLookupExpr(EmptyShell Empty,
373372
UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
374373
const ASTContext &Context, CXXRecordDecl *NamingClass,
375374
NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo,
376-
bool RequiresADL, bool Overloaded, UnresolvedSetIterator Begin,
377-
UnresolvedSetIterator End) {
375+
bool RequiresADL, UnresolvedSetIterator Begin, UnresolvedSetIterator End,
376+
bool KnownDependent) {
378377
unsigned NumResults = End - Begin;
379378
unsigned Size = totalSizeToAlloc<DeclAccessPair, ASTTemplateKWAndArgsInfo,
380379
TemplateArgumentLoc>(NumResults, 0, 0);
381380
void *Mem = Context.Allocate(Size, alignof(UnresolvedLookupExpr));
382-
return new (Mem) UnresolvedLookupExpr(Context, NamingClass, QualifierLoc,
383-
SourceLocation(), NameInfo, RequiresADL,
384-
Overloaded, nullptr, Begin, End, false);
381+
return new (Mem) UnresolvedLookupExpr(
382+
Context, NamingClass, QualifierLoc,
383+
/*TemplateKWLoc=*/SourceLocation(), NameInfo, RequiresADL,
384+
/*TemplateArgs=*/nullptr, Begin, End, KnownDependent);
385385
}
386386

387387
UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
@@ -390,16 +390,16 @@ UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
390390
const DeclarationNameInfo &NameInfo, bool RequiresADL,
391391
const TemplateArgumentListInfo *Args, UnresolvedSetIterator Begin,
392392
UnresolvedSetIterator End, bool KnownDependent) {
393-
assert(Args || TemplateKWLoc.isValid());
394393
unsigned NumResults = End - Begin;
394+
bool HasTemplateKWAndArgsInfo = Args || TemplateKWLoc.isValid();
395395
unsigned NumTemplateArgs = Args ? Args->size() : 0;
396-
unsigned Size =
397-
totalSizeToAlloc<DeclAccessPair, ASTTemplateKWAndArgsInfo,
398-
TemplateArgumentLoc>(NumResults, 1, NumTemplateArgs);
396+
unsigned Size = totalSizeToAlloc<DeclAccessPair, ASTTemplateKWAndArgsInfo,
397+
TemplateArgumentLoc>(
398+
NumResults, HasTemplateKWAndArgsInfo, NumTemplateArgs);
399399
void *Mem = Context.Allocate(Size, alignof(UnresolvedLookupExpr));
400-
return new (Mem) UnresolvedLookupExpr(
401-
Context, NamingClass, QualifierLoc, TemplateKWLoc, NameInfo, RequiresADL,
402-
/*Overloaded=*/true, Args, Begin, End, KnownDependent);
400+
return new (Mem) UnresolvedLookupExpr(Context, NamingClass, QualifierLoc,
401+
TemplateKWLoc, NameInfo, RequiresADL,
402+
Args, Begin, End, KnownDependent);
403403
}
404404

405405
UnresolvedLookupExpr *UnresolvedLookupExpr::CreateEmpty(

clang/lib/Sema/SemaCoroutine.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -817,13 +817,10 @@ ExprResult Sema::BuildOperatorCoawaitLookupExpr(Scope *S, SourceLocation Loc) {
817817

818818
assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
819819
const auto &Functions = Operators.asUnresolvedSet();
820-
bool IsOverloaded =
821-
Functions.size() > 1 ||
822-
(Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin()));
823820
Expr *CoawaitOp = UnresolvedLookupExpr::Create(
824821
Context, /*NamingClass*/ nullptr, NestedNameSpecifierLoc(),
825-
DeclarationNameInfo(OpName, Loc), /*RequiresADL*/ true, IsOverloaded,
826-
Functions.begin(), Functions.end());
822+
DeclarationNameInfo(OpName, Loc), /*RequiresADL*/ true, Functions.begin(),
823+
Functions.end(), /*KnownDependent=*/false);
827824
assert(CoawaitOp);
828825
return CoawaitOp;
829826
}

clang/lib/Sema/SemaDecl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,8 +1240,8 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
12401240
Result.suppressDiagnostics();
12411241
return NameClassification::OverloadSet(UnresolvedLookupExpr::Create(
12421242
Context, Result.getNamingClass(), SS.getWithLocInContext(Context),
1243-
Result.getLookupNameInfo(), ADL, Result.isOverloadedResult(),
1244-
Result.begin(), Result.end()));
1243+
Result.getLookupNameInfo(), ADL, Result.begin(), Result.end(),
1244+
/*KnownDependent=*/false));
12451245
}
12461246

12471247
ExprResult

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,7 @@ static bool checkTupleLikeDecomposition(Sema &S,
13021302
// in the associated namespaces.
13031303
Expr *Get = UnresolvedLookupExpr::Create(
13041304
S.Context, nullptr, NestedNameSpecifierLoc(), SourceLocation(),
1305-
DeclarationNameInfo(GetDN, Loc), /*RequiresADL*/ true, &Args,
1305+
DeclarationNameInfo(GetDN, Loc), /*RequiresADL=*/true, &Args,
13061306
UnresolvedSetIterator(), UnresolvedSetIterator(),
13071307
/*KnownDependent=*/false);
13081308

clang/lib/Sema/SemaExpr.cpp

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

29422925
if (TemplateArgs || TemplateKWLoc.isValid()) {
29432926

@@ -3471,12 +3454,10 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
34713454
// we've picked a target.
34723455
R.suppressDiagnostics();
34733456

3474-
UnresolvedLookupExpr *ULE
3475-
= UnresolvedLookupExpr::Create(Context, R.getNamingClass(),
3476-
SS.getWithLocInContext(Context),
3477-
R.getLookupNameInfo(),
3478-
NeedsADL, R.isOverloadedResult(),
3479-
R.begin(), R.end());
3457+
UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create(
3458+
Context, R.getNamingClass(), SS.getWithLocInContext(Context),
3459+
R.getLookupNameInfo(), NeedsADL, R.begin(), R.end(),
3460+
/*KnownDependent=*/false);
34803461

34813462
return ULE;
34823463
}

clang/lib/Sema/SemaExprCXX.cpp

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

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

1424-
if (ThisTy.isNull()) {
1425-
DeclContext *DC = getFunctionLevelDeclContext();
1425+
if (CheckCXXThisType(Loc, ThisTy))
1426+
return ExprError();
14261427

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

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

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

14411457
Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type,
@@ -8644,21 +8660,8 @@ static ExprResult attemptRecovery(Sema &SemaRef,
86448660

86458661
// Detect and handle the case where the decl might be an implicit
86468662
// member.
8647-
bool MightBeImplicitMember;
8648-
if (!Consumer.isAddressOfOperand())
8649-
MightBeImplicitMember = true;
8650-
else if (!NewSS.isEmpty())
8651-
MightBeImplicitMember = false;
8652-
else if (R.isOverloadedResult())
8653-
MightBeImplicitMember = false;
8654-
else if (R.isUnresolvableResult())
8655-
MightBeImplicitMember = true;
8656-
else
8657-
MightBeImplicitMember = isa<FieldDecl>(ND) ||
8658-
isa<IndirectFieldDecl>(ND) ||
8659-
isa<MSPropertyDecl>(ND);
8660-
8661-
if (MightBeImplicitMember)
8663+
if (SemaRef.isPotentialImplicitMemberAccess(
8664+
NewSS, R, Consumer.isAddressOfOperand()))
86628665
return SemaRef.BuildPossibleImplicitMemberExpr(
86638666
NewSS, /*TemplateKWLoc*/ SourceLocation(), R,
86648667
/*TemplateArgs*/ nullptr, /*S*/ nullptr);

0 commit comments

Comments
 (0)