https://github.com/Z3rox-dev updated https://github.com/llvm/llvm-project/pull/181561
>From 5e07a4e662a671b6116e755ef8aa66fc9b050d8e Mon Sep 17 00:00:00 2001 From: Z3rox-dev <[email protected]> Date: Sun, 15 Feb 2026 21:03:16 +0100 Subject: [PATCH] [Clang][CodeGen] Fix crash on value-dependent initializer during error recovery In error-recovery scenarios (e.g., invalid template partial specializations), a global variable's initializer can remain value-dependent. Previously this triggered: 1. assert(!Init->isValueDependent()) in VarDecl::evaluateValueImpl 2. UNREACHABLE 'non-canonical or dependent type in IR-generation' This patch adds defensive checks for value-dependent initializers in three places in the CodeGen pipeline: - VarDecl::evaluateValueImpl(): return nullptr instead of asserting - ConstantEmitter::tryEmitPrivateForVarInit(): bail out early - CodeGenModule::EmitGlobalVarDefinition(): handle dependent types and skip global ctor registration for value-dependent inits Fixes #181410 --- clang/lib/AST/Decl.cpp | 9 ++++-- clang/lib/CodeGen/CGExprConstant.cpp | 6 ++++ clang/lib/CodeGen/CodeGenModule.cpp | 8 +++++- .../CodeGenCXX/crash-value-dependent-init.cpp | 28 +++++++++++++++++++ 4 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 clang/test/CodeGenCXX/crash-value-dependent-init.cpp diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 66c625f41158a..173d48135e43c 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2593,7 +2593,11 @@ APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes, EvaluatedStmt *Eval = ensureEvaluatedStmt(); const auto *Init = getInit(); - assert(!Init->isValueDependent()); + // In error-recovery scenarios (e.g., invalid template specializations), + // the initializer may remain value-dependent. Bail out gracefully instead + // of crashing, since callers already handle nullptr returns. + if (!Init || Init->isValueDependent()) + return nullptr; // We only produce notes indicating why an initializer is non-constant the // first time it is evaluated. FIXME: The notes won't always be emitted the @@ -2684,7 +2688,8 @@ bool VarDecl::checkForConstantInitialization( getASTContext().getLangOpts().C23) && "only meaningful in C++/C23"); - assert(!getInit()->isValueDependent()); + if (!getInit() || getInit()->isValueDependent()) + return false; // Evaluate the initializer to check whether it's a constant expression. Eval->HasConstantInitialization = diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index c316642a87baf..4822eb47716a8 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1873,6 +1873,12 @@ llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) { const Expr *E = D.getInit(); assert(E && "No initializer to emit"); + // In error-recovery scenarios (e.g., invalid template specializations), + // the initializer may remain value-dependent. We cannot evaluate or + // lower dependent expressions to LLVM IR, so bail out. + if (E->isValueDependent()) + return nullptr; + if (!destType->isReferenceType()) { QualType nonMemoryDestType = getNonMemoryType(CGM, destType); if (llvm::Constant *C = ConstExprEmitter(*this).Visit(E, nonMemoryDestType)) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 6a087be3751f0..92bc3786f4631 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -6134,10 +6134,16 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, QualType T = InitExpr->getType(); if (D->getType()->isReferenceType()) T = D->getType(); + // In error-recovery, the init expression's type may still be dependent. + // Fall back to the variable's declared type which should be concrete. + if (T->isDependentType()) + T = D->getType(); if (getLangOpts().CPlusPlus) { Init = EmitNullConstant(T); - if (!IsDefinitionAvailableExternally) + // If the initializer is value-dependent (error recovery with invalid + // templates), we cannot lower it to IR, so skip the global ctor. + if (!IsDefinitionAvailableExternally && !InitExpr->isValueDependent()) NeedsGlobalCtor = true; if (InitDecl->hasFlexibleArrayInit(getContext())) { ErrorUnsupported(D, "flexible array initializer"); diff --git a/clang/test/CodeGenCXX/crash-value-dependent-init.cpp b/clang/test/CodeGenCXX/crash-value-dependent-init.cpp new file mode 100644 index 0000000000000..b456004e656d1 --- /dev/null +++ b/clang/test/CodeGenCXX/crash-value-dependent-init.cpp @@ -0,0 +1,28 @@ +// RUN: not %clang_cc1 -std=c++20 -emit-llvm %s + +// Verify that we don't crash when a global variable has a value-dependent +// initializer due to an invalid template partial specialization that the +// compiler recovers from (crash-on-invalid). +// +// Previously this triggered: +// 1. assert(!Init->isValueDependent()) in VarDecl::evaluateValueImpl +// 2. UNREACHABLE "non-canonical or dependent type in IR-generation" + +template <int> +struct integer_sequence {}; + +template <int> +struct array {}; + +template <int*> +struct MetaValuesHelper; + +template <typename TupleName, TupleName kValues> +struct MetaValuesHelper<kValues> { + template <int... Is> + static array<0> MetaValuesFunc(integer_sequence<Is...>); +}; + +int kBaseIndexRegistersUsed; + +array<0> u = decltype(MetaValuesHelper<&kBaseIndexRegistersUsed>::MetaValuesFunc(integer_sequence<0>{})){}; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
