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

Reply via email to