Skip to content

Commit ac60b8c

Browse files
zyn0217jph-13
authored andcommitted
[Clang] Don't give up on an unsuccessful function instantiation (llvm#126723)
For constexpr function templates, we immediately instantiate them upon reference. However, if the function isn't defined at the time of instantiation, even though it might be defined later, the instantiation would forever fail. This patch corrects the behavior by popping up failed instantiations through PendingInstantiations, so that we are able to instantiate them again in the future (e.g. at the end of TU.) Fixes llvm#125747
1 parent 64857ea commit ac60b8c

File tree

5 files changed

+69
-27
lines changed

5 files changed

+69
-27
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ Bug Fixes to C++ Support
264264
- Clang is now better at keeping track of friend function template instance contexts. (#GH55509)
265265
- Clang now prints the correct instantiation context for diagnostics suppressed
266266
by template argument deduction.
267+
- Clang is now better at instantiating the function definition after its use inside
268+
of a constexpr lambda. (#GH125747)
267269
- The initialization kind of elements of structured bindings
268270
direct-list-initialized from an array is corrected to direct-initialization.
269271
- Clang no longer crashes when a coroutine is declared ``[[noreturn]]``. (#GH127327)

clang/include/clang/Sema/Sema.h

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13657,12 +13657,16 @@ class Sema final : public SemaBase {
1365713657

1365813658
class LocalEagerInstantiationScope {
1365913659
public:
13660-
LocalEagerInstantiationScope(Sema &S) : S(S) {
13660+
LocalEagerInstantiationScope(Sema &S, bool AtEndOfTU)
13661+
: S(S), AtEndOfTU(AtEndOfTU) {
1366113662
SavedPendingLocalImplicitInstantiations.swap(
1366213663
S.PendingLocalImplicitInstantiations);
1366313664
}
1366413665

13665-
void perform() { S.PerformPendingInstantiations(/*LocalOnly=*/true); }
13666+
void perform() {
13667+
S.PerformPendingInstantiations(/*LocalOnly=*/true,
13668+
/*AtEndOfTU=*/AtEndOfTU);
13669+
}
1366613670

1366713671
~LocalEagerInstantiationScope() {
1366813672
assert(S.PendingLocalImplicitInstantiations.empty() &&
@@ -13673,6 +13677,7 @@ class Sema final : public SemaBase {
1367313677

1367413678
private:
1367513679
Sema &S;
13680+
bool AtEndOfTU;
1367613681
std::deque<PendingImplicitInstantiation>
1367713682
SavedPendingLocalImplicitInstantiations;
1367813683
};
@@ -13695,8 +13700,8 @@ class Sema final : public SemaBase {
1369513700

1369613701
class GlobalEagerInstantiationScope {
1369713702
public:
13698-
GlobalEagerInstantiationScope(Sema &S, bool Enabled)
13699-
: S(S), Enabled(Enabled) {
13703+
GlobalEagerInstantiationScope(Sema &S, bool Enabled, bool AtEndOfTU)
13704+
: S(S), Enabled(Enabled), AtEndOfTU(AtEndOfTU) {
1370013705
if (!Enabled)
1370113706
return;
1370213707

@@ -13710,7 +13715,8 @@ class Sema final : public SemaBase {
1371013715
void perform() {
1371113716
if (Enabled) {
1371213717
S.DefineUsedVTables();
13713-
S.PerformPendingInstantiations();
13718+
S.PerformPendingInstantiations(/*LocalOnly=*/false,
13719+
/*AtEndOfTU=*/AtEndOfTU);
1371413720
}
1371513721
}
1371613722

@@ -13725,7 +13731,8 @@ class Sema final : public SemaBase {
1372513731
S.SavedVTableUses.pop_back();
1372613732

1372713733
// Restore the set of pending implicit instantiations.
13728-
if (S.TUKind != TU_Prefix || !S.LangOpts.PCHInstantiateTemplates) {
13734+
if ((S.TUKind != TU_Prefix || !S.LangOpts.PCHInstantiateTemplates) &&
13735+
AtEndOfTU) {
1372913736
assert(S.PendingInstantiations.empty() &&
1373013737
"PendingInstantiations should be empty before it is discarded.");
1373113738
S.PendingInstantiations.swap(S.SavedPendingInstantiations.back());
@@ -13744,6 +13751,7 @@ class Sema final : public SemaBase {
1374413751
private:
1374513752
Sema &S;
1374613753
bool Enabled;
13754+
bool AtEndOfTU;
1374713755
};
1374813756

1374913757
ExplicitSpecifier instantiateExplicitSpecifier(
@@ -13929,7 +13937,8 @@ class Sema final : public SemaBase {
1392913937

1393013938
/// Performs template instantiation for all implicit template
1393113939
/// instantiations we have seen until this point.
13932-
void PerformPendingInstantiations(bool LocalOnly = false);
13940+
void PerformPendingInstantiations(bool LocalOnly = false,
13941+
bool AtEndOfTU = true);
1393313942

1393413943
TemplateParameterList *
1393513944
SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner,

clang/lib/Interpreter/IncrementalParser.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ llvm::Expected<TranslationUnitDecl *>
4141
IncrementalParser::ParseOrWrapTopLevelDecl() {
4242
// Recover resources if we crash before exiting this method.
4343
llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
44-
Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true);
45-
Sema::LocalEagerInstantiationScope LocalInstantiations(S);
44+
Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true,
45+
/*AtEndOfTU=*/true);
46+
Sema::LocalEagerInstantiationScope LocalInstantiations(S, /*AtEndOfTU=*/true);
4647

4748
// Add a new PTU.
4849
ASTContext &C = S.getASTContext();

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,7 +2362,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
23622362
// DR1484 clarifies that the members of a local class are instantiated as part
23632363
// of the instantiation of their enclosing entity.
23642364
if (D->isCompleteDefinition() && D->isLocalClass()) {
2365-
Sema::LocalEagerInstantiationScope LocalInstantiations(SemaRef);
2365+
Sema::LocalEagerInstantiationScope LocalInstantiations(SemaRef,
2366+
/*AtEndOfTU=*/false);
23662367

23672368
SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs,
23682369
TSK_ImplicitInstantiation,
@@ -5344,8 +5345,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
53445345
// This has to happen before LateTemplateParser below is called, so that
53455346
// it marks vtables used in late parsed templates as used.
53465347
GlobalEagerInstantiationScope GlobalInstantiations(*this,
5347-
/*Enabled=*/Recursive);
5348-
LocalEagerInstantiationScope LocalInstantiations(*this);
5348+
/*Enabled=*/Recursive,
5349+
/*AtEndOfTU=*/AtEndOfTU);
5350+
LocalEagerInstantiationScope LocalInstantiations(*this,
5351+
/*AtEndOfTU=*/AtEndOfTU);
53495352

53505353
// Call the LateTemplateParser callback if there is a need to late parse
53515354
// a templated function definition.
@@ -5919,10 +5922,12 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
59195922
// If we're performing recursive template instantiation, create our own
59205923
// queue of pending implicit instantiations that we will instantiate
59215924
// later, while we're still within our own instantiation context.
5922-
GlobalEagerInstantiationScope GlobalInstantiations(*this,
5923-
/*Enabled=*/Recursive);
5925+
GlobalEagerInstantiationScope GlobalInstantiations(
5926+
*this,
5927+
/*Enabled=*/Recursive, /*AtEndOfTU=*/AtEndOfTU);
59245928
LocalInstantiationScope Local(*this);
5925-
LocalEagerInstantiationScope LocalInstantiations(*this);
5929+
LocalEagerInstantiationScope LocalInstantiations(*this,
5930+
/*AtEndOfTU=*/AtEndOfTU);
59265931

59275932
// Enter the scope of this instantiation. We don't use
59285933
// PushDeclContext because we don't have a scope.
@@ -6019,14 +6024,16 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
60196024
// queue of pending implicit instantiations that we will instantiate later,
60206025
// while we're still within our own instantiation context.
60216026
GlobalEagerInstantiationScope GlobalInstantiations(*this,
6022-
/*Enabled=*/Recursive);
6027+
/*Enabled=*/Recursive,
6028+
/*AtEndOfTU=*/AtEndOfTU);
60236029

60246030
// Enter the scope of this instantiation. We don't use
60256031
// PushDeclContext because we don't have a scope.
60266032
ContextRAII PreviousContext(*this, Var->getDeclContext());
60276033
LocalInstantiationScope Local(*this);
60286034

6029-
LocalEagerInstantiationScope LocalInstantiations(*this);
6035+
LocalEagerInstantiationScope LocalInstantiations(*this,
6036+
/*AtEndOfTU=*/AtEndOfTU);
60306037

60316038
VarDecl *OldVar = Var;
60326039
if (Def->isStaticDataMember() && !Def->isOutOfLine()) {
@@ -6774,18 +6781,20 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
67746781
return D;
67756782
}
67766783

6777-
void Sema::PerformPendingInstantiations(bool LocalOnly) {
6778-
std::deque<PendingImplicitInstantiation> delayedPCHInstantiations;
6784+
void Sema::PerformPendingInstantiations(bool LocalOnly, bool AtEndOfTU) {
6785+
std::deque<PendingImplicitInstantiation> DelayedImplicitInstantiations;
67796786
while (!PendingLocalImplicitInstantiations.empty() ||
67806787
(!LocalOnly && !PendingInstantiations.empty())) {
67816788
PendingImplicitInstantiation Inst;
67826789

6790+
bool LocalInstantiation = false;
67836791
if (PendingLocalImplicitInstantiations.empty()) {
67846792
Inst = PendingInstantiations.front();
67856793
PendingInstantiations.pop_front();
67866794
} else {
67876795
Inst = PendingLocalImplicitInstantiations.front();
67886796
PendingLocalImplicitInstantiations.pop_front();
6797+
LocalInstantiation = true;
67896798
}
67906799

67916800
// Instantiate function definitions
@@ -6794,22 +6803,26 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
67946803
TSK_ExplicitInstantiationDefinition;
67956804
if (Function->isMultiVersion()) {
67966805
getASTContext().forEachMultiversionedFunctionVersion(
6797-
Function, [this, Inst, DefinitionRequired](FunctionDecl *CurFD) {
6806+
Function,
6807+
[this, Inst, DefinitionRequired, AtEndOfTU](FunctionDecl *CurFD) {
67986808
InstantiateFunctionDefinition(/*FIXME:*/ Inst.second, CurFD, true,
6799-
DefinitionRequired, true);
6809+
DefinitionRequired, AtEndOfTU);
68006810
if (CurFD->isDefined())
68016811
CurFD->setInstantiationIsPending(false);
68026812
});
68036813
} else {
68046814
InstantiateFunctionDefinition(/*FIXME:*/ Inst.second, Function, true,
6805-
DefinitionRequired, true);
6815+
DefinitionRequired, AtEndOfTU);
68066816
if (Function->isDefined())
68076817
Function->setInstantiationIsPending(false);
68086818
}
68096819
// Definition of a PCH-ed template declaration may be available only in the TU.
68106820
if (!LocalOnly && LangOpts.PCHInstantiateTemplates &&
68116821
TUKind == TU_Prefix && Function->instantiationIsPending())
6812-
delayedPCHInstantiations.push_back(Inst);
6822+
DelayedImplicitInstantiations.push_back(Inst);
6823+
else if (!AtEndOfTU && Function->instantiationIsPending() &&
6824+
!LocalInstantiation)
6825+
DelayedImplicitInstantiations.push_back(Inst);
68136826
continue;
68146827
}
68156828

@@ -6853,11 +6866,11 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
68536866
// Instantiate static data member definitions or variable template
68546867
// specializations.
68556868
InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true,
6856-
DefinitionRequired, true);
6869+
DefinitionRequired, AtEndOfTU);
68576870
}
68586871

6859-
if (!LocalOnly && LangOpts.PCHInstantiateTemplates)
6860-
PendingInstantiations.swap(delayedPCHInstantiations);
6872+
if (!DelayedImplicitInstantiations.empty())
6873+
PendingInstantiations.swap(DelayedImplicitInstantiations);
68616874
}
68626875

68636876
void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,

clang/test/CodeGenCXX/function-template-specialization.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple %s -o - | FileCheck %s
1+
// RUN: %clang_cc1 -emit-llvm -Wundefined-func-template -verify -triple %itanium_abi_triple %s -o - | FileCheck %s
2+
// expected-no-diagnostics
23

34
// CHECK-DAG: _ZZN7PR219047GetDataIiEERKibE1i = internal global i32 4
45
// CHECK-DAG: _ZZN7PR219047GetDataIiEERKibE1i_0 = internal global i32 2
@@ -43,3 +44,19 @@ const int &GetData<int>(bool b) {
4344
return i;
4445
}
4546
}
47+
48+
namespace GH125747 {
49+
50+
template<typename F> constexpr int visit(F f) { return f(0); }
51+
52+
template <class T> int G(T t);
53+
54+
int main() { return visit([](auto s) -> int { return G(s); }); }
55+
56+
template <class T> int G(T t) {
57+
return 0;
58+
}
59+
60+
// CHECK: define {{.*}} @_ZN8GH1257471GIiEEiT_
61+
62+
}

0 commit comments

Comments
 (0)