Revert "[clang] Track function template instantiation from definition (#110387)" (#111764)

This reverts commit 4336f00f2156970cc0af2816331387a0a4039317.
This commit is contained in:
Krystian Stasiowski 2024-10-09 15:43:55 -06:00 committed by GitHub
parent ac3321f104
commit 91dd4ec20e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 26 additions and 169 deletions

View File

@ -468,7 +468,6 @@ Bug Fixes to C++ Support
- Fixed an assertion failure in debug mode, and potential crashes in release mode, when
diagnosing a failed cast caused indirectly by a failed implicit conversion to the type of the constructor parameter.
- Fixed an assertion failure by adjusting integral to boolean vector conversions (#GH108326)
- Clang is now better at keeping track of friend function template instance contexts. (#GH55509)
- Fixed an issue deducing non-type template arguments of reference type. (#GH73460)
- Fixed an issue in constraint evaluation, where type constraints on the lambda expression
containing outer unexpanded parameters were not correctly expanded. (#GH101754)

View File

@ -2299,13 +2299,6 @@ public:
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

View File

@ -1763,8 +1763,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)
@ -1815,7 +1813,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
@ -1826,12 +1824,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;
@ -1845,7 +1843,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

View File

@ -1008,15 +1008,6 @@ public:
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,

View File

@ -13017,12 +13017,6 @@ public:
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
bool RelativeToPrimary = false, bool ForConstraintInstantiation = false);
void getTemplateInstantiationArgs(
MultiLevelTemplateArgumentList &Result, const NamedDecl *D,
const DeclContext *DC = nullptr, bool Final = false,
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
bool RelativeToPrimary = false, bool ForConstraintInstantiation = false);
/// RAII object to handle the state changes required to synthesize
/// a function body.
class SynthesizedFunctionScope {

View File

@ -3067,7 +3067,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;

View File

@ -3928,7 +3928,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);

View File

@ -512,13 +512,13 @@ struct TemplateInstantiationArgumentCollecter
} // namespace
void Sema::getTemplateInstantiationArgs(
MultiLevelTemplateArgumentList &Result, const NamedDecl *ND,
const DeclContext *DC, bool Final,
MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
const NamedDecl *ND, const DeclContext *DC, bool Final,
std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
bool ForConstraintInstantiation) {
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
const Decl *CurDecl = ND;
if (!CurDecl)
@ -529,17 +529,6 @@ void Sema::getTemplateInstantiationArgs(
do {
CurDecl = Collecter.Visit(const_cast<Decl *>(CurDecl));
} while (CurDecl);
}
MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
const NamedDecl *ND, const DeclContext *DC, bool Final,
std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
bool ForConstraintInstantiation) {
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
getTemplateInstantiationArgs(Result, ND, DC, Final, Innermost,
RelativeToPrimary, ForConstraintInstantiation);
return Result;
}

View File

@ -5224,26 +5224,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
RebuildTypeSourceInfoForDefaultSpecialMembers();
SetDeclDefaulted(Function, PatternDecl->getLocation());
} else {
DeclContext *DC = Function;
MultiLevelTemplateArgumentList TemplateArgs;
if (auto *Primary = Function->getPrimaryTemplate();
Primary &&
!isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) {
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();
if (Function->getTemplateSpecializationKind() !=
TSK_ExplicitSpecialization)
TemplateArgs.addOuterTemplateArguments(
Function, Function->getTemplateSpecializationArgs()->asArray(),
/*Final=*/false);
}
getTemplateInstantiationArgs(TemplateArgs, /*D=*/nullptr, DC);
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
Function, Function->getLexicalDeclContext());
// Substitute into the qualifier; we can get a substitution failure here
// through evil use of alias templates.

View File

@ -1087,7 +1087,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());

View File

@ -626,7 +626,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");
@ -732,7 +732,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);

View File

@ -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