Skip to content

Commit 62b5b61

Browse files
authored
[Clang][Sema] Fix lookup of dependent operator= outside of complete-class contexts (llvm#91498)
Fixes a crash caused by llvm#90152.
1 parent ba5170f commit 62b5b61

File tree

3 files changed

+35
-20
lines changed

3 files changed

+35
-20
lines changed

clang/lib/Sema/SemaLookup.cpp

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,20 @@ struct FindLocalExternScope {
12671267
LookupResult &R;
12681268
bool OldFindLocalExtern;
12691269
};
1270+
1271+
/// Returns true if 'operator=' should be treated as a dependent name.
1272+
bool isDependentAssignmentOperator(DeclarationName Name,
1273+
DeclContext *LookupContext) {
1274+
const auto *LookupRecord = dyn_cast_if_present<CXXRecordDecl>(LookupContext);
1275+
// If the lookup context is the current instantiation but we are outside a
1276+
// complete-class context, we will never find the implicitly declared
1277+
// copy/move assignment operators because they are declared at the closing '}'
1278+
// of the class specifier. In such cases, we treat 'operator=' like any other
1279+
// unqualified name because the results of name lookup in the template
1280+
// definition/instantiation context will always be the same.
1281+
return Name.getCXXOverloadedOperator() == OO_Equal && LookupRecord &&
1282+
!LookupRecord->isBeingDefined() && LookupRecord->isDependentContext();
1283+
}
12701284
} // end anonymous namespace
12711285

12721286
bool Sema::CppLookupName(LookupResult &R, Scope *S) {
@@ -1275,13 +1289,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
12751289
DeclarationName Name = R.getLookupName();
12761290
Sema::LookupNameKind NameKind = R.getLookupKind();
12771291

1278-
// If this is the name of an implicitly-declared special member function,
1279-
// go through the scope stack to implicitly declare
1280-
if (isImplicitlyDeclaredMemberFunctionName(Name)) {
1281-
for (Scope *PreS = S; PreS; PreS = PreS->getParent())
1282-
if (DeclContext *DC = PreS->getEntity())
1283-
DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
1284-
}
12851292
// C++23 [temp.dep.general]p2:
12861293
// The component name of an unqualified-id is dependent if
12871294
// - it is a conversion-function-id whose conversion-type-id
@@ -1299,9 +1306,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
12991306
if (isImplicitlyDeclaredMemberFunctionName(Name)) {
13001307
for (Scope *PreS = S; PreS; PreS = PreS->getParent())
13011308
if (DeclContext *DC = PreS->getEntity()) {
1302-
if (DC->isDependentContext() && isa<CXXRecordDecl>(DC) &&
1303-
Name.getCXXOverloadedOperator() == OO_Equal &&
1304-
!R.isTemplateNameLookup()) {
1309+
if (!R.isTemplateNameLookup() &&
1310+
isDependentAssignmentOperator(Name, DC)) {
13051311
R.setNotFoundInCurrentInstantiation();
13061312
return false;
13071313
}
@@ -2472,8 +2478,6 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
24722478
}
24732479
} QL(LookupCtx);
24742480

2475-
bool TemplateNameLookup = R.isTemplateNameLookup();
2476-
CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx);
24772481
if (!InUnqualifiedLookup && !R.isForRedeclaration()) {
24782482
// C++23 [temp.dep.type]p5:
24792483
// A qualified name is dependent if
@@ -2486,13 +2490,14 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
24862490
if (DeclarationName Name = R.getLookupName();
24872491
(Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
24882492
Name.getCXXNameType()->isDependentType()) ||
2489-
(Name.getCXXOverloadedOperator() == OO_Equal && LookupRec &&
2490-
LookupRec->isDependentContext() && !TemplateNameLookup)) {
2493+
(!R.isTemplateNameLookup() &&
2494+
isDependentAssignmentOperator(Name, LookupCtx))) {
24912495
R.setNotFoundInCurrentInstantiation();
24922496
return false;
24932497
}
24942498
}
24952499

2500+
CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx);
24962501
if (LookupDirect(*this, R, LookupCtx)) {
24972502
R.resolveKind();
24982503
if (LookupRec)
@@ -2604,7 +2609,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
26042609
// template, and if the name is used as a template-name, the
26052610
// reference refers to the class template itself and not a
26062611
// specialization thereof, and is not ambiguous.
2607-
if (TemplateNameLookup)
2612+
if (R.isTemplateNameLookup())
26082613
if (auto *TD = getAsTemplateNameDecl(ND))
26092614
ND = TD;
26102615

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
726726
const DeclarationNameInfo &NameInfo,
727727
bool isAddressOfOperand,
728728
const TemplateArgumentListInfo *TemplateArgs) {
729-
DeclContext *DC = getFunctionLevelDeclContext();
729+
QualType ThisType = getCurrentThisType();
730730

731731
// C++11 [expr.prim.general]p12:
732732
// An id-expression that denotes a non-static data member or non-static
@@ -748,10 +748,7 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
748748
IsEnum = isa_and_nonnull<EnumType>(NNS->getAsType());
749749

750750
if (!MightBeCxx11UnevalField && !isAddressOfOperand && !IsEnum &&
751-
isa<CXXMethodDecl>(DC) &&
752-
cast<CXXMethodDecl>(DC)->isImplicitObjectMemberFunction()) {
753-
QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType().getNonReferenceType();
754-
751+
!ThisType.isNull()) {
755752
// Since the 'this' expression is synthesized, we don't need to
756753
// perform the double-lookup check.
757754
NamedDecl *FirstQualifierInScope = nullptr;

clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,19 @@ namespace N3 {
471471
this->C::operator=(*this);
472472
}
473473
};
474+
475+
template<typename T>
476+
struct D {
477+
auto not_instantiated() -> decltype(operator=(0)); // expected-error {{use of undeclared 'operator='}}
478+
};
479+
480+
template<typename T>
481+
struct E {
482+
auto instantiated(E& e) -> decltype(operator=(e)); // expected-error {{use of undeclared 'operator='}}
483+
};
484+
485+
template struct E<int>; // expected-note {{in instantiation of template class 'N3::E<int>' requested here}}
486+
474487
} // namespace N3
475488

476489
namespace N4 {

0 commit comments

Comments
 (0)