Skip to content

Commit 75ebcbf

Browse files
authored
[Clang][Sema] Revert changes to operator= lookup in templated classes from #91498, #90999, and #90152 (#91620)
This reverts changes in #91498, #90999, and #90152 which make `operator=` dependent whenever the current class is templated.
1 parent d36b4ab commit 75ebcbf

File tree

4 files changed

+28
-38
lines changed

4 files changed

+28
-38
lines changed

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
996996
// build a CXXDependentScopeMemberExpr.
997997
if (R.wasNotFoundInCurrentInstantiation() ||
998998
(IsArrow && !BaseExprType->isPointerType() &&
999-
BaseExprType->isDependentType()))
999+
BaseExprType->isDependentType()) ||
1000+
(R.getLookupName().getCXXOverloadedOperator() == OO_Equal &&
1001+
(SS.isSet() ? SS.getScopeRep()->isDependent()
1002+
: BaseExprType->isDependentType())))
10001003
return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
10011004
TemplateKWLoc, FirstQualifierInScope,
10021005
R.getLookupNameInfo(), TemplateArgs);

clang/lib/Sema/SemaLookup.cpp

Lines changed: 17 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,20 +1267,6 @@ 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-
}
12841270
} // end anonymous namespace
12851271

12861272
bool Sema::CppLookupName(LookupResult &R, Scope *S) {
@@ -1289,6 +1275,14 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
12891275
DeclarationName Name = R.getLookupName();
12901276
Sema::LookupNameKind NameKind = R.getLookupKind();
12911277

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+
}
1285+
12921286
// C++23 [temp.dep.general]p2:
12931287
// The component name of an unqualified-id is dependent if
12941288
// - it is a conversion-function-id whose conversion-type-id
@@ -1301,20 +1295,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
13011295
return false;
13021296
}
13031297

1304-
// If this is the name of an implicitly-declared special member function,
1305-
// go through the scope stack to implicitly declare
1306-
if (isImplicitlyDeclaredMemberFunctionName(Name)) {
1307-
for (Scope *PreS = S; PreS; PreS = PreS->getParent())
1308-
if (DeclContext *DC = PreS->getEntity()) {
1309-
if (!R.isTemplateNameLookup() &&
1310-
isDependentAssignmentOperator(Name, DC)) {
1311-
R.setNotFoundInCurrentInstantiation();
1312-
return false;
1313-
}
1314-
DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
1315-
}
1316-
}
1317-
13181298
// Implicitly declare member functions with the name we're looking for, if in
13191299
// fact we are in a scope where it matters.
13201300

@@ -2478,6 +2458,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
24782458
}
24792459
} QL(LookupCtx);
24802460

2461+
CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx);
2462+
// FIXME: Per [temp.dep.general]p2, an unqualified name is also dependent
2463+
// if it's a dependent conversion-function-id or operator= where the current
2464+
// class is a templated entity. This should be handled in LookupName.
24812465
if (!InUnqualifiedLookup && !R.isForRedeclaration()) {
24822466
// C++23 [temp.dep.type]p5:
24832467
// A qualified name is dependent if
@@ -2488,16 +2472,13 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
24882472
// is operator=, or
24892473
// - [...]
24902474
if (DeclarationName Name = R.getLookupName();
2491-
(Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
2492-
Name.getCXXNameType()->isDependentType()) ||
2493-
(!R.isTemplateNameLookup() &&
2494-
isDependentAssignmentOperator(Name, LookupCtx))) {
2475+
Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
2476+
Name.getCXXNameType()->isDependentType()) {
24952477
R.setNotFoundInCurrentInstantiation();
24962478
return false;
24972479
}
24982480
}
24992481

2500-
CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx);
25012482
if (LookupDirect(*this, R, LookupCtx)) {
25022483
R.resolveKind();
25032484
if (LookupRec)
@@ -2588,6 +2569,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
25882569
return true;
25892570
};
25902571

2572+
bool TemplateNameLookup = R.isTemplateNameLookup();
2573+
25912574
// Determine whether two sets of members contain the same members, as
25922575
// required by C++ [class.member.lookup]p6.
25932576
auto HasSameDeclarations = [&](DeclContext::lookup_iterator A,
@@ -2609,7 +2592,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
26092592
// template, and if the name is used as a template-name, the
26102593
// reference refers to the class template itself and not a
26112594
// specialization thereof, and is not ambiguous.
2612-
if (R.isTemplateNameLookup())
2595+
if (TemplateNameLookup)
26132596
if (auto *TD = getAsTemplateNameDecl(ND))
26142597
ND = TD;
26152598

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 6 additions & 2 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-
QualType ThisType = getCurrentThisType();
729+
DeclContext *DC = getFunctionLevelDeclContext();
730730

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

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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,6 @@ namespace N3 {
483483
};
484484

485485
template struct E<int>; // expected-note {{in instantiation of template class 'N3::E<int>' requested here}}
486-
487486
} // namespace N3
488487

489488
namespace N4 {
@@ -551,4 +550,5 @@ namespace N4 {
551550
};
552551

553552
template void D<B>::instantiated(D); // expected-note {{in instantiation of}}
553+
554554
} // namespace N4

0 commit comments

Comments
 (0)