Author: Martin Storsjö Date: 2025-01-30T12:05:56+02:00 New Revision: 5c24847e7dba01dde230e18b39a3074022279c89
URL: https://github.com/llvm/llvm-project/commit/5c24847e7dba01dde230e18b39a3074022279c89 DIFF: https://github.com/llvm/llvm-project/commit/5c24847e7dba01dde230e18b39a3074022279c89.diff LOG: Revert "[clang] Track function template instantiation from definition (#112241)" This reverts commit 07a0e2be86f33beb6d519a3d466b95c2257e93cb. This change broke compiling Qt; see https://github.com/llvm/llvm-project/pull/112241 for details. Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/AST/Decl.h clang/include/clang/AST/DeclBase.h clang/include/clang/AST/DeclTemplate.h clang/lib/AST/Decl.cpp clang/lib/Sema/SemaTemplateDeduction.cpp clang/lib/Sema/SemaTemplateInstantiate.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/lib/Serialization/ASTReaderDecl.cpp clang/lib/Serialization/ASTWriterDecl.cpp Removed: clang/test/SemaTemplate/GH55509.cpp ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b8b47103d95177..d754c49f2aa3a4 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -128,8 +128,6 @@ Bug Fixes to Attribute Support Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ -- Clang is now better at keeping track of friend function template instance contexts. (#GH55509) - Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index f305cbbce4c609..499d27a9be5a8a 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2298,13 +2298,6 @@ class FunctionDecl : public DeclaratorDecl, FunctionDeclBits.IsLateTemplateParsed = ILT; } - bool isInstantiatedFromMemberTemplate() const { - return FunctionDeclBits.IsInstantiatedFromMemberTemplate; - } - void setInstantiatedFromMemberTemplate(bool Val = true) { - FunctionDeclBits.IsInstantiatedFromMemberTemplate = Val; - } - /// Whether this function is "trivial" in some specialized C++ senses. /// Can only be true for default constructors, copy constructors, /// copy assignment operators, and destructors. Not meaningful until diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 3a13309a6100ee..2c0c3a8dc2f9d5 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -1777,8 +1777,6 @@ class DeclContext { uint64_t HasImplicitReturnZero : 1; LLVM_PREFERRED_TYPE(bool) uint64_t IsLateTemplateParsed : 1; - LLVM_PREFERRED_TYPE(bool) - uint64_t IsInstantiatedFromMemberTemplate : 1; /// Kind of contexpr specifier as defined by ConstexprSpecKind. LLVM_PREFERRED_TYPE(ConstexprSpecKind) @@ -1829,7 +1827,7 @@ class DeclContext { }; /// Number of inherited and non-inherited bits in FunctionDeclBitfields. - enum { NumFunctionDeclBits = NumDeclContextBits + 32 }; + enum { NumFunctionDeclBits = NumDeclContextBits + 31 }; /// Stores the bits used by CXXConstructorDecl. If modified /// NumCXXConstructorDeclBits and the accessor @@ -1840,12 +1838,12 @@ class DeclContext { LLVM_PREFERRED_TYPE(FunctionDeclBitfields) uint64_t : NumFunctionDeclBits; - /// 19 bits to fit in the remaining available space. + /// 20 bits to fit in the remaining available space. /// Note that this makes CXXConstructorDeclBitfields take /// exactly 64 bits and thus the width of NumCtorInitializers /// will need to be shrunk if some bit is added to NumDeclContextBitfields, /// NumFunctionDeclBitfields or CXXConstructorDeclBitfields. - uint64_t NumCtorInitializers : 16; + uint64_t NumCtorInitializers : 17; LLVM_PREFERRED_TYPE(bool) uint64_t IsInheritingConstructor : 1; @@ -1859,7 +1857,7 @@ class DeclContext { }; /// Number of inherited and non-inherited bits in CXXConstructorDeclBitfields. - enum { NumCXXConstructorDeclBits = NumFunctionDeclBits + 19 }; + enum { NumCXXConstructorDeclBits = NumFunctionDeclBits + 20 }; /// Stores the bits used by ObjCMethodDecl. /// If modified NumObjCMethodDeclBits and the accessor diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 0c706036ff7022..9ecff2c898acd5 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1011,15 +1011,6 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl { return getTemplatedDecl()->isThisDeclarationADefinition(); } - bool isCompatibleWithDefinition() const { - return getTemplatedDecl()->isInstantiatedFromMemberTemplate() || - isThisDeclarationADefinition(); - } - void setInstantiatedFromMemberTemplate(FunctionTemplateDecl *D) { - getTemplatedDecl()->setInstantiatedFromMemberTemplate(); - RedeclarableTemplateDecl::setInstantiatedFromMemberTemplate(D); - } - /// Return the specialization with the provided arguments if it exists, /// otherwise return the insertion point. FunctionDecl *findSpecialization(ArrayRef<TemplateArgument> Args, diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 610207cf8b9a4a..7e8a172ae4c37f 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3065,7 +3065,6 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, FunctionDeclBits.IsIneligibleOrNotSelected = false; FunctionDeclBits.HasImplicitReturnZero = false; FunctionDeclBits.IsLateTemplateParsed = false; - FunctionDeclBits.IsInstantiatedFromMemberTemplate = false; FunctionDeclBits.ConstexprKind = static_cast<uint64_t>(ConstexprKind); FunctionDeclBits.BodyContainsImmediateEscalatingExpression = false; FunctionDeclBits.InstantiationIsPending = false; diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 6aaf86a6a6ff36..137942f0c30bfe 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -4074,7 +4074,22 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( if (FunctionTemplate->getFriendObjectKind()) Owner = FunctionTemplate->getLexicalDeclContext(); FunctionDecl *FD = FunctionTemplate->getTemplatedDecl(); - + // additional check for inline friend, + // ``` + // template <class F1> int foo(F1 X); + // template <int A1> struct A { + // template <class F1> friend int foo(F1 X) { return A1; } + // }; + // template struct A<1>; + // int a = foo(1.0); + // ``` + const FunctionDecl *FDFriend; + if (FD->getFriendObjectKind() == Decl::FriendObjectKind::FOK_None && + FD->isDefined(FDFriend, /*CheckForPendingFriendDefinition*/ true) && + FDFriend->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None) { + FD = const_cast<FunctionDecl *>(FDFriend); + Owner = FD->getLexicalDeclContext(); + } MultiLevelTemplateArgumentList SubstArgs( FunctionTemplate, CanonicalDeducedArgumentList->asArray(), /*Final=*/false); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 12e98a33d07853..dc3bfa97eff399 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -479,6 +479,9 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( using namespace TemplateInstArgsHelpers; const Decl *CurDecl = ND; + if (!CurDecl) + CurDecl = Decl::castFromDeclContext(DC); + if (Innermost) { Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), *Innermost, Final); @@ -492,10 +495,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( // has a depth of 0. if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) HandleDefaultTempArgIntoTempTempParam(TTP, Result); - CurDecl = DC ? Decl::castFromDeclContext(DC) - : Response::UseNextDecl(CurDecl).NextDecl; - } else if (!CurDecl) - CurDecl = Decl::castFromDeclContext(DC); + CurDecl = Response::UseNextDecl(CurDecl).NextDecl; + } while (!CurDecl->isFileContextDecl()) { Response R; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index d530ed0847ae86..4855e8a23689ce 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -12,7 +12,6 @@ #include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DependentDiagnostic.h" @@ -5277,26 +5276,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, RebuildTypeSourceInfoForDefaultSpecialMembers(); SetDeclDefaulted(Function, PatternDecl->getLocation()); } else { - NamedDecl *ND = Function; - DeclContext *DC = ND->getLexicalDeclContext(); - std::optional<ArrayRef<TemplateArgument>> Innermost; - if (auto *Primary = Function->getPrimaryTemplate(); - Primary && - !isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function) && - Function->getTemplateSpecializationKind() != - TSK_ExplicitSpecialization) { - auto It = llvm::find_if(Primary->redecls(), - [](const RedeclarableTemplateDecl *RTD) { - return cast<FunctionTemplateDecl>(RTD) - ->isCompatibleWithDefinition(); - }); - assert(It != Primary->redecls().end() && - "Should't get here without a definition"); - DC = (*It)->getLexicalDeclContext(); - Innermost.emplace(Function->getTemplateSpecializationArgs()->asArray()); - } MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs( - Function, DC, /*Final=*/false, Innermost, false, PatternDecl); + Function, Function->getLexicalDeclContext(), /*Final=*/false, + /*Innermost=*/std::nullopt, false, PatternDecl); // Substitute into the qualifier; we can get a substitution failure here // through evil use of alias templates. diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 7a15e60d87d83a..8210eb2143acf5 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1064,7 +1064,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->setHasImplicitReturnZero(FunctionDeclBits.getNextBit()); FD->setIsMultiVersion(FunctionDeclBits.getNextBit()); FD->setLateTemplateParsed(FunctionDeclBits.getNextBit()); - FD->setInstantiatedFromMemberTemplate(FunctionDeclBits.getNextBit()); FD->setFriendConstraintRefersToEnclosingTemplate( FunctionDeclBits.getNextBit()); FD->setUsesSEHTry(FunctionDeclBits.getNextBit()); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 6a79444bdb9892..fa2294da95de8d 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -679,7 +679,7 @@ void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { } void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { - static_assert(DeclContext::NumFunctionDeclBits == 45, + static_assert(DeclContext::NumFunctionDeclBits == 44, "You need to update the serializer after you change the " "FunctionDeclBits"); @@ -785,7 +785,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { FunctionDeclBits.addBit(D->hasImplicitReturnZero()); FunctionDeclBits.addBit(D->isMultiVersion()); FunctionDeclBits.addBit(D->isLateTemplateParsed()); - FunctionDeclBits.addBit(D->isInstantiatedFromMemberTemplate()); FunctionDeclBits.addBit(D->FriendConstraintRefersToEnclosingTemplate()); FunctionDeclBits.addBit(D->usesSEHTry()); Record.push_back(FunctionDeclBits); diff --git a/clang/test/SemaTemplate/GH55509.cpp b/clang/test/SemaTemplate/GH55509.cpp deleted file mode 100644 index f95833fbed7b19..00000000000000 --- a/clang/test/SemaTemplate/GH55509.cpp +++ /dev/null @@ -1,101 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++26 %s - -namespace t1 { - template<int N> struct A { - template<class C> friend auto cica(const A<N-1>&, C) { - return N; - } - }; - - template<> struct A<0> { - template<class C> friend auto cica(const A<0>&, C); - // expected-note@-1 {{declared here}} - }; - - void test() { - cica(A<0>{}, 0); - // expected-error@-1 {{function 'cica<int>' with deduced return type cannot be used before it is defined}} - - (void)A<1>{}; - cica(A<0>{}, 0); - } -} // namespace t1 -namespace t2 { - template<int N> struct A { - template<class C> friend auto cica(const A<N-1>&, C) { - return N; - } - }; - - template<> struct A<0> { - template<class C> friend auto cica(const A<0>&, C); - }; - - template <int N, class = decltype(cica(A<N>{}, nullptr))> - void MakeCica(); - // expected-note@-1 {{candidate function}} - - template <int N> void MakeCica(A<N+1> = {}); - // expected-note@-1 {{candidate function}} - - void test() { - MakeCica<0>(); - - MakeCica<0>(); - // expected-error@-1 {{call to 'MakeCica' is ambiguous}} - } -} // namespace t2 -namespace t3 { - template<int N> struct A { - template<class C> friend auto cica(const A<N-1>&, C) { - return N-1; - } - }; - - template<> struct A<0> { - template<class C> friend auto cica(const A<0>&, C); - }; - - template <int N, class AT, class = decltype(cica(AT{}, nullptr))> - static constexpr bool MakeCica(int); - - template <int N, class AT> - static constexpr bool MakeCica(short, A<N+1> = {}); - - template <int N, class AT = A<N>, class Val = decltype(MakeCica<N, AT>(0))> - static constexpr bool has_cica = Val{}; - - constexpr bool cica2 = has_cica<0> || has_cica<0>; -} // namespace t3 -namespace t4 { - template<int N> struct A { - template<class C> friend auto cica(const A<N-1>&, C); - }; - - template<> struct A<0> { - template<class C> friend auto cica(const A<0>&, C) { - C a; - } - }; - - template struct A<1>; - - void test() { - cica(A<0>{}, 0); - } -} // namespace t4 -namespace regression1 { - template <class> class A; - - template <class T> [[gnu::abi_tag("TAG")]] void foo(A<T>); - - template <class> struct A { - friend void foo <>(A); - }; - - template struct A<int>; - - template <class T> [[gnu::abi_tag("TAG")]] void foo(A<T>) {} - - template void foo<int>(A<int>); -} // namespace regression1 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits