https://github.com/akash-manna-sky created 
https://github.com/llvm/llvm-project/pull/237565

Fixes #119126

The type guard in the `__builtin_constant_p` lowering uses `isFloatingType()`, 
which is also true for `_Complex` types, so a complex argument the constant 
evaluator couldn't fold reaches `EmitScalarExpr` and trips its 
`hasScalarEvaluationKind` assert.

Complex arguments now take their own path: emit the value with 
`EmitComplexExpr` and AND the `llvm.is.constant` results for the real and 
imaginary parts, which matches what the constant evaluator and GCC already do 
for complex values.

Assisted-by: LLM Tools


>From e31ff90b24bc8b89d46b954d05e58cd244042108 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Tue, 27 Oct 2026 18:40:16 +0530
Subject: [PATCH] Fixes #119126

The type guard in the `__builtin_constant_p` lowering uses `isFloatingType()`, 
which is also true for `_Complex` types, so a complex argument the constant 
evaluator couldn't fold reaches `EmitScalarExpr` and trips its 
`hasScalarEvaluationKind` assert.

Complex arguments now take their own path: emit the value with 
`EmitComplexExpr` and AND the `llvm.is.constant` results for the real and 
imaginary parts, which matches what the constant evaluator and GCC already do 
for complex values.

LLM tools were used for this contribution.
---
 clang/docs/ReleaseNotes.md                   |   1 +
 clang/lib/CodeGen/CGBuiltin.cpp              |  32 ++++--
 clang/test/CodeGen/builtin-constant-p.c      | 105 +++++++++++++++++++
 clang/test/CodeGenCXX/builtin-constant-p.cpp |  10 ++
 4 files changed, 138 insertions(+), 10 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index e6b71ba2a0b565..78ef817b380557 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -783,6 +783,7 @@ features cannot lower the translation-unit ABI level;
 - Fix a crash when using `__builtin_assume_aligned` with dynamic allocations
   during constant evaluation. (#GH173767)
 - Fixed a crash on an invalid pointer argument to `__builtin_assume_aligned`. 
(#GH194289)
+- Fixed a crash when `__builtin_constant_p` is applied to a `_Complex` value 
that could not be constant folded. (#GH119126)
 - Fixed a crash when constant-evaluating `__builtin_align_up`, 
`__builtin_align_down`,
   or `__builtin_is_aligned` with pointers without an underlying object. Null 
pointers
   are handled as aligned values, while other base-less pointers are rejected 
during constant
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index e154b9e752fd5c..1587389bb3117f 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4092,7 +4092,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
     QualType ArgType = Arg->getType();
     // FIXME: The allowance for Obj-C pointers and block pointers is historical
     // and likely a mistake.
-    if (!ArgType->isIntegralOrEnumerationType() && !ArgType->isFloatingType() 
&&
+    if (!ArgType->isIntegralOrEnumerationType() &&
+        !ArgType->isRealFloatingType() && !ArgType->isAnyComplexType() &&
         !ArgType->isObjCObjectPointerType() && !ArgType->isBlockPointerType())
       // Per the GCC documentation, only numeric constants are recognized after
       // inlining.
@@ -4103,16 +4104,27 @@ RValue CodeGenFunction::EmitBuiltinExpr(const 
GlobalDecl GD, unsigned BuiltinID,
       // side-effects.
       return RValue::get(ConstantInt::get(ResultType, 0));
 
-    Value *ArgValue = EmitScalarExpr(Arg);
-    if (ArgType->isObjCObjectPointerType()) {
-      // Convert Objective-C objects to id because we cannot distinguish 
between
-      // LLVM types for Obj-C classes as they are opaque.
-      ArgType = CGM.getContext().getObjCIdType();
-      ArgValue = Builder.CreateBitCast(ArgValue, ConvertType(ArgType));
+    Value *Result;
+    if (ArgType->isAnyComplexType()) {
+      // A complex value is constant when both of its components are.
+      ComplexPairTy ArgValue = EmitComplexExpr(Arg);
+      Function *F =
+          CGM.getIntrinsic(Intrinsic::is_constant, ArgValue.first->getType());
+      Value *Real = Builder.CreateCall(F, ArgValue.first);
+      Value *Imag = Builder.CreateCall(F, ArgValue.second);
+      Result = Builder.CreateAnd(Real, Imag);
+    } else {
+      Value *ArgValue = EmitScalarExpr(Arg);
+      if (ArgType->isObjCObjectPointerType()) {
+        // Convert Objective-C objects to id because we cannot distinguish
+        // between LLVM types for Obj-C classes as they are opaque.
+        ArgType = CGM.getContext().getObjCIdType();
+        ArgValue = Builder.CreateBitCast(ArgValue, ConvertType(ArgType));
+      }
+      Function *F =
+          CGM.getIntrinsic(Intrinsic::is_constant, ConvertType(ArgType));
+      Result = Builder.CreateCall(F, ArgValue);
     }
-    Function *F =
-        CGM.getIntrinsic(Intrinsic::is_constant, ConvertType(ArgType));
-    Value *Result = Builder.CreateCall(F, ArgValue);
     if (Result->getType() != ResultType)
       Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/false);
     return RValue::get(Result);
diff --git a/clang/test/CodeGen/builtin-constant-p.c 
b/clang/test/CodeGen/builtin-constant-p.c
index 07288069a5e3ad..085ae9aae52330 100644
--- a/clang/test/CodeGen/builtin-constant-p.c
+++ b/clang/test/CodeGen/builtin-constant-p.c
@@ -153,3 +153,108 @@ void test15(void) {
   int a, b;
   (void)__builtin_constant_p((a = b, test15_f()));
 }
+
+/* --- Complex types (GH119126) */
+
+__complex double test_complex_cond(void) {
+  // CHECK-LABEL: test_complex_cond
+  // CHECK: [[R:%.*]] = call i1 @llvm.is.constant.f64(double %f.real)
+  // CHECK: [[I:%.*]] = call i1 @llvm.is.constant.f64(double %f.imag)
+  // CHECK: and i1 [[R]], [[I]]
+  __complex double f;
+  return (__builtin_constant_p(f) ? f : 0);
+}
+
+int test_complex_float(_Complex float x) {
+  // CHECK-LABEL: test_complex_float
+  // CHECK: [[R:%.*]] = call i1 @llvm.is.constant.f32(float %x.real)
+  // CHECK: [[I:%.*]] = call i1 @llvm.is.constant.f32(float %x.imag)
+  // CHECK: [[AND:%.*]] = and i1 [[R]], [[I]]
+  // CHECK: zext i1 [[AND]] to i32
+  int r = __builtin_constant_p(x);
+  return r;
+}
+
+int test_complex_long_double(_Complex long double x) {
+  // CHECK-LABEL: test_complex_long_double
+  // CHECK: [[R:%.*]] = call i1 @llvm.is.constant.f80(x86_fp80 %x.real)
+  // CHECK: [[I:%.*]] = call i1 @llvm.is.constant.f80(x86_fp80 %x.imag)
+  // CHECK: and i1 [[R]], [[I]]
+  return __builtin_constant_p(x);
+}
+
+int test_complex_float16(_Complex _Float16 x) {
+  // CHECK-LABEL: test_complex_float16
+  // CHECK: [[R:%.*]] = call i1 @llvm.is.constant.f16(half %x.real)
+  // CHECK: [[I:%.*]] = call i1 @llvm.is.constant.f16(half %x.imag)
+  // CHECK: and i1 [[R]], [[I]]
+  return __builtin_constant_p(x);
+}
+
+int test_complex_int(_Complex int x) {
+  // CHECK-LABEL: test_complex_int
+  // CHECK: [[R:%.*]] = call i1 @llvm.is.constant.i32(i32 %x.real)
+  // CHECK: [[I:%.*]] = call i1 @llvm.is.constant.i32(i32 %x.imag)
+  // CHECK: and i1 [[R]], [[I]]
+  return __builtin_constant_p(x);
+}
+
+int test_complex_const1(void) {
+  // CHECK-LABEL: test_complex_const1
+  // CHECK: ret i32 1
+  return __builtin_constant_p(1.0i);
+}
+
+int test_complex_const2(void) {
+  // CHECK-LABEL: test_complex_const2
+  // CHECK: ret i32 1
+  return __builtin_constant_p(__builtin_complex(1.0f, 2.0f));
+}
+
+const _Complex long double c_cld = __builtin_complex(1.0L, 2.0L);
+
+int test_complex_const3(void) {
+  // CHECK-LABEL: test_complex_const3
+  // CHECK: ret i32 1
+  return __builtin_constant_p(c_cld);
+}
+
+_Complex double test_complex_f(void);
+
+int test_complex_side_effect(void) {
+  // CHECK-LABEL: test_complex_side_effect
+  // CHECK-NOT: test_complex_f
+  // CHECK-NOT: llvm.is.constant
+  // CHECK: ret i32 0
+  return __builtin_constant_p(test_complex_f());
+}
+
+/* --- Scalar controls */
+
+int test_double(double x) {
+  // CHECK-LABEL: test_double
+  // CHECK: call i1 @llvm.is.constant.f64(double %
+  // CHECK-NOT: and i1
+  // CHECK: ret i32
+  return __builtin_constant_p(x);
+}
+
+enum test_enum_t { TEST_ENUM_A };
+
+int test_enum(enum test_enum_t x) {
+  // CHECK-LABEL: test_enum
+  // CHECK: call i1 @llvm.is.constant.i32(i32 %
+  return __builtin_constant_p(x);
+}
+
+int test_bitint(_BitInt(37) x) {
+  // CHECK-LABEL: test_bitint
+  // CHECK: call i1 @llvm.is.constant.i37(i37 %
+  return __builtin_constant_p(x);
+}
+
+int test_pointer(int *p) {
+  // CHECK-LABEL: test_pointer
+  // CHECK: ret i32 0
+  return __builtin_constant_p(p);
+}
diff --git a/clang/test/CodeGenCXX/builtin-constant-p.cpp 
b/clang/test/CodeGenCXX/builtin-constant-p.cpp
index 39416b94375fe5..f57db922bdc56a 100644
--- a/clang/test/CodeGenCXX/builtin-constant-p.cpp
+++ b/clang/test/CodeGenCXX/builtin-constant-p.cpp
@@ -47,3 +47,13 @@ bool bcp_stmt_expr_2(int n) {
   // CHECK-NOT: }
   // CHECK: ret i1 false
 }
+
+// GH119126: a complex argument was emitted as a scalar.
+// CHECK-LABEL: define {{.*}} @_Z8gh119126v()
+// CHECK: [[R:%.*]] = call i1 @llvm.is.constant.f64(double %f.real)
+// CHECK: [[I:%.*]] = call i1 @llvm.is.constant.f64(double %f.imag)
+// CHECK: and i1 [[R]], [[I]]
+__complex double gh119126() {
+  __complex double f;
+  return (__builtin_constant_p(f) ? f : 0);
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to