https://github.com/bcardosolopes created https://github.com/llvm/llvm-project/pull/214926
emitStaticVarDecl bailed with errorNYI whenever a `static` local had a variably modified type -- in practice a pointer to a VLA, since the static itself can't be one. CIRGenFunction::emitVariablyModifiedType already exists and already handles this walk, so this is the same one-liner classic CodeGen uses in CodeGenFunction::EmitStaticVarDecl. Found when building binutils. This is autoconf's AC_C_VARARRAYS probe, so the NYI was quietly changing what configure-based projects build: the probe failed under -fclangir, config.h came out with HAVE_C_VARARRAYS undefined and __STDC_NO_VLA__ defined, and gnulib took its non-VLA fallback paths. Nothing errored -- the CIR build just compiled different source than the baseline. >From 71152e5be3909318542cb48e40a800b499105c36 Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes <[email protected]> Date: Fri, 7 Aug 2026 20:53:30 -0700 Subject: [PATCH] [CIR] Evaluate VLA bounds for a static local of variably modified type emitStaticVarDecl bailed with errorNYI whenever a `static` local had a variably modified type -- in practice a pointer to a VLA, since the static itself can't be one. CIRGenFunction::emitVariablyModifiedType already exists and already handles this walk, so this is the same one-liner classic CodeGen uses in CodeGenFunction::EmitStaticVarDecl. This is autoconf's AC_C_VARARRAYS probe, so the NYI was quietly changing what configure-based projects build: the probe failed under -fclangir, config.h came out with HAVE_C_VARARRAYS undefined and __STDC_NO_VLA__ defined, and gnulib took its non-VLA fallback paths. Nothing errored -- the CIR build just compiled different source than the baseline. Add clang/test/CIR/CodeGen/static-vla-pointer.c covering both the AC_C_VARARRAYS shape and a bound with side effects, checked against classic CodeGen. --- clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 6 +-- clang/test/CIR/CodeGen/static-vla-pointer.c | 57 +++++++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 clang/test/CIR/CodeGen/static-vla-pointer.c diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index e17550a8c1668..d2fa07b3afa9a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -725,10 +725,8 @@ void CIRGenFunction::emitStaticVarDecl(const VarDecl &d, // We can't have a VLA here, but we can have a pointer to a VLA, // even though that doesn't really make any sense. // Make sure to evaluate VLA bounds now so that we have them for later. - if (d.getType()->isVariablyModifiedType()) { - cgm.errorNYI(d.getSourceRange(), - "emitStaticVarDecl: variably modified type"); - } + if (d.getType()->isVariablyModifiedType()) + emitVariablyModifiedType(d.getType()); // Save the type in case adding the initializer forces a type change. mlir::Type expectedType = addr.getType(); diff --git a/clang/test/CIR/CodeGen/static-vla-pointer.c b/clang/test/CIR/CodeGen/static-vla-pointer.c new file mode 100644 index 0000000000000..1342d46ffcade --- /dev/null +++ b/clang/test/CIR/CodeGen/static-vla-pointer.c @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -Wno-error=incompatible-pointer-types -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -Wno-error=incompatible-pointer-types -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -Wno-error=incompatible-pointer-types -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +// A `static` local can't be a VLA, but it can have a variably modified type -- +// a pointer to a VLA. The variable itself is an ordinary global; the VLA bound +// still has to be evaluated in the enclosing function, for its side effects. + +int bound(void); +int buf[100]; + +// The two static locals are ordinary globals initialized to &buf. Both +// functions emit their globals into the same module prologue, so check them +// together and out of order. + +// CIR-DAG: cir.global "private" internal dso_local @side_effecting_bound.p = #cir.global_view<@buf> : !cir.ptr<!s32i> +// CIR-DAG: cir.global "private" internal dso_local @vararrays_probe.q = #cir.global_view<@buf> : !cir.ptr<!s32i> + +// LLVM-DAG: @side_effecting_bound.p = internal global ptr @buf +// LLVM-DAG: @vararrays_probe.q = internal global ptr @buf + +// OGCG-DAG: @side_effecting_bound.p = internal global ptr @buf +// OGCG-DAG: @vararrays_probe.q = internal global ptr @buf + +void side_effecting_bound(void) { + static int (*p)[bound()] = &buf; + (void)p; +} + +// CIR-LABEL: cir.func{{.*}} @side_effecting_bound() +// CIR: cir.call @bound() : () -> !s32i + +// LLVM-LABEL: define {{.*}} void @side_effecting_bound() +// LLVM: call i32 @bound() + +// OGCG-LABEL: define {{.*}} void @side_effecting_bound() +// OGCG: call i32 @bound() + +// This is autoconf's AC_C_VARARRAYS probe. It mainly has to compile at all; a +// failure here silently flips HAVE_C_VARARRAYS in every configure-based project. + +int vararrays_probe(int m, int c[m][m]) { + static int (*q)[m] = &buf; + return c && q != 0; +} + +// CIR-LABEL: cir.func{{.*}} @vararrays_probe( +// CIR: cir.get_global @vararrays_probe.q : !cir.ptr<!cir.ptr<!s32i>> + +// LLVM-LABEL: define {{.*}} i32 @vararrays_probe( +// LLVM: load ptr, ptr @vararrays_probe.q + +// OGCG-LABEL: define {{.*}} i32 @vararrays_probe( +// OGCG: load ptr, ptr @vararrays_probe.q _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
