https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/173537
>From 9eed555bd86be4accc2096cc40e5de30c809afda Mon Sep 17 00:00:00 2001 From: Corentin Jabot <[email protected]> Date: Wed, 24 Dec 2025 14:30:29 +0100 Subject: [PATCH 1/8] [Clang] Instantiate constexpr function when they are needed. This is a rework of #115168, with the sole aim of fixing #73232. The scaffolding is introduced here is necessary - but not sufficient for reflection. Reading the comments on #115168, I think we need to separate multiple concerns: - Do we have access to Sema (which this PR provides) - Can we mutate the AST - which is something individual callers will have to figure out. This does **not** fix #59966, as the change is complicated enough that i want to explore it in a separate PR. Fixes #73232 --- clang/docs/ReleaseNotes.rst | 155 ++++++++++++++++++ clang/include/clang/AST/ASTContext.h | 17 ++ clang/include/clang/Sema/Sema.h | 3 + clang/lib/AST/ASTContext.cpp | 7 + clang/lib/AST/ByteCode/Interp.cpp | 30 +++- clang/lib/AST/ByteCode/InterpState.cpp | 2 + clang/lib/AST/ByteCode/State.h | 2 + clang/lib/AST/ExprConstant.cpp | 42 ++++- clang/lib/Interpreter/IncrementalParser.cpp | 6 +- clang/lib/Parse/ParseAST.cpp | 6 + clang/lib/Sema/Sema.cpp | 30 ++++ .../SemaCXX/constexpr-late-instantiation.cpp | 84 +++++++++- .../constexpr-subobj-initialization.cpp | 5 +- .../SemaCXX/cxx2b-consteval-propagate.cpp | 5 +- 14 files changed, 374 insertions(+), 20 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5ac5ae4a7d37e..009a09819f359 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -140,9 +140,97 @@ Non-comprehensive list of changes in this release Usable in constant expressions. Implicit conversion is supported for class/struct types with conversion operators. +<<<<<<< HEAD - A new generic bit-reverse builtin function ``__builtin_bitreverseg`` that extends bit-reversal support to all standard integers type, including ``_BitInt`` +======= +- Added ``__builtin_elementwise_ldexp``. + +- Added ``__builtin_elementwise_fshl`` and ``__builtin_elementwise_fshr``. + +- ``__builtin_elementwise_abs`` can now be used in constant expression. + +- Added ``__builtin_elementwise_minnumnum`` and ``__builtin_elementwise_maxnumnum``. + +- Trapping UBSan (e.g. ``-fsanitize=undefined -fsanitize-trap=undefined``) now + emits a string describing the reason for trapping into the generated debug + info. This feature allows debuggers (e.g. LLDB) to display the reason for + trapping if the trap is reached. The string is currently encoded in the debug + info as an artificial frame that claims to be inlined at the trap location. + The function used for the artificial frame is an artificial function whose + name encodes the reason for trapping. The encoding used is currently the same + as ``__builtin_verbose_trap`` but might change in the future. This feature is + enabled by default but can be disabled by compiling with + ``-fno-sanitize-debug-trap-reasons``. The feature has a ``basic`` and + ``detailed`` mode (the default). The ``basic`` mode emits a hard-coded string + per trap kind (e.g. ``Integer addition overflowed``) and the ``detailed`` mode + emits a more descriptive string describing each individual trap (e.g. ``signed + integer addition overflow in 'a + b'``). The ``detailed`` mode produces larger + debug info than ``basic`` but is more helpful for debugging. The + ``-fsanitize-debug-trap-reasons=`` flag can be used to switch between the + different modes or disable the feature entirely. Note due to trap merging in + optimized builds (i.e. in each function all traps of the same kind get merged + into the same trap instruction) the trap reasons might be removed. To prevent + this build without optimizations (i.e. use `-O0` or use the `optnone` function + attribute) or use the `fno-sanitize-merge=` flag in optimized builds. + +- ``__builtin_elementwise_max`` and ``__builtin_elementwise_min`` functions for integer types can + now be used in constant expressions. + +- A vector of booleans is now a valid condition for the ternary ``?:`` operator. + This binds to a simple vector select operation. + +- Added ``__builtin_masked_load``, ``__builtin_masked_expand_load``, + ``__builtin_masked_store``, ``__builtin_masked_compress_store`` for + conditional memory loads from vectors. Binds to the LLVM intrinsics of the + same name. + +- Added ``__builtin_masked_gather`` and ``__builtin_masked_scatter`` for + conditional gathering and scattering operations on vectors. Binds to the LLVM + intrinsics of the same name. + +- The ``__builtin_popcountg``, ``__builtin_ctzg``, and ``__builtin_clzg`` + functions now accept fixed-size boolean vectors. + +- Use of ``__has_feature`` to detect the ``ptrauth_qualifier`` and ``ptrauth_intrinsics`` + features has been deprecated, and is restricted to the arm64e target only. The + correct method to check for these features is to test for the ``__PTRAUTH__`` + macro. + +- Added a new builtin, ``__builtin_dedup_pack``, to remove duplicate types from a parameter pack. + This feature is particularly useful in template metaprogramming for normalizing type lists. + The builtin produces a new, unexpanded parameter pack that can be used in contexts like template + argument lists or base specifiers. + + .. code-block:: c++ + + template <typename...> struct TypeList; + + // The resulting type is TypeList<int, double, char> + using MyTypeList = TypeList<__builtin_dedup_pack<int, double, int, char, double>...>; + + Currently, the use of ``__builtin_dedup_pack`` is limited to template arguments and base + specifiers, it also must be used within a template context. + +- ``__builtin_assume_dereferenceable`` now accepts non-constant size operands. + +- Fixed a crash when the second argument to ``__builtin_assume_aligned`` was not constant (#GH161314) + +- Introduce support for :doc:`allocation tokens <AllocToken>` to enable + allocator-level heap organization strategies. A feature to instrument all + allocation functions with a token ID can be enabled via the + ``-fsanitize=alloc-token`` flag. + +- A new generic byte swap builtin function ``__builtin_bswapg`` that extends the existing + __builtin_bswap{16,32,64} function family to support all standard integer types. + +- A builtin ``__builtin_infer_alloc_token(<args>, ...)`` is provided to allow + compile-time querying of allocation token IDs, where the builtin arguments + mirror those normally passed to an allocation function. + +- Clang now rejects the invalid use of ``constexpr`` with ``auto`` and an explicit type in C. (#GH163090) +>>>>>>> 3f06fd997749 ([Clang] Instantiate constexpr function when they are needed.) New Compiler Flags ------------------ @@ -230,6 +318,7 @@ Improvements to Clang's diagnostics .. code-block:: c++ +<<<<<<< HEAD struct DanglingView { std::string_view view; DanglingView(std::string s) : view(s) {} // warning: address of stack memory escapes to a field @@ -246,6 +335,14 @@ Improvements to Clang's diagnostics - The ``-Wloop-analysis`` warning has been extended to catch more cases of variable modification inside lambda expressions (#GH132038). +======= +- Fixed a crash when enabling ``-fdiagnostics-format=sarif`` and the output + carries messages like 'In file included from ...' or 'In module ...'. + Now the include/import locations are written into `sarif.run.result.relatedLocations`. + +- Clang now generates a fix-it for C++20 designated initializers when the + initializers do not match the declaration order in the structure. +>>>>>>> 3f06fd997749 ([Clang] Instantiate constexpr function when they are needed.) Improvements to Clang's time-trace ---------------------------------- @@ -280,10 +377,68 @@ Bug Fixes to Attribute Support Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ +<<<<<<< HEAD - Fixed a crash when instantiating ``requires`` expressions involving substitution failures in C++ concepts. (#GH176402) - Fixed a crash when a default argument is passed to an explicit object parameter. (#GH176639) - Fixed a crash when diagnosing an invalid static member function with an explicit object parameter (#GH177741) - Fixed a crash when evaluating uninitialized GCC vector/ext_vector_type vectors in ``constexpr``. (#GH180044) +======= +- Diagnose binding a reference to ``*nullptr`` during constant evaluation. (#GH48665) +- Suppress ``-Wdeprecated-declarations`` in implicitly generated functions. (#GH147293) +- Fix a crash when deleting a pointer to an incomplete array (#GH150359). +- Fixed a mismatched lambda scope bug when propagating up ``consteval`` within nested lambdas. (#GH145776) +- Disallow immediate escalation in destructors. (#GH109096) +- Fix an assertion failure when expression in assumption attribute + (``[[assume(expr)]]``) creates temporary objects. +- Fix the dynamic_cast to final class optimization to correctly handle + casts that are guaranteed to fail (#GH137518). +- Fix bug rejecting partial specialization of variable templates with auto NTTPs (#GH118190). +- Fix a crash if errors "member of anonymous [...] redeclares" and + "initializing multiple members of union" coincide (#GH149985). +- Fix a crash when using ``explicit(bool)`` in pre-C++11 language modes. (#GH152729) +- Fix the parsing of variadic member functions when the ellipis immediately follows a default argument.(#GH153445) +- Fix a crash when using an explicit object parameter in a non-member function with an invalid return type.(#GH173943) +- Fixed a bug that caused ``this`` captured by value in a lambda with a dependent explicit object parameter to not be + instantiated properly. (#GH154054) +- Fixed a bug where our ``member-like constrained friend`` checking caused an incorrect analysis of lambda captures. (#GH156225) +- Fixed a crash when implicit conversions from initialize list to arrays of + unknown bound during constant evaluation. (#GH151716) +- Instantiate constexpr functions as needed before they are evaluated. (#GH73232) +- Support the dynamic_cast to final class optimization with pointer + authentication enabled. (#GH152601) +- Fix the check for narrowing int-to-float conversions, so that they are detected in + cases where converting the float back to an integer is undefined behaviour (#GH157067). +- Stop rejecting C++11-style attributes on the first argument of constructors in older + standards. (#GH156809). +- Fix a crash when applying binary or ternary operators to two same function types with different spellings, + where at least one of the function parameters has an attribute which affects + the function type. +- Fix an assertion failure when a ``constexpr`` variable is only referenced through + ``__builtin_addressof``, and related issues with builtin arguments. (#GH154034) +- Fix an assertion failure when taking the address on a non-type template parameter argument of + object type. (#GH151531) +- Suppress ``-Wdouble-promotion`` when explicitly asked for with C++ list initialization (#GH33409). +- Fix the result of `__builtin_is_implicit_lifetime` for types with a user-provided constructor. (#GH160610) +- Correctly deduce return types in ``decltype`` expressions. (#GH160497) (#GH56652) (#GH116319) (#GH161196) +- Fixed a crash in the pre-C++23 warning for attributes before a lambda declarator (#GH161070). +- Fix a crash when attempting to deduce a deduction guide from a non deducible template template parameter. (#130604) +- Fix for clang incorrectly rejecting the default construction of a union with + nontrivial member when another member has an initializer. (#GH81774) +- Fixed a template depth issue when parsing lambdas inside a type constraint. (#GH162092) +- Fix the support of zero-length arrays in SFINAE context. (#GH170040) +- Diagnose unresolved overload sets in non-dependent compound requirements. (#GH51246) (#GH97753) +- Fix a crash when extracting unavailable member type from alias in template deduction. (#GH165560) +- Fix incorrect diagnostics for lambdas with init-captures inside braced initializers. (#GH163498) +- Fixed an issue where templates prevented nested anonymous records from checking the deletion of special members. (#GH167217) +- Fixed serialization of pack indexing types, where we failed to expand those packs from a PCH/module. (#GH172464) +- Fixed spurious diagnoses of certain nested lambda expressions. (#GH149121) (#GH156579) +- Fix the result of ``__is_pointer_interconvertible_base_of`` when arguments are qualified and passed via template parameters. (#GH135273) +- Fixed a crash when evaluating nested requirements in requires-expressions that reference invented parameters. (#GH166325) +- Fixed a crash when standard comparison categories (e.g. ``std::partial_ordering``) are defined with incorrect static member types. (#GH170015) (#GH56571) +- Fixed a crash when parsing the ``enable_if`` attribute on C function declarations with identifier-list parameters. (#GH173826) +- Fixed an assertion failure triggered by nested lambdas during capture handling. (#GH172814) +- Fixed an assertion failure in vector conversions involving instantiation-dependent template expressions. (#GH173347) +>>>>>>> 3f06fd997749 ([Clang] Instantiate constexpr function when they are needed.) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 6b819de2fb36d..bf75813922c6e 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -44,6 +44,7 @@ #include "llvm/ADT/StringSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/TypeSize.h" +#include <memory> #include <optional> namespace llvm { @@ -215,6 +216,16 @@ struct TypeInfoChars { } }; +/// Interface that allows constant evaluator to call Sema +/// and mutate the AST. +struct SemaProxy { + virtual ~SemaProxy() = default; + + virtual void + InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, + FunctionDecl *Function) = 0; +}; + /// Holds long-lived AST nodes (such as types and decls) that can be /// referred to throughout the semantic analysis of a file. class ASTContext : public RefCountedBase<ASTContext> { @@ -786,6 +797,8 @@ class ASTContext : public RefCountedBase<ASTContext> { /// Keeps track of the deallocated DeclListNodes for future reuse. DeclListNode *ListNodeFreeList = nullptr; + std::unique_ptr<SemaProxy> SemaProxyPtr; + public: IdentifierTable &Idents; SelectorTable &Selectors; @@ -1409,6 +1422,10 @@ class ASTContext : public RefCountedBase<ASTContext> { /// with this AST context, if any. ASTMutationListener *getASTMutationListener() const { return Listener; } + SemaProxy *getSemaProxy(); + + void setSemaProxy(std::unique_ptr<SemaProxy> Proxy); + void PrintStats() const; const SmallVectorImpl<Type *>& getTypes() const { return Types; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 9424b80d5cdb6..fa8a54a3730ac 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -910,6 +910,9 @@ class Sema final : public SemaBase { /// initialized but before it parses anything. void Initialize(); + void RegisterSemaProxy(); + void UnregisterSemaProxy(); + /// This virtual key function only exists to limit the emission of debug info /// describing the Sema class. GCC and Clang only emit debug info for a class /// with a vtable when the vtable is emitted. Sema is final and not diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 3f63420cae91e..eb70a9d91cc0c 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -926,6 +926,13 @@ ASTContext::setExternalSource(IntrusiveRefCntPtr<ExternalASTSource> Source) { ExternalSource = std::move(Source); } +SemaProxy *ASTContext::getSemaProxy() { return SemaProxyPtr.get(); } + +void ASTContext::setSemaProxy(std::unique_ptr<SemaProxy> Proxy) { + assert((!SemaProxyPtr || !Proxy) && "SemaProxy already set"); + SemaProxyPtr = std::move(Proxy); +} + void ASTContext::PrintStats() const { llvm::errs() << "\n*** AST Context Stats:\n"; llvm::errs() << " " << Types.size() << " types total.\n"; diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index bb259822c3dfe..11f629d0d97c5 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Interp.h" +#include "ByteCode/Source.h" #include "Compiler.h" #include "Function.h" #include "InterpFrame.h" @@ -1624,13 +1625,30 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType, return true; } -static void compileFunction(InterpState &S, const Function *Func) { - const FunctionDecl *Definition = Func->getDecl()->getDefinition(); - if (!Definition) +static void compileFunction(InterpState &S, const Function *Func, + SourceLocation Loc) { + + const FunctionDecl *Fn = Func->getDecl(); + + // [C++26] [temp.inst] p5 + // [...] the function template specialization is implicitly instantiated + // when the specialization is referenced in a context that requires a function + // definition to exist or if the existence of the definition affects the + // semantics of the program. + if (!Fn->isDefined() && Fn->isImplicitlyInstantiable() && Fn->isConstexpr() && + S.inConstantContext() && !S.TryConstantInitialization && + !S.checkingPotentialConstantExpression()) { + SemaProxy *SP = S.getASTContext().getSemaProxy(); + if (!SP) + return; + SP->InstantiateFunctionDefinition(Loc, const_cast<FunctionDecl *>(Fn)); + } + Fn = Fn->getDefinition(); + if (!Fn) return; Compiler<ByteCodeEmitter>(S.getContext(), S.P) - .compileFunc(Definition, const_cast<Function *>(Func)); + .compileFunc(Fn, const_cast<Function *>(Func)); } bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, @@ -1656,7 +1674,7 @@ bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, } if (!Func->isFullyCompiled()) - compileFunction(S, Func); + compileFunction(S, Func, S.Current->getLocation(OpPC)); if (!CheckCallable(S, OpPC, Func)) return false; @@ -1733,7 +1751,7 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func, } if (!Func->isFullyCompiled()) - compileFunction(S, Func); + compileFunction(S, Func, S.Current->getLocation(OpPC)); if (!CheckCallable(S, OpPC, Func)) return cleanup(); diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp index df507bd5507c3..d8a8d76b9f06d 100644 --- a/clang/lib/AST/ByteCode/InterpState.cpp +++ b/clang/lib/AST/ByteCode/InterpState.cpp @@ -24,6 +24,7 @@ InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk, StepsLeft(Ctx.getLangOpts().ConstexprStepLimit), InfiniteSteps(StepsLeft == 0) { InConstantContext = Parent.InConstantContext; + TryConstantInitialization = Parent.TryConstantInitialization; CheckingPotentialConstantExpression = Parent.CheckingPotentialConstantExpression; CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior; @@ -38,6 +39,7 @@ InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk, Current(&BottomFrame), StepsLeft(Ctx.getLangOpts().ConstexprStepLimit), InfiniteSteps(StepsLeft == 0) { InConstantContext = Parent.InConstantContext; + TryConstantInitialization = Parent.TryConstantInitialization; CheckingPotentialConstantExpression = Parent.CheckingPotentialConstantExpression; CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior; diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h index a720033c7914b..841da0836516d 100644 --- a/clang/lib/AST/ByteCode/State.h +++ b/clang/lib/AST/ByteCode/State.h @@ -187,6 +187,8 @@ class State { /// is set; this is used when evaluating ICEs in C. bool CheckingForUndefinedBehavior = false; + bool TryConstantInitialization = false; + EvaluationMode EvalMode; ASTContext &Ctx; Expr::EvalStatus &EvalStatus; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 2c13befec02f2..7ceea521640f2 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -43,6 +43,7 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/CurrentSourceLocExprScope.h" +#include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/InferAlloc.h" #include "clang/AST/OSLog.h" @@ -53,6 +54,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/APFixedPoint.h" @@ -6961,6 +6963,28 @@ static bool handleTrivialCopy(EvalInfo &Info, const ParmVarDecl *Param, CopyObjectRepresentation); } +static void InstantiateFunctionBeforeCall(const FunctionDecl *FD, + EvalInfo &Info, SourceLocation Loc) { + + // [C++26] [temp.inst] p5 + // [...] the function template specialization is implicitly instantiated + // when the specialization is referenced in a context that requires a function + // definition to exist or if the existence of the definition affects the + // semantics of the program. + + if (!FD->isDefined() && FD->isImplicitlyInstantiable() && FD->isConstexpr() && + Info.InConstantContext && !Info.TryConstantInitialization && + !Info.checkingPotentialConstantExpression()) { + + SemaProxy *SP = Info.getASTContext().getSemaProxy(); + // Try to instantiate the definition if Sema is available + // (i.e during the initial parse of the TU). + if (SP) { + SP->InstantiateFunctionDefinition(Loc, const_cast<FunctionDecl *>(FD)); + } + } +} + /// Evaluate a function call. static bool HandleFunctionCall(SourceLocation CallLoc, const FunctionDecl *Callee, @@ -7354,6 +7378,8 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceRange CallRange, if (!Info.CheckCallLimit(CallRange.getBegin())) return false; + InstantiateFunctionBeforeCall(DD, Info, CallRange.getBegin()); + const FunctionDecl *Definition = nullptr; const Stmt *Body = DD->getBody(Definition); @@ -8819,10 +8845,13 @@ class ExprEvaluatorBase CallScope.destroy(); } - const FunctionDecl *Definition = nullptr; - Stmt *Body = FD->getBody(Definition); SourceLocation Loc = E->getExprLoc(); + InstantiateFunctionBeforeCall(FD, Info, Loc); + + const FunctionDecl *Definition = nullptr; + const Stmt *Body = FD->getBody(Definition); + // Treat the object argument as `this` when evaluating defaulted // special menmber functions if (FD->hasCXXExplicitFunctionObjectParameter()) @@ -11340,8 +11369,10 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, return handleDefaultInitValue(T, Result); } + InstantiateFunctionBeforeCall(FD, Info, E->getBeginLoc()); + const FunctionDecl *Definition = nullptr; - auto Body = FD->getBody(Definition); + const Stmt *Body = FD->getBody(Definition); if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body)) return false; @@ -11381,8 +11412,9 @@ bool RecordExprEvaluator::VisitCXXInheritedCtorInitExpr( if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl()) return false; + InstantiateFunctionBeforeCall(FD, Info, E->getBeginLoc()); const FunctionDecl *Definition = nullptr; - auto Body = FD->getBody(Definition); + const Stmt *Body = FD->getBody(Definition); if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body)) return false; @@ -20796,6 +20828,8 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, : EvaluationMode::ConstantFold); Info.setEvaluatingDecl(VD, Value); Info.InConstantContext = IsConstantInitialization; + Info.TryConstantInitialization = + !VD->isConstexpr() && !VD->hasAttr<ConstInitAttr>(); SourceLocation DeclLoc = VD->getLocation(); QualType DeclTy = VD->getType(); diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp index bf08911e23533..5a24342e73ca4 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -42,9 +42,13 @@ IncrementalParser::IncrementalParser(CompilerInstance &Instance, External->StartTranslationUnit(Consumer); P->Initialize(); + S.RegisterSemaProxy(); } -IncrementalParser::~IncrementalParser() { P.reset(); } +IncrementalParser::~IncrementalParser() { + S.UnregisterSemaProxy(); + P.reset(); +} llvm::Expected<TranslationUnitDecl *> IncrementalParser::ParseOrWrapTopLevelDecl() { diff --git a/clang/lib/Parse/ParseAST.cpp b/clang/lib/Parse/ParseAST.cpp index c8ee625eb57ad..1cea282f13a00 100644 --- a/clang/lib/Parse/ParseAST.cpp +++ b/clang/lib/Parse/ParseAST.cpp @@ -21,6 +21,7 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/TimeProfiler.h" #include <cstdio> @@ -161,6 +162,11 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { return M; }); P.Initialize(); + + auto Unregister = + llvm::make_scope_exit([&S]() { S.UnregisterSemaProxy(); }); + S.RegisterSemaProxy(); + Parser::DeclGroupPtrTy ADecl; Sema::ModuleImportState ImportState; EnterExpressionEvaluationContext PotentiallyEvaluated( diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index d53527af38653..90b919974586b 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -75,11 +75,14 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/TimeProfiler.h" +#include <memory> #include <optional> using namespace clang; using namespace sema; +static std::unique_ptr<SemaProxy> getSemaProxyImplementation(Sema &SemaRef); + SourceLocation Sema::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) { return Lexer::getLocForEndOfToken(Loc, Offset, SourceMgr, LangOpts); } @@ -622,6 +625,15 @@ Sema::~Sema() { SemaPPCallbackHandler->reset(); } +void Sema::RegisterSemaProxy() { + // Let the AST context relies on Sema for + // ast mutations features that require semantic analysis + // (lazy instantiation, reflection, etc). + Context.setSemaProxy(getSemaProxyImplementation(*this)); +} + +void Sema::UnregisterSemaProxy() { Context.setSemaProxy({}); } + void Sema::runWithSufficientStackSpace(SourceLocation Loc, llvm::function_ref<void()> Fn) { StackHandler.runWithSufficientStackSpace(Loc, Fn); @@ -2964,3 +2976,21 @@ Attr *Sema::CreateAnnotationAttr(const ParsedAttr &AL) { return CreateAnnotationAttr(AL, Str, Args); } + +class SemaProxyImplementation final : public SemaProxy { +private: + Sema &SemaRef; + +public: + SemaProxyImplementation(Sema &SemaRef) : SemaRef(SemaRef) {} + void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, + FunctionDecl *Function) override { + SemaRef.InstantiateFunctionDefinition( + PointOfInstantiation, Function, /*Recursive=*/true, + /*DefinitionRequired=*/true, /*AtEndOfTU=*/false); + } +}; + +std::unique_ptr<SemaProxy> getSemaProxyImplementation(Sema &SemaRef) { + return std::make_unique<SemaProxyImplementation>(SemaRef); +} diff --git a/clang/test/SemaCXX/constexpr-late-instantiation.cpp b/clang/test/SemaCXX/constexpr-late-instantiation.cpp index 9aec0c90e61dc..59cfbfdff0e03 100644 --- a/clang/test/SemaCXX/constexpr-late-instantiation.cpp +++ b/clang/test/SemaCXX/constexpr-late-instantiation.cpp @@ -1,16 +1,90 @@ -// RUN: %clang_cc1 %s -fsyntax-only -verify -// RUN: %clang_cc1 %s -fexperimental-new-constant-interpreter -fsyntax-only -verify +// RUN: %clang_cc1 %s -std=c++14 -fsyntax-only -verify +// RUN: %clang_cc1 %s -std=c++20 -fsyntax-only -verify +// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -verify + +// RUN: %clang_cc1 %s -std=c++14 -fsyntax-only -fexperimental-new-constant-interpreter -verify +// RUN: %clang_cc1 %s -std=c++20 -fsyntax-only -fexperimental-new-constant-interpreter -verify +// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fexperimental-new-constant-interpreter -verify template <typename T> -constexpr T foo(T a); // expected-note {{declared here}} +constexpr T foo(T a); // expected-note {{explicit instantiation refers here}} int main() { int k = foo<int>(5); // Ok - constexpr int j = // expected-error {{constexpr variable 'j' must be initialized by a constant expression}} - foo<int>(5); // expected-note {{undefined function 'foo<int>' cannot be used in a constant expression}} + constexpr int j = + foo<int>(5); // expected-error {{explicit instantiation of undefined function template 'foo'}} \ + // expected-error {{constexpr variable 'j' must be initialized by a constant expression}} } template <typename T> constexpr T foo(T a) { return a; } + + +namespace GH73232 { +namespace ex1 { +template <typename T> +constexpr void g(T); + +constexpr int f() { + g(0); + return 0; +} + +template <typename T> +constexpr void g(T) {} + +constexpr auto z = f(); +} + +namespace ex2 { +template <typename> constexpr static void fromType(); + +void registerConverter() { fromType<int>(); } +template <typename> struct QMetaTypeId {}; +template <typename T> constexpr void fromType() { + (void)QMetaTypeId<T>{}; +} +template <> struct QMetaTypeId<int> {}; +} // namespace ex2 + +namespace ex3 { + +#if __cplusplus > 202302L +struct A { + consteval A(int i) { + chk(i); + } + constexpr void chk(auto) {} +}; +A a{1}; + +#endif + +} + +} // namespace GH73232 + + +namespace GH156255 { + +class X +{ +public: + constexpr int f( int x ) const + { + return g( x ); + } + +private: + + template<class T> + constexpr T g( T x ) const + { + return x; + } +}; + +constexpr int x = X().f( 1 ); +} diff --git a/clang/test/SemaCXX/constexpr-subobj-initialization.cpp b/clang/test/SemaCXX/constexpr-subobj-initialization.cpp index f0252df1e2ce1..c2e51d3920f6a 100644 --- a/clang/test/SemaCXX/constexpr-subobj-initialization.cpp +++ b/clang/test/SemaCXX/constexpr-subobj-initialization.cpp @@ -47,12 +47,13 @@ constexpr Bar bb; // expected-error {{must be initialized by a constant expressi template <typename Ty> struct Baz { - constexpr Baz(); // expected-note {{declared here}} + constexpr Baz(); // expected-note {{explicit instantiation refers here}} }; struct Quux : Baz<Foo>, private Bar { int i; - constexpr Quux() : i(12) {} // expected-note {{undefined constructor 'Baz' cannot be used in a constant expression}} + constexpr Quux() : i(12) {} // expected-error {{explicit instantiation of undefined member function 'Baz' of class template 'Baz<Foo>'}} \ + // expected-note {{subexpression not valid in a constant expression}} }; constexpr Quux qx; // expected-error {{must be initialized by a constant expression}} \ diff --git a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp index 39097d17441f7..a2c5b583904f2 100644 --- a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp +++ b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp @@ -75,10 +75,11 @@ struct a { a aa(fdupe<int>((f<int>(7)))); template <typename T> -constexpr int foo(T t); // expected-note {{declared here}} +constexpr int foo(T t); // expected-note {{explicit instantiation refers here}} a bb(f<int>(foo<int>(7))); // expected-error{{call to immediate function 'f<int>' is not a constant expression}} \ - // expected-note{{undefined function 'foo<int>' cannot be used in a constant expression}} + // expected-error{{explicit instantiation of undefined function template 'foo'}} \ + // expected-note{{subexpression not valid in a constant expression}} } >From 3a3ad6cb7cb21df5fb9757770dfb7ffe1be1f071 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <[email protected]> Date: Fri, 2 Jan 2026 10:11:38 +0100 Subject: [PATCH 2/8] Address some review comments --- clang/docs/ReleaseNotes.rst | 2 +- clang/lib/AST/ByteCode/Interp.cpp | 12 ++--- clang/lib/AST/ByteCode/InterpState.cpp | 4 +- clang/lib/AST/ByteCode/State.h | 4 +- clang/lib/AST/ExprConstant.cpp | 4 +- clang/lib/Sema/Sema.cpp | 5 +- .../SemaCXX/constexpr-late-instantiation.cpp | 49 +++++++++++++++++++ 7 files changed, 65 insertions(+), 15 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 009a09819f359..e0b69dac70baa 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -403,7 +403,7 @@ Bug Fixes to C++ Support - Fixed a bug where our ``member-like constrained friend`` checking caused an incorrect analysis of lambda captures. (#GH156225) - Fixed a crash when implicit conversions from initialize list to arrays of unknown bound during constant evaluation. (#GH151716) -- Instantiate constexpr functions as needed before they are evaluated. (#GH73232) +- Instantiate constexpr functions as needed before they are evaluated. (#GH73232) (#GH35052) (#GH100897) - Support the dynamic_cast to final class optimization with pointer authentication enabled. (#GH152601) - Fix the check for narrowing int-to-float conversions, so that they are detected in diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 11f629d0d97c5..b725ccc6a1a20 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "Interp.h" -#include "ByteCode/Source.h" #include "Compiler.h" #include "Function.h" #include "InterpFrame.h" @@ -1626,7 +1625,7 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType, } static void compileFunction(InterpState &S, const Function *Func, - SourceLocation Loc) { + CodePtr OpPC) { const FunctionDecl *Fn = Func->getDecl(); @@ -1636,12 +1635,13 @@ static void compileFunction(InterpState &S, const Function *Func, // definition to exist or if the existence of the definition affects the // semantics of the program. if (!Fn->isDefined() && Fn->isImplicitlyInstantiable() && Fn->isConstexpr() && - S.inConstantContext() && !S.TryConstantInitialization && + S.inConstantContext() && !S.PerformingTrialEvaluation && !S.checkingPotentialConstantExpression()) { SemaProxy *SP = S.getASTContext().getSemaProxy(); if (!SP) return; - SP->InstantiateFunctionDefinition(Loc, const_cast<FunctionDecl *>(Fn)); + SP->InstantiateFunctionDefinition(S.Current->getLocation(OpPC), + const_cast<FunctionDecl *>(Fn)); } Fn = Fn->getDefinition(); if (!Fn) @@ -1674,7 +1674,7 @@ bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, } if (!Func->isFullyCompiled()) - compileFunction(S, Func, S.Current->getLocation(OpPC)); + compileFunction(S, Func, OpPC); if (!CheckCallable(S, OpPC, Func)) return false; @@ -1751,7 +1751,7 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func, } if (!Func->isFullyCompiled()) - compileFunction(S, Func, S.Current->getLocation(OpPC)); + compileFunction(S, Func, OpPC); if (!CheckCallable(S, OpPC, Func)) return cleanup(); diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp index d8a8d76b9f06d..4d6c182392e1c 100644 --- a/clang/lib/AST/ByteCode/InterpState.cpp +++ b/clang/lib/AST/ByteCode/InterpState.cpp @@ -24,7 +24,7 @@ InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk, StepsLeft(Ctx.getLangOpts().ConstexprStepLimit), InfiniteSteps(StepsLeft == 0) { InConstantContext = Parent.InConstantContext; - TryConstantInitialization = Parent.TryConstantInitialization; + PerformingTrialEvaluation = Parent.PerformingTrialEvaluation; CheckingPotentialConstantExpression = Parent.CheckingPotentialConstantExpression; CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior; @@ -39,7 +39,7 @@ InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk, Current(&BottomFrame), StepsLeft(Ctx.getLangOpts().ConstexprStepLimit), InfiniteSteps(StepsLeft == 0) { InConstantContext = Parent.InConstantContext; - TryConstantInitialization = Parent.TryConstantInitialization; + PerformingTrialEvaluation = Parent.PerformingTrialEvaluation; CheckingPotentialConstantExpression = Parent.CheckingPotentialConstantExpression; CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior; diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h index 841da0836516d..c4a4071f6f359 100644 --- a/clang/lib/AST/ByteCode/State.h +++ b/clang/lib/AST/ByteCode/State.h @@ -187,7 +187,9 @@ class State { /// is set; this is used when evaluating ICEs in C. bool CheckingForUndefinedBehavior = false; - bool TryConstantInitialization = false; + /// Whether we are performing trial evaluation, i.e when evaluating the + /// initializer of a constant-initialized variable. + bool PerformingTrialEvaluation = false; EvaluationMode EvalMode; ASTContext &Ctx; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 7ceea521640f2..d2026108e9de1 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -6973,7 +6973,7 @@ static void InstantiateFunctionBeforeCall(const FunctionDecl *FD, // semantics of the program. if (!FD->isDefined() && FD->isImplicitlyInstantiable() && FD->isConstexpr() && - Info.InConstantContext && !Info.TryConstantInitialization && + Info.InConstantContext && !Info.PerformingTrialEvaluation && !Info.checkingPotentialConstantExpression()) { SemaProxy *SP = Info.getASTContext().getSemaProxy(); @@ -20828,7 +20828,7 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, : EvaluationMode::ConstantFold); Info.setEvaluatingDecl(VD, Value); Info.InConstantContext = IsConstantInitialization; - Info.TryConstantInitialization = + Info.PerformingTrialEvaluation = !VD->isConstexpr() && !VD->hasAttr<ConstInitAttr>(); SourceLocation DeclLoc = VD->getLocation(); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 90b919974586b..bdc5155214730 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -75,7 +75,6 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/TimeProfiler.h" -#include <memory> #include <optional> using namespace clang; @@ -626,8 +625,8 @@ Sema::~Sema() { } void Sema::RegisterSemaProxy() { - // Let the AST context relies on Sema for - // ast mutations features that require semantic analysis + // Let the AST context rely on Sema for + // AST mutation features that require semantic analysis // (lazy instantiation, reflection, etc). Context.setSemaProxy(getSemaProxyImplementation(*this)); } diff --git a/clang/test/SemaCXX/constexpr-late-instantiation.cpp b/clang/test/SemaCXX/constexpr-late-instantiation.cpp index 59cfbfdff0e03..cbfd26587c128 100644 --- a/clang/test/SemaCXX/constexpr-late-instantiation.cpp +++ b/clang/test/SemaCXX/constexpr-late-instantiation.cpp @@ -88,3 +88,52 @@ class X constexpr int x = X().f( 1 ); } + + +namespace GH35052 { + +template <typename F> +constexpr int func(F f) { + if constexpr (f(1UL)) { + return 1; + } + return 0; +} + +int test() { + auto predicate = [](auto v) constexpr -> bool { return v == 1; }; + return func(predicate); +} + +} // namespace GH35052 + +namespace GH115118 { + +struct foo { + foo(const foo&) = default; + foo(auto) + requires([]<int = 0>() -> bool { return true; }()) + {} +}; + +struct bar { + foo x; +}; + +} // namespace GH115118 + +namespace GH100897 { + +template <typename> +constexpr auto foo() noexcept { + constexpr auto extract_size = []<typename argument_t>() constexpr -> int { + return 1; + }; + + constexpr int result = extract_size.template operator()<int>(); + return result; +} + +void test() { foo<void>(); } + +} // namespace GH100897 >From 1b7302264724fbb9b7c68457ad5b679a809e87bd Mon Sep 17 00:00:00 2001 From: Corentin Jabot <[email protected]> Date: Fri, 2 Jan 2026 13:15:57 +0100 Subject: [PATCH 3/8] fix tests --- clang/test/SemaCXX/constexpr-late-instantiation.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clang/test/SemaCXX/constexpr-late-instantiation.cpp b/clang/test/SemaCXX/constexpr-late-instantiation.cpp index cbfd26587c128..24df761cf0a52 100644 --- a/clang/test/SemaCXX/constexpr-late-instantiation.cpp +++ b/clang/test/SemaCXX/constexpr-late-instantiation.cpp @@ -89,6 +89,7 @@ class X constexpr int x = X().f( 1 ); } +#if __cplusplus > 202002L namespace GH35052 { @@ -105,6 +106,7 @@ int test() { return func(predicate); } + } // namespace GH35052 namespace GH115118 { @@ -122,6 +124,7 @@ struct bar { } // namespace GH115118 + namespace GH100897 { template <typename> @@ -137,3 +140,5 @@ constexpr auto foo() noexcept { void test() { foo<void>(); } } // namespace GH100897 + +#endif >From 693f142b0900fc2df9cfa22b638dc97f2e450955 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <[email protected]> Date: Fri, 9 Jan 2026 10:50:19 +0100 Subject: [PATCH 4/8] address more feedback --- clang/docs/ReleaseNotes.rst | 13 ++++++++-- clang/include/clang/AST/ASTContext.h | 2 +- clang/include/clang/Sema/Sema.h | 4 +-- clang/lib/AST/ByteCode/Interp.cpp | 4 +-- clang/lib/AST/ExprConstShared.h | 4 +++ clang/lib/AST/ExprConstant.cpp | 27 ++++++++++++--------- clang/lib/Interpreter/IncrementalParser.cpp | 4 +-- clang/lib/Parse/ParseAST.cpp | 24 ++++++++++-------- clang/lib/Sema/Sema.cpp | 6 ++--- 9 files changed, 55 insertions(+), 33 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index e0b69dac70baa..3af3f81b4f53c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -221,8 +221,8 @@ Non-comprehensive list of changes in this release allocator-level heap organization strategies. A feature to instrument all allocation functions with a token ID can be enabled via the ``-fsanitize=alloc-token`` flag. - -- A new generic byte swap builtin function ``__builtin_bswapg`` that extends the existing + +- A new generic byte swap builtin function ``__builtin_bswapg`` that extends the existing __builtin_bswap{16,32,64} function family to support all standard integer types. - A builtin ``__builtin_infer_alloc_token(<args>, ...)`` is provided to allow @@ -318,6 +318,7 @@ Improvements to Clang's diagnostics .. code-block:: c++ +<<<<<<< HEAD <<<<<<< HEAD struct DanglingView { std::string_view view; @@ -343,6 +344,14 @@ Improvements to Clang's diagnostics - Clang now generates a fix-it for C++20 designated initializers when the initializers do not match the declaration order in the structure. >>>>>>> 3f06fd997749 ([Clang] Instantiate constexpr function when they are >>>>>>> needed.) +======= +- Fixed a crash when enabling ``-fdiagnostics-format=sarif`` and the output + carries messages like 'In file included from ...' or 'In module ...'. + Now the include/import locations are written into `sarif.run.result.relatedLocations`. + +- Clang now generates a fix-it for C++20 designated initializers when the + initializers do not match the declaration order in the structure. +>>>>>>> ea6211a89115 (address more feedback) Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index bf75813922c6e..7ba0cde3aba8e 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -222,7 +222,7 @@ struct SemaProxy { virtual ~SemaProxy() = default; virtual void - InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, + instantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function) = 0; }; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fa8a54a3730ac..45f236034bb0e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -910,8 +910,8 @@ class Sema final : public SemaBase { /// initialized but before it parses anything. void Initialize(); - void RegisterSemaProxy(); - void UnregisterSemaProxy(); + void registerSemaProxy(); + void unregisterSemaProxy(); /// This virtual key function only exists to limit the emission of debug info /// describing the Sema class. GCC and Clang only emit debug info for a class diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index b725ccc6a1a20..a7729741cbc5c 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1634,13 +1634,13 @@ static void compileFunction(InterpState &S, const Function *Func, // when the specialization is referenced in a context that requires a function // definition to exist or if the existence of the definition affects the // semantics of the program. - if (!Fn->isDefined() && Fn->isImplicitlyInstantiable() && Fn->isConstexpr() && + if (FunctionDefinitionCanBeLazilyInstantiated(Func->getDecl()) && S.inConstantContext() && !S.PerformingTrialEvaluation && !S.checkingPotentialConstantExpression()) { SemaProxy *SP = S.getASTContext().getSemaProxy(); if (!SP) return; - SP->InstantiateFunctionDefinition(S.Current->getLocation(OpPC), + SP->instantiateFunctionDefinition(S.Current->getLocation(OpPC), const_cast<FunctionDecl *>(Fn)); } Fn = Fn->getDefinition(); diff --git a/clang/lib/AST/ExprConstShared.h b/clang/lib/AST/ExprConstShared.h index 550b36c232161..a88e8fc4fa96e 100644 --- a/clang/lib/AST/ExprConstShared.h +++ b/clang/lib/AST/ExprConstShared.h @@ -28,6 +28,7 @@ class LangOptions; class ASTContext; class CharUnits; class Expr; +class FunctionDecl; } // namespace clang using namespace clang; /// Values returned by __builtin_classify_type, chosen to match the values @@ -84,4 +85,7 @@ uint8_t GFNIAffine(uint8_t XByte, const llvm::APInt &AQword, llvm::APSInt NormalizeRotateAmount(const llvm::APSInt &Value, const llvm::APSInt &Amount); +/// Whether we can instantiate FD during constant evaluation +bool FunctionDefinitionCanBeLazilyInstantiated(const FunctionDecl *FD); + #endif diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index d2026108e9de1..d67cd76a7f407 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -6963,8 +6963,14 @@ static bool handleTrivialCopy(EvalInfo &Info, const ParmVarDecl *Param, CopyObjectRepresentation); } -static void InstantiateFunctionBeforeCall(const FunctionDecl *FD, - EvalInfo &Info, SourceLocation Loc) { +bool FunctionDefinitionCanBeLazilyInstantiated(const FunctionDecl *FD) { + return !FD->isDefined() && FD->isImplicitlyInstantiable() && + FD->isConstexpr(); +} + +static void TryInstantiateFunctionBeforeCall(const FunctionDecl *FD, + EvalInfo &Info, + SourceLocation Loc) { // [C++26] [temp.inst] p5 // [...] the function template specialization is implicitly instantiated @@ -6972,16 +6978,15 @@ static void InstantiateFunctionBeforeCall(const FunctionDecl *FD, // definition to exist or if the existence of the definition affects the // semantics of the program. - if (!FD->isDefined() && FD->isImplicitlyInstantiable() && FD->isConstexpr() && - Info.InConstantContext && !Info.PerformingTrialEvaluation && + if (FunctionDefinitionCanBeLazilyInstantiated(FD) && Info.InConstantContext && + !Info.PerformingTrialEvaluation && !Info.checkingPotentialConstantExpression()) { SemaProxy *SP = Info.getASTContext().getSemaProxy(); // Try to instantiate the definition if Sema is available // (i.e during the initial parse of the TU). - if (SP) { - SP->InstantiateFunctionDefinition(Loc, const_cast<FunctionDecl *>(FD)); - } + if (SP) + SP->instantiateFunctionDefinition(Loc, const_cast<FunctionDecl *>(FD)); } } @@ -7378,7 +7383,7 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceRange CallRange, if (!Info.CheckCallLimit(CallRange.getBegin())) return false; - InstantiateFunctionBeforeCall(DD, Info, CallRange.getBegin()); + TryInstantiateFunctionBeforeCall(DD, Info, CallRange.getBegin()); const FunctionDecl *Definition = nullptr; const Stmt *Body = DD->getBody(Definition); @@ -8847,7 +8852,7 @@ class ExprEvaluatorBase SourceLocation Loc = E->getExprLoc(); - InstantiateFunctionBeforeCall(FD, Info, Loc); + TryInstantiateFunctionBeforeCall(FD, Info, Loc); const FunctionDecl *Definition = nullptr; const Stmt *Body = FD->getBody(Definition); @@ -11369,7 +11374,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, return handleDefaultInitValue(T, Result); } - InstantiateFunctionBeforeCall(FD, Info, E->getBeginLoc()); + TryInstantiateFunctionBeforeCall(FD, Info, E->getBeginLoc()); const FunctionDecl *Definition = nullptr; const Stmt *Body = FD->getBody(Definition); @@ -11412,7 +11417,7 @@ bool RecordExprEvaluator::VisitCXXInheritedCtorInitExpr( if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl()) return false; - InstantiateFunctionBeforeCall(FD, Info, E->getBeginLoc()); + TryInstantiateFunctionBeforeCall(FD, Info, E->getBeginLoc()); const FunctionDecl *Definition = nullptr; const Stmt *Body = FD->getBody(Definition); diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp index 5a24342e73ca4..5630b96927c38 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -42,11 +42,11 @@ IncrementalParser::IncrementalParser(CompilerInstance &Instance, External->StartTranslationUnit(Consumer); P->Initialize(); - S.RegisterSemaProxy(); + S.registerSemaProxy(); } IncrementalParser::~IncrementalParser() { - S.UnregisterSemaProxy(); + S.unregisterSemaProxy(); P.reset(); } diff --git a/clang/lib/Parse/ParseAST.cpp b/clang/lib/Parse/ParseAST.cpp index 1cea282f13a00..01e17a563838a 100644 --- a/clang/lib/Parse/ParseAST.cpp +++ b/clang/lib/Parse/ParseAST.cpp @@ -163,22 +163,26 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { }); P.Initialize(); - auto Unregister = - llvm::make_scope_exit([&S]() { S.UnregisterSemaProxy(); }); - S.RegisterSemaProxy(); + S.registerSemaProxy(); Parser::DeclGroupPtrTy ADecl; Sema::ModuleImportState ImportState; EnterExpressionEvaluationContext PotentiallyEvaluated( S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); - for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF; - AtEOF = P.ParseTopLevelDecl(ADecl, ImportState)) { - // If we got a null return and something *was* parsed, ignore it. This - // is due to a top-level semicolon, an action override, or a parse error - // skipping something. - if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) - return; + { + // Remove the sema proxy after the initial parse. + llvm::scope_exit SemaProxyScope([&S]() { S.unregisterSemaProxy(); }); + + for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF; + AtEOF = P.ParseTopLevelDecl(ADecl, ImportState)) { + + // If we got a null return and something *was* parsed, ignore it. This + // is due to a top-level semicolon, an action override, or a parse error + // skipping something. + if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) + return; + } } } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index bdc5155214730..d562c8dc95374 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -624,14 +624,14 @@ Sema::~Sema() { SemaPPCallbackHandler->reset(); } -void Sema::RegisterSemaProxy() { +void Sema::registerSemaProxy() { // Let the AST context rely on Sema for // AST mutation features that require semantic analysis // (lazy instantiation, reflection, etc). Context.setSemaProxy(getSemaProxyImplementation(*this)); } -void Sema::UnregisterSemaProxy() { Context.setSemaProxy({}); } +void Sema::unregisterSemaProxy() { Context.setSemaProxy({}); } void Sema::runWithSufficientStackSpace(SourceLocation Loc, llvm::function_ref<void()> Fn) { @@ -2982,7 +2982,7 @@ class SemaProxyImplementation final : public SemaProxy { public: SemaProxyImplementation(Sema &SemaRef) : SemaRef(SemaRef) {} - void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, + void instantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function) override { SemaRef.InstantiateFunctionDefinition( PointOfInstantiation, Function, /*Recursive=*/true, >From 8daac7ba06c7c8e1c3413c4bc524ad055cc6597f Mon Sep 17 00:00:00 2001 From: Corentin Jabot <[email protected]> Date: Mon, 16 Feb 2026 19:53:16 +0100 Subject: [PATCH 5/8] fix rebase --- clang/docs/ReleaseNotes.rst | 173 +----------------------------- clang/lib/AST/ByteCode/Interp.cpp | 2 +- 2 files changed, 6 insertions(+), 169 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3af3f81b4f53c..68400853e36fc 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -140,97 +140,9 @@ Non-comprehensive list of changes in this release Usable in constant expressions. Implicit conversion is supported for class/struct types with conversion operators. -<<<<<<< HEAD - A new generic bit-reverse builtin function ``__builtin_bitreverseg`` that extends bit-reversal support to all standard integers type, including ``_BitInt`` -======= -- Added ``__builtin_elementwise_ldexp``. - -- Added ``__builtin_elementwise_fshl`` and ``__builtin_elementwise_fshr``. - -- ``__builtin_elementwise_abs`` can now be used in constant expression. - -- Added ``__builtin_elementwise_minnumnum`` and ``__builtin_elementwise_maxnumnum``. - -- Trapping UBSan (e.g. ``-fsanitize=undefined -fsanitize-trap=undefined``) now - emits a string describing the reason for trapping into the generated debug - info. This feature allows debuggers (e.g. LLDB) to display the reason for - trapping if the trap is reached. The string is currently encoded in the debug - info as an artificial frame that claims to be inlined at the trap location. - The function used for the artificial frame is an artificial function whose - name encodes the reason for trapping. The encoding used is currently the same - as ``__builtin_verbose_trap`` but might change in the future. This feature is - enabled by default but can be disabled by compiling with - ``-fno-sanitize-debug-trap-reasons``. The feature has a ``basic`` and - ``detailed`` mode (the default). The ``basic`` mode emits a hard-coded string - per trap kind (e.g. ``Integer addition overflowed``) and the ``detailed`` mode - emits a more descriptive string describing each individual trap (e.g. ``signed - integer addition overflow in 'a + b'``). The ``detailed`` mode produces larger - debug info than ``basic`` but is more helpful for debugging. The - ``-fsanitize-debug-trap-reasons=`` flag can be used to switch between the - different modes or disable the feature entirely. Note due to trap merging in - optimized builds (i.e. in each function all traps of the same kind get merged - into the same trap instruction) the trap reasons might be removed. To prevent - this build without optimizations (i.e. use `-O0` or use the `optnone` function - attribute) or use the `fno-sanitize-merge=` flag in optimized builds. - -- ``__builtin_elementwise_max`` and ``__builtin_elementwise_min`` functions for integer types can - now be used in constant expressions. - -- A vector of booleans is now a valid condition for the ternary ``?:`` operator. - This binds to a simple vector select operation. - -- Added ``__builtin_masked_load``, ``__builtin_masked_expand_load``, - ``__builtin_masked_store``, ``__builtin_masked_compress_store`` for - conditional memory loads from vectors. Binds to the LLVM intrinsics of the - same name. - -- Added ``__builtin_masked_gather`` and ``__builtin_masked_scatter`` for - conditional gathering and scattering operations on vectors. Binds to the LLVM - intrinsics of the same name. - -- The ``__builtin_popcountg``, ``__builtin_ctzg``, and ``__builtin_clzg`` - functions now accept fixed-size boolean vectors. - -- Use of ``__has_feature`` to detect the ``ptrauth_qualifier`` and ``ptrauth_intrinsics`` - features has been deprecated, and is restricted to the arm64e target only. The - correct method to check for these features is to test for the ``__PTRAUTH__`` - macro. - -- Added a new builtin, ``__builtin_dedup_pack``, to remove duplicate types from a parameter pack. - This feature is particularly useful in template metaprogramming for normalizing type lists. - The builtin produces a new, unexpanded parameter pack that can be used in contexts like template - argument lists or base specifiers. - - .. code-block:: c++ - - template <typename...> struct TypeList; - - // The resulting type is TypeList<int, double, char> - using MyTypeList = TypeList<__builtin_dedup_pack<int, double, int, char, double>...>; - - Currently, the use of ``__builtin_dedup_pack`` is limited to template arguments and base - specifiers, it also must be used within a template context. - -- ``__builtin_assume_dereferenceable`` now accepts non-constant size operands. - -- Fixed a crash when the second argument to ``__builtin_assume_aligned`` was not constant (#GH161314) - -- Introduce support for :doc:`allocation tokens <AllocToken>` to enable - allocator-level heap organization strategies. A feature to instrument all - allocation functions with a token ID can be enabled via the - ``-fsanitize=alloc-token`` flag. - -- A new generic byte swap builtin function ``__builtin_bswapg`` that extends the existing - __builtin_bswap{16,32,64} function family to support all standard integer types. - -- A builtin ``__builtin_infer_alloc_token(<args>, ...)`` is provided to allow - compile-time querying of allocation token IDs, where the builtin arguments - mirror those normally passed to an allocation function. - -- Clang now rejects the invalid use of ``constexpr`` with ``auto`` and an explicit type in C. (#GH163090) ->>>>>>> 3f06fd997749 ([Clang] Instantiate constexpr function when they are needed.) New Compiler Flags ------------------ @@ -318,8 +230,6 @@ Improvements to Clang's diagnostics .. code-block:: c++ -<<<<<<< HEAD -<<<<<<< HEAD struct DanglingView { std::string_view view; DanglingView(std::string s) : view(s) {} // warning: address of stack memory escapes to a field @@ -331,27 +241,11 @@ Improvements to Clang's diagnostics when accessing a member function on a past-the-end array element. (#GH179128) -- Added a missing space to the FixIt for the ``implicit-int`` group of diagnostics and +- Added a missing space to the FixIt for the ``implicit-int`` group of diagnostics and made sure that only one such diagnostic and FixIt is emitted per declaration group. (#GH179354) - The ``-Wloop-analysis`` warning has been extended to catch more cases of variable modification inside lambda expressions (#GH132038). -======= -- Fixed a crash when enabling ``-fdiagnostics-format=sarif`` and the output - carries messages like 'In file included from ...' or 'In module ...'. - Now the include/import locations are written into `sarif.run.result.relatedLocations`. - -- Clang now generates a fix-it for C++20 designated initializers when the - initializers do not match the declaration order in the structure. ->>>>>>> 3f06fd997749 ([Clang] Instantiate constexpr function when they are needed.) -======= -- Fixed a crash when enabling ``-fdiagnostics-format=sarif`` and the output - carries messages like 'In file included from ...' or 'In module ...'. - Now the include/import locations are written into `sarif.run.result.relatedLocations`. - -- Clang now generates a fix-it for C++20 designated initializers when the - initializers do not match the declaration order in the structure. ->>>>>>> ea6211a89115 (address more feedback) Improvements to Clang's time-trace ---------------------------------- @@ -386,68 +280,11 @@ Bug Fixes to Attribute Support Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ -<<<<<<< HEAD - Fixed a crash when instantiating ``requires`` expressions involving substitution failures in C++ concepts. (#GH176402) - Fixed a crash when a default argument is passed to an explicit object parameter. (#GH176639) - Fixed a crash when diagnosing an invalid static member function with an explicit object parameter (#GH177741) -- Fixed a crash when evaluating uninitialized GCC vector/ext_vector_type vectors in ``constexpr``. (#GH180044) -======= -- Diagnose binding a reference to ``*nullptr`` during constant evaluation. (#GH48665) -- Suppress ``-Wdeprecated-declarations`` in implicitly generated functions. (#GH147293) -- Fix a crash when deleting a pointer to an incomplete array (#GH150359). -- Fixed a mismatched lambda scope bug when propagating up ``consteval`` within nested lambdas. (#GH145776) -- Disallow immediate escalation in destructors. (#GH109096) -- Fix an assertion failure when expression in assumption attribute - (``[[assume(expr)]]``) creates temporary objects. -- Fix the dynamic_cast to final class optimization to correctly handle - casts that are guaranteed to fail (#GH137518). -- Fix bug rejecting partial specialization of variable templates with auto NTTPs (#GH118190). -- Fix a crash if errors "member of anonymous [...] redeclares" and - "initializing multiple members of union" coincide (#GH149985). -- Fix a crash when using ``explicit(bool)`` in pre-C++11 language modes. (#GH152729) -- Fix the parsing of variadic member functions when the ellipis immediately follows a default argument.(#GH153445) -- Fix a crash when using an explicit object parameter in a non-member function with an invalid return type.(#GH173943) -- Fixed a bug that caused ``this`` captured by value in a lambda with a dependent explicit object parameter to not be - instantiated properly. (#GH154054) -- Fixed a bug where our ``member-like constrained friend`` checking caused an incorrect analysis of lambda captures. (#GH156225) -- Fixed a crash when implicit conversions from initialize list to arrays of - unknown bound during constant evaluation. (#GH151716) - Instantiate constexpr functions as needed before they are evaluated. (#GH73232) (#GH35052) (#GH100897) -- Support the dynamic_cast to final class optimization with pointer - authentication enabled. (#GH152601) -- Fix the check for narrowing int-to-float conversions, so that they are detected in - cases where converting the float back to an integer is undefined behaviour (#GH157067). -- Stop rejecting C++11-style attributes on the first argument of constructors in older - standards. (#GH156809). -- Fix a crash when applying binary or ternary operators to two same function types with different spellings, - where at least one of the function parameters has an attribute which affects - the function type. -- Fix an assertion failure when a ``constexpr`` variable is only referenced through - ``__builtin_addressof``, and related issues with builtin arguments. (#GH154034) -- Fix an assertion failure when taking the address on a non-type template parameter argument of - object type. (#GH151531) -- Suppress ``-Wdouble-promotion`` when explicitly asked for with C++ list initialization (#GH33409). -- Fix the result of `__builtin_is_implicit_lifetime` for types with a user-provided constructor. (#GH160610) -- Correctly deduce return types in ``decltype`` expressions. (#GH160497) (#GH56652) (#GH116319) (#GH161196) -- Fixed a crash in the pre-C++23 warning for attributes before a lambda declarator (#GH161070). -- Fix a crash when attempting to deduce a deduction guide from a non deducible template template parameter. (#130604) -- Fix for clang incorrectly rejecting the default construction of a union with - nontrivial member when another member has an initializer. (#GH81774) -- Fixed a template depth issue when parsing lambdas inside a type constraint. (#GH162092) -- Fix the support of zero-length arrays in SFINAE context. (#GH170040) -- Diagnose unresolved overload sets in non-dependent compound requirements. (#GH51246) (#GH97753) -- Fix a crash when extracting unavailable member type from alias in template deduction. (#GH165560) -- Fix incorrect diagnostics for lambdas with init-captures inside braced initializers. (#GH163498) -- Fixed an issue where templates prevented nested anonymous records from checking the deletion of special members. (#GH167217) -- Fixed serialization of pack indexing types, where we failed to expand those packs from a PCH/module. (#GH172464) -- Fixed spurious diagnoses of certain nested lambda expressions. (#GH149121) (#GH156579) -- Fix the result of ``__is_pointer_interconvertible_base_of`` when arguments are qualified and passed via template parameters. (#GH135273) -- Fixed a crash when evaluating nested requirements in requires-expressions that reference invented parameters. (#GH166325) -- Fixed a crash when standard comparison categories (e.g. ``std::partial_ordering``) are defined with incorrect static member types. (#GH170015) (#GH56571) -- Fixed a crash when parsing the ``enable_if`` attribute on C function declarations with identifier-list parameters. (#GH173826) -- Fixed an assertion failure triggered by nested lambdas during capture handling. (#GH172814) -- Fixed an assertion failure in vector conversions involving instantiation-dependent template expressions. (#GH173347) ->>>>>>> 3f06fd997749 ([Clang] Instantiate constexpr function when they are needed.) +- Fixed a crash when evaluating uninitialized GCC vector/ext_vector_type vectors in ``constexpr``. (#GH180044) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -548,7 +385,7 @@ AST Matchers clang-format ------------ -- Add ``ObjCSpaceAfterMethodDeclarationPrefix`` option to control space between the +- Add ``ObjCSpaceAfterMethodDeclarationPrefix`` option to control space between the '-'/'+' and the return type in Objective-C method declarations libclang @@ -586,8 +423,8 @@ Python Binding Changes Affected methods: ``isKindOptional``, ``isKindTypedText``, ``isKindPlaceHolder``, ``isKindInformative`` and ``isKindResultType``. - Add a deprecation warning to ``CodeCompletionResults.results``. - This property will become an implementation detail with changed behavior in a - future release and should not be used directly.. Existing uses of + This property will become an implementation detail with changed behavior in a + future release and should not be used directly.. Existing uses of ``CodeCompletionResults.results`` should be changed to directly use ``CodeCompletionResults``: it nows supports ``__len__`` and ``__getitem__``, so it can be used the same as ``CodeCompletionResults.results``. diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index a7729741cbc5c..2b750cfb4e0d7 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1960,7 +1960,7 @@ bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, // because the Call/CallVirt below might access the instance pointer // but the Function's information about them is wrong. if (!F->isFullyCompiled()) - compileFunction(S, F); + compileFunction(S, F, OpPC); if (!CheckCallable(S, OpPC, F)) return false; >From 0a1ca008eceaff8c71d821150a84c129302a6be3 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <[email protected]> Date: Mon, 16 Feb 2026 20:23:25 +0100 Subject: [PATCH 6/8] check lookup happens in the appropriate context --- .../SemaCXX/constexpr-late-instantiation.cpp | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/clang/test/SemaCXX/constexpr-late-instantiation.cpp b/clang/test/SemaCXX/constexpr-late-instantiation.cpp index 24df761cf0a52..38f056aacb607 100644 --- a/clang/test/SemaCXX/constexpr-late-instantiation.cpp +++ b/clang/test/SemaCXX/constexpr-late-instantiation.cpp @@ -91,6 +91,28 @@ constexpr int x = X().f( 1 ); #if __cplusplus > 202002L +namespace instantiation_context_lookup { + +static constexpr int i = 42; +static constexpr int v = 8; + + +constexpr int f(auto); + +constexpr int g(int v = 42) { + static constexpr int i = 1; + return f(1); + return 0; +} + +constexpr int f(auto) { + return i + v; +} + +static_assert(g() == 50); + +} + namespace GH35052 { template <typename F> >From 1b130562ce70518bbe549e3e765b3d2215e6bc03 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <[email protected]> Date: Mon, 2 Mar 2026 15:11:50 +0100 Subject: [PATCH 7/8] add comments --- clang/include/clang/AST/ASTContext.h | 6 ++++++ clang/test/SemaCXX/constexpr-late-instantiation.cpp | 7 ++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index f4ca6cf85259e..de06582636c29 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1440,8 +1440,14 @@ class ASTContext : public RefCountedBase<ASTContext> { /// with this AST context, if any. ASTMutationListener *getASTMutationListener() const { return Listener; } + /// Returns a SemaProxy*, i.e an object through which interact with Sema. + /// This will return null, unless setSemaProxy has been called. + /// As Sema is only available during parsing, getSemaProxy will return null + /// during CodeGen and when using the AST from tooling. SemaProxy *getSemaProxy(); + /// Set the SemaProxy instance + /// This function is called from Sema during the initial parsing of a TU. void setSemaProxy(std::unique_ptr<SemaProxy> Proxy); void PrintStats() const; diff --git a/clang/test/SemaCXX/constexpr-late-instantiation.cpp b/clang/test/SemaCXX/constexpr-late-instantiation.cpp index 38f056aacb607..f6e13d762ae1a 100644 --- a/clang/test/SemaCXX/constexpr-late-instantiation.cpp +++ b/clang/test/SemaCXX/constexpr-late-instantiation.cpp @@ -86,6 +86,7 @@ class X } }; +// check that g is instantiated here. constexpr int x = X().f( 1 ); } @@ -125,7 +126,7 @@ constexpr int func(F f) { int test() { auto predicate = [](auto v) constexpr -> bool { return v == 1; }; - return func(predicate); + return func(predicate); // check that "predicate" is instantiated. } @@ -141,7 +142,7 @@ struct foo { }; struct bar { - foo x; + foo x; // check that the lambda gets instantiated. }; } // namespace GH115118 @@ -159,7 +160,7 @@ constexpr auto foo() noexcept { return result; } -void test() { foo<void>(); } +void test() { foo<void>(); } // check that the lambda gets instantiated. } // namespace GH100897 >From 7a88bbe246447d43fbd8d2d74a6b339533bc58f3 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <[email protected]> Date: Mon, 2 Mar 2026 15:14:36 +0100 Subject: [PATCH 8/8] inline getSemaProxy --- clang/include/clang/AST/ASTContext.h | 2 +- clang/lib/AST/ASTContext.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index de06582636c29..07045b286e7c9 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1444,7 +1444,7 @@ class ASTContext : public RefCountedBase<ASTContext> { /// This will return null, unless setSemaProxy has been called. /// As Sema is only available during parsing, getSemaProxy will return null /// during CodeGen and when using the AST from tooling. - SemaProxy *getSemaProxy(); + SemaProxy *getSemaProxy() { return SemaProxyPtr.get(); } /// Set the SemaProxy instance /// This function is called from Sema during the initial parsing of a TU. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 8e8ffb1138607..da6b38595cb9b 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -963,8 +963,6 @@ ASTContext::setExternalSource(IntrusiveRefCntPtr<ExternalASTSource> Source) { ExternalSource = std::move(Source); } -SemaProxy *ASTContext::getSemaProxy() { return SemaProxyPtr.get(); } - void ASTContext::setSemaProxy(std::unique_ptr<SemaProxy> Proxy) { assert((!SemaProxyPtr || !Proxy) && "SemaProxy already set"); SemaProxyPtr = std::move(Proxy); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
