llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: cor3ntin (cor3ntin) <details> <summary>Changes</summary> 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]) independant 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 --- Full diff: https://github.com/llvm/llvm-project/pull/73463.diff 7 Files Affected: - (modified) clang/docs/ReleaseNotes.rst (+5) - (modified) clang/include/clang/Sema/Sema.h (+11) - (modified) clang/lib/Sema/SemaDecl.cpp (+3) - (modified) clang/lib/Sema/SemaExpr.cpp (+7-2) - (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+17) - (modified) clang/test/SemaCXX/cxx2b-consteval-propagate.cpp (+5-3) - (added) clang/test/SemaTemplate/instantiate-used-constexpr-function.cpp (+30) ``````````diff diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 29a06d0f713f588..b34b66ec7dcabc2 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -762,6 +762,11 @@ Bug Fixes to C++ Support completes (except deduction guides). Fixes: (`#59827 <https://github.com/llvm/llvm-project/issues/59827>`_) +- Clang now immediately instantiates function template specializations + at the end of the definition of the corresponding function template + when the definition appears after the first point of instantiation. + (`#73232 <https://github.com/llvm/llvm-project/issues/73232>`_) + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an import failure of recursive friend class template. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f7c9d0e2e6412b7..091e1e3b4c1fd64 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -59,6 +59,7 @@ #include "clang/Sema/TypoCorrection.h" #include "clang/Sema/Weak.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" @@ -10078,6 +10079,12 @@ class Sema final { /// but have not yet been performed. std::deque<PendingImplicitInstantiation> PendingInstantiations; + /// Track constexpr functions referenced before they are (lexically) defined. + /// The key is the pattern, associated with a list of specialisations that + /// need to be instantiated when the pattern is defined. + llvm::DenseMap<NamedDecl *, SmallVector<NamedDecl *>> + PendingInstantiationsOfConstexprEntities; + /// Queue of implicit template instantiations that cannot be performed /// eagerly. SmallVector<PendingImplicitInstantiation, 1> LateParsedInstantiations; @@ -10396,6 +10403,10 @@ class Sema final { bool Recursive = false, bool DefinitionRequired = false, bool AtEndOfTU = false); + + void InstantiateFunctionTemplateSpecializations( + SourceLocation PointOfInstantiation, FunctionDecl *Template); + VarTemplateSpecializationDecl *BuildVarTemplateInstantiation( VarTemplateDecl *VarTemplate, VarDecl *FromVar, const TemplateArgumentList &TemplateArgList, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 23dd8ae15c16583..1030ba0d21b1906 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16255,6 +16255,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD && !FD->isDeleted()) checkTypeSupport(FD->getType(), FD->getLocation(), FD); + if (FD && FD->isConstexpr() && FD->isTemplated()) + InstantiateFunctionTemplateSpecializations(FD->getEndLoc(), FD); + return dcl; } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index fc39d6149c1cc65..37b0d0eed35845c 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -19047,12 +19047,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 08f4ba00fc9f7de..9afbf139a1c2b88 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -6481,6 +6481,23 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { PendingInstantiations.swap(delayedPCHInstantiations); } +// Instantiate all referenced specializations of the given function template +// definition. This make sure that function template that are defined after the +// point of instantiation of their used can be evaluated after they are defined. +// see CWG2497. +void Sema::InstantiateFunctionTemplateSpecializations( + SourceLocation PointOfInstantiation, FunctionDecl *Tpl) { + auto It = + PendingInstantiationsOfConstexprEntities.find(Tpl->getCanonicalDecl()); + if (It == PendingInstantiationsOfConstexprEntities.end()) + return; + for (NamedDecl *Fun : It->second) { + InstantiateFunctionDefinition(PointOfInstantiation, + cast<FunctionDecl>(Fun)); + } + PendingInstantiationsOfConstexprEntities.erase(It); +} + void Sema::PerformDependentDiagnostics(const DeclContext *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs) { for (auto *DD : Pattern->ddiags()) { diff --git a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp index 531a62622873357..a2b4039a31db778 100644 --- a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp +++ b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp @@ -105,13 +105,15 @@ template <typename T> constexpr int f(T t); auto a = &f<char>; -auto b = &f<int>; // expected-error {{immediate function 'f<int>' used before it is defined}} \ - // expected-note {{in instantiation of function template specialization}} +auto b = &f<int>; // expected-error {{immediate function 'f<int>' used before it is defined}} template <typename T> constexpr int f(T t) { // expected-note {{'f<int>' defined here}} return id(t); // expected-note {{'f<int>' is an immediate function because its body contains a call to a consteval function 'id' and that call is not a constant expression}} -} +} // expected-note {{in instantiation of function template specialization}} + + + } namespace constructors { diff --git a/clang/test/SemaTemplate/instantiate-used-constexpr-function.cpp b/clang/test/SemaTemplate/instantiate-used-constexpr-function.cpp new file mode 100644 index 000000000000000..57353d681ac7708 --- /dev/null +++ b/clang/test/SemaTemplate/instantiate-used-constexpr-function.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +namespace GH73232 { + +template <typename _CharT> +struct basic_string { + constexpr void _M_construct(); + constexpr basic_string() { + _M_construct(); + } +}; + +basic_string<char> a; + +template <typename _CharT> +constexpr void basic_string<_CharT>::_M_construct(){} +constexpr basic_string<char> z{}; + +template <typename T> +constexpr void g(T); + +constexpr int f() { g(0); return 0; } + +template <typename T> +constexpr void g(T) {} + +constexpr int z = f(); + +} `````````` </details> https://github.com/llvm/llvm-project/pull/73463 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits