aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorcor3ntin <corentinjabot@gmail.com>2023-11-30 08:45:05 +0100
committerGitHub <noreply@github.com>2023-11-30 08:45:05 +0100
commit030047c432cac133738be68fa0974f70e69dd58d (patch)
tree9e0e500d92fd0a6f05ab250c840fe2dedb0b5574 /clang/lib
parent8a66510fa73c1507c2a58338e180ddb075993a5a (diff)
downloadllvm-030047c432cac133738be68fa0974f70e69dd58d.zip
llvm-030047c432cac133738be68fa0974f70e69dd58d.tar.gz
llvm-030047c432cac133738be68fa0974f70e69dd58d.tar.bz2
[Clang] Eagerly instantiate used constexpr function upon definition. (#73463)
Despite CWG2497 not being resolved, it is reasonable to expect the following code to compile (and which is supported by other compilers) ```cpp template<typename T> constexpr T f(); constexpr int g() { return f<int>(); } // #1 template<typename T> constexpr T f() { return 123; } int k[g()]; // #2 ``` To that end, we eagerly instantiate all referenced specializations of constexpr functions when they are defined. We maintain a map of (pattern, [instantiations]) independent of `PendingInstantiations` to avoid having to iterate that list after each function definition. We should apply the same logic to constexpr variables, but I wanted to keep the PR small. Fixes #73232
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/MultiplexExternalSemaSource.cpp6
-rw-r--r--clang/lib/Sema/SemaDecl.cpp3
-rw-r--r--clang/lib/Sema/SemaExpr.cpp9
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp28
-rw-r--r--clang/lib/Serialization/ASTReader.cpp27
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp16
6 files changed, 87 insertions, 2 deletions
diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
index 058e22c..d0d6a3a 100644
--- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -310,6 +310,12 @@ void MultiplexExternalSemaSource::ReadPendingInstantiations(
Sources[i]->ReadPendingInstantiations(Pending);
}
+void MultiplexExternalSemaSource::ReadPendingInstantiationsOfConstexprEntity(
+ const NamedDecl *D, llvm::SmallSetVector<NamedDecl *, 4> &Decls) {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadPendingInstantiationsOfConstexprEntity(D, Decls);
+};
+
void MultiplexExternalSemaSource::ReadLateParsedTemplates(
llvm::MapVector<const FunctionDecl *, std::unique_ptr<LateParsedTemplate>>
&LPTMap) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 77ff4e1..9591f8b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16275,6 +16275,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (FD && !FD->isDeleted())
checkTypeSupport(FD->getType(), FD->getLocation(), FD);
+ if (FD && FD->isConstexpr() && FD->isTemplated())
+ PerformPendingInstantiationsOfConstexprFunctions(FD);
+
return dcl;
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index d1b2b80..b204cb0 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -19053,12 +19053,17 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
CodeSynthesisContexts.size())
PendingLocalImplicitInstantiations.push_back(
std::make_pair(Func, PointOfInstantiation));
- else if (Func->isConstexpr())
+ else if (Func->isConstexpr()) {
// Do not defer instantiations of constexpr functions, to avoid the
// expression evaluator needing to call back into Sema if it sees a
// call to such a function.
InstantiateFunctionDefinition(PointOfInstantiation, Func);
- else {
+ if (!Func->isDefined()) {
+ PendingInstantiationsOfConstexprEntities
+ [Func->getTemplateInstantiationPattern()->getCanonicalDecl()]
+ .push_back(Func);
+ }
+ } else {
Func->setInstantiationIsPending(true);
PendingInstantiations.push_back(
std::make_pair(Func, PointOfInstantiation));
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d768bb7..aa367e0 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6495,6 +6495,34 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
PendingInstantiations.swap(delayedPCHInstantiations);
}
+// Instantiate all referenced specializations of the given function template
+// definition. This make sure that constexpr function templates that are defined
+// after the point of instantiation of their use can be evaluated after they
+// are defined. see CWG2497.
+void Sema::PerformPendingInstantiationsOfConstexprFunctions(FunctionDecl *Tpl) {
+
+ auto InstantiateAll = [&](const auto &Range) {
+ for (NamedDecl *D : Range) {
+ FunctionDecl *Fun = cast<FunctionDecl>(D);
+ InstantiateFunctionDefinition(Fun->getPointOfInstantiation(), Fun);
+ }
+ };
+
+ auto It =
+ PendingInstantiationsOfConstexprEntities.find(Tpl->getCanonicalDecl());
+ if (It != PendingInstantiationsOfConstexprEntities.end()) {
+ auto Decls = std::move(It->second);
+ PendingInstantiationsOfConstexprEntities.erase(It);
+ InstantiateAll(Decls);
+ }
+
+ llvm::SmallSetVector<NamedDecl *, 4> Decls;
+ if (ExternalSource) {
+ ExternalSource->ReadPendingInstantiationsOfConstexprEntity(Tpl, Decls);
+ InstantiateAll(Decls);
+ }
+}
+
void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,
const MultiLevelTemplateArgumentList &TemplateArgs) {
for (auto *DD : Pattern->ddiags()) {
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index f22da83..ef191c2 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -3709,6 +3709,19 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
}
break;
+ case PENDING_INSTANTIATIONS_OF_CONSTEXPR_ENTITIES:
+ if (Record.size() % 2 != 0)
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "Invalid PENDING_INSTANTIATIONS_OF_CONSTEXPR_ENTITIES block");
+
+ for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
+ DeclID Key = getGlobalDeclID(F, Record[I++]);
+ DeclID Value = getGlobalDeclID(F, Record[I++]);
+ PendingInstantiationsOfConstexprEntities[Key].insert(Value);
+ }
+ break;
+
case SEMA_DECL_REFS:
if (Record.size() != 3)
return llvm::createStringError(std::errc::illegal_byte_sequence,
@@ -8718,6 +8731,20 @@ void ASTReader::ReadPendingInstantiations(
PendingInstantiations.clear();
}
+void ASTReader::ReadPendingInstantiationsOfConstexprEntity(
+ const NamedDecl *D, llvm::SmallSetVector<NamedDecl *, 4> &Decls) {
+ for (auto *Redecl : D->redecls()) {
+ if (!Redecl->isFromASTFile())
+ continue;
+ DeclID Id = Redecl->getGlobalID();
+ auto It = PendingInstantiationsOfConstexprEntities.find(Id);
+ if (It == PendingInstantiationsOfConstexprEntities.end())
+ continue;
+ for (DeclID InstantiationId : It->second)
+ Decls.insert(cast<NamedDecl>(GetDecl(InstantiationId)));
+ }
+}
+
void ASTReader::ReadLateParsedTemplates(
llvm::MapVector<const FunctionDecl *, std::unique_ptr<LateParsedTemplate>>
&LPTMap) {
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 6df8152..8c8048f 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -849,6 +849,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(SEMA_DECL_REFS);
RECORD(WEAK_UNDECLARED_IDENTIFIERS);
RECORD(PENDING_IMPLICIT_INSTANTIATIONS);
+ RECORD(PENDING_INSTANTIATIONS_OF_CONSTEXPR_ENTITIES);
RECORD(UPDATE_VISIBLE);
RECORD(DECL_UPDATE_OFFSETS);
RECORD(DECL_UPDATES);
@@ -4836,6 +4837,16 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
assert(SemaRef.PendingLocalImplicitInstantiations.empty() &&
"There are local ones at end of translation unit!");
+ // Build a record containing all pending instantiations of constexpr
+ // entities.
+ RecordData PendingInstantiationsOfConstexprEntities;
+ for (const auto &I : SemaRef.PendingInstantiationsOfConstexprEntities) {
+ for (const auto &Elem : I.second) {
+ AddDeclRef(I.first, PendingInstantiationsOfConstexprEntities);
+ AddDeclRef(Elem, PendingInstantiationsOfConstexprEntities);
+ }
+ }
+
// Build a record containing some declaration references.
RecordData SemaDeclRefs;
if (SemaRef.StdNamespace || SemaRef.StdBadAlloc || SemaRef.StdAlignValT) {
@@ -5153,6 +5164,11 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
if (!PendingInstantiations.empty())
Stream.EmitRecord(PENDING_IMPLICIT_INSTANTIATIONS, PendingInstantiations);
+ // Write the record containing pending instantiations of constexpr entities.
+ if (!PendingInstantiationsOfConstexprEntities.empty())
+ Stream.EmitRecord(PENDING_INSTANTIATIONS_OF_CONSTEXPR_ENTITIES,
+ PendingInstantiationsOfConstexprEntities);
+
// Write the record containing declaration references of Sema.
if (!SemaDeclRefs.empty())
Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs);