Skip to content

Commit 5548ea3

Browse files
authored
[Clang] Instantiate local constexpr functions eagerly (llvm#95660)
We had a code path in `Sema::MarkFunctionReferenced()` that deferred local lambda instantiation even for constexprs. This resulted in any calls to them referring to function decls that lack bodies and hence failures at constant evaluation. The issue doesn't occur when the lambda has no explicit return type because the return type deduction requires instantiation. Fixes llvm#35052 Fixes llvm#94849
1 parent d442bf0 commit 5548ea3

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,7 @@ Bug Fixes to C++ Support
858858
- Fixed several bugs in capturing variables within unevaluated contexts. (#GH63845), (#GH67260), (#GH69307),
859859
(#GH88081), (#GH89496), (#GH90669) and (#GH91633).
860860
- Fixed handling of brace ellison when building deduction guides. (#GH64625), (#GH83368).
861+
- Clang now instantiates local constexpr functions eagerly for constant evaluators. (#GH35052), (#GH94849)
861862

862863
Bug Fixes to AST Handling
863864
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaExpr.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18112,16 +18112,17 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
1811218112

1811318113
if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
1811418114
Func->isConstexpr()) {
18115-
if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
18116-
cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
18117-
CodeSynthesisContexts.size())
18118-
PendingLocalImplicitInstantiations.push_back(
18119-
std::make_pair(Func, PointOfInstantiation));
18120-
else if (Func->isConstexpr())
18115+
if (Func->isConstexpr())
1812118116
// Do not defer instantiations of constexpr functions, to avoid the
1812218117
// expression evaluator needing to call back into Sema if it sees a
1812318118
// call to such a function.
1812418119
InstantiateFunctionDefinition(PointOfInstantiation, Func);
18120+
else if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
18121+
cast<CXXRecordDecl>(Func->getDeclContext())
18122+
->isLocalClass() &&
18123+
CodeSynthesisContexts.size())
18124+
PendingLocalImplicitInstantiations.push_back(
18125+
std::make_pair(Func, PointOfInstantiation));
1812518126
else {
1812618127
Func->setInstantiationIsPending(true);
1812718128
PendingInstantiations.push_back(

clang/test/SemaTemplate/instantiate-local-class.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// RUN: %clang_cc1 -verify -std=c++11 %s
22
// RUN: %clang_cc1 -verify -std=c++11 -fdelayed-template-parsing %s
3+
// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s
34

45
template<typename T>
56
void f0() {
@@ -509,3 +510,26 @@ namespace LambdaInDefaultMemberInitializer {
509510
}
510511
template void f<int>();
511512
}
513+
514+
#if __cplusplus >= 201703L
515+
namespace GH35052 {
516+
517+
template <typename F> constexpr int func(F f) {
518+
if constexpr (f(1UL)) {
519+
return 1;
520+
}
521+
return 0;
522+
}
523+
524+
int main() {
525+
auto predicate = [](auto v) /*implicit constexpr*/ -> bool {
526+
return v == 1;
527+
};
528+
529+
static_assert(predicate(1));
530+
return func(predicate);
531+
}
532+
533+
} // namespace GH35052
534+
535+
#endif

0 commit comments

Comments
 (0)