Author: Krystian Stasiowski Date: 2024-05-08T20:49:59-04:00 New Revision: 62b5b61f436add042d8729dc9837d055613180d9
URL: https://github.com/llvm/llvm-project/commit/62b5b61f436add042d8729dc9837d055613180d9 DIFF: https://github.com/llvm/llvm-project/commit/62b5b61f436add042d8729dc9837d055613180d9.diff LOG: [Clang][Sema] Fix lookup of dependent operator= outside of complete-class contexts (#91498) Fixes a crash caused by #90152. Added: Modified: clang/lib/Sema/SemaLookup.cpp clang/lib/Sema/SemaTemplate.cpp clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index e63da5875d2c9..e20de338ebb16 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1267,6 +1267,20 @@ struct FindLocalExternScope { LookupResult &R; bool OldFindLocalExtern; }; + +/// Returns true if 'operator=' should be treated as a dependent name. +bool isDependentAssignmentOperator(DeclarationName Name, + DeclContext *LookupContext) { + const auto *LookupRecord = dyn_cast_if_present<CXXRecordDecl>(LookupContext); + // If the lookup context is the current instantiation but we are outside a + // complete-class context, we will never find the implicitly declared + // copy/move assignment operators because they are declared at the closing '}' + // of the class specifier. In such cases, we treat 'operator=' like any other + // unqualified name because the results of name lookup in the template + // definition/instantiation context will always be the same. + return Name.getCXXOverloadedOperator() == OO_Equal && LookupRecord && + !LookupRecord->isBeingDefined() && LookupRecord->isDependentContext(); +} } // end anonymous namespace bool Sema::CppLookupName(LookupResult &R, Scope *S) { @@ -1275,13 +1289,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { DeclarationName Name = R.getLookupName(); Sema::LookupNameKind NameKind = R.getLookupKind(); - // If this is the name of an implicitly-declared special member function, - // go through the scope stack to implicitly declare - if (isImplicitlyDeclaredMemberFunctionName(Name)) { - for (Scope *PreS = S; PreS; PreS = PreS->getParent()) - if (DeclContext *DC = PreS->getEntity()) - DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC); - } // C++23 [temp.dep.general]p2: // The component name of an unqualified-id is dependent if // - it is a conversion-function-id whose conversion-type-id @@ -1299,9 +1306,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { if (isImplicitlyDeclaredMemberFunctionName(Name)) { for (Scope *PreS = S; PreS; PreS = PreS->getParent()) if (DeclContext *DC = PreS->getEntity()) { - if (DC->isDependentContext() && isa<CXXRecordDecl>(DC) && - Name.getCXXOverloadedOperator() == OO_Equal && - !R.isTemplateNameLookup()) { + if (!R.isTemplateNameLookup() && + isDependentAssignmentOperator(Name, DC)) { R.setNotFoundInCurrentInstantiation(); return false; } @@ -2472,8 +2478,6 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, } } QL(LookupCtx); - bool TemplateNameLookup = R.isTemplateNameLookup(); - CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx); if (!InUnqualifiedLookup && !R.isForRedeclaration()) { // C++23 [temp.dep.type]p5: // A qualified name is dependent if @@ -2486,13 +2490,14 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, if (DeclarationName Name = R.getLookupName(); (Name.getNameKind() == DeclarationName::CXXConversionFunctionName && Name.getCXXNameType()->isDependentType()) || - (Name.getCXXOverloadedOperator() == OO_Equal && LookupRec && - LookupRec->isDependentContext() && !TemplateNameLookup)) { + (!R.isTemplateNameLookup() && + isDependentAssignmentOperator(Name, LookupCtx))) { R.setNotFoundInCurrentInstantiation(); return false; } } + CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx); if (LookupDirect(*this, R, LookupCtx)) { R.resolveKind(); if (LookupRec) @@ -2604,7 +2609,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // template, and if the name is used as a template-name, the // reference refers to the class template itself and not a // specialization thereof, and is not ambiguous. - if (TemplateNameLookup) + if (R.isTemplateNameLookup()) if (auto *TD = getAsTemplateNameDecl(ND)) ND = TD; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 7e57fa0696725..480bc74c2001a 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -726,7 +726,7 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs) { - DeclContext *DC = getFunctionLevelDeclContext(); + QualType ThisType = getCurrentThisType(); // C++11 [expr.prim.general]p12: // An id-expression that denotes a non-static data member or non-static @@ -748,10 +748,7 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, IsEnum = isa_and_nonnull<EnumType>(NNS->getAsType()); if (!MightBeCxx11UnevalField && !isAddressOfOperand && !IsEnum && - isa<CXXMethodDecl>(DC) && - cast<CXXMethodDecl>(DC)->isImplicitObjectMemberFunction()) { - QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType().getNonReferenceType(); - + !ThisType.isNull()) { // Since the 'this' expression is synthesized, we don't need to // perform the double-lookup check. NamedDecl *FirstQualifierInScope = nullptr; diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp index 46dd52f8c4c13..43053c18c5076 100644 --- a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp +++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp @@ -471,6 +471,19 @@ namespace N3 { this->C::operator=(*this); } }; + + template<typename T> + struct D { + auto not_instantiated() -> decltype(operator=(0)); // expected-error {{use of undeclared 'operator='}} + }; + + template<typename T> + struct E { + auto instantiated(E& e) -> decltype(operator=(e)); // expected-error {{use of undeclared 'operator='}} + }; + + template struct E<int>; // expected-note {{in instantiation of template class 'N3::E<int>' requested here}} + } // namespace N3 namespace N4 { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits