[clang] [CIR] Fix verifier error for no-proto calls with multiple arguments (PR #182626)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 20 16:06:18 PST 2026
https://github.com/valium007 created https://github.com/llvm/llvm-project/pull/182626
Fixes #182175
>From 81b33c1d328e23ba5cd32e8b9cc1c0315b43949f Mon Sep 17 00:00:00 2001
From: valium007 <valium007 at proton.me>
Date: Sat, 21 Feb 2026 05:28:26 +0530
Subject: [PATCH] [CIR] Fix verifier error for no-proto calls with multiple
arguments
When emitting a call through a FunctionNoProtoType, the callee type was
built from FnInfo's inputs which are empty (RequiredArgs(0) produces no
required params). This gave a zero-param non-variadic FuncType, causing
the CIR verifier to fire with "incorrect number of operands for callee"
whenever such a function was called with arguments (e.g. printf without
a header under -fno-builtin or -std=c89).
Fix by building the non-variadic callee type from the actual promoted
argument types (convertType(arg.ty)) instead, matching what classic
CodeGen does in CGCall.cpp.
---
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 13 ++++++++++---
clang/test/CIR/CodeGen/no-prototype.c | 12 ++++++++++++
2 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 83d51bac01d1e..1989ead7e748a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -2039,9 +2039,16 @@ RValue CIRGenFunction::emitCall(clang::QualType calleeTy,
assert(!cir::MissingFeatures::opCallChain());
assert(!cir::MissingFeatures::addressSpace());
cir::FuncType calleeTy = getTypes().getFunctionType(funcInfo);
- // get non-variadic function type
- calleeTy = cir::FuncType::get(calleeTy.getInputs(),
- calleeTy.getReturnType(), false);
+
+ // For unprototyped functions, funcInfo was built with RequiredArgs(0) so
+ // calleeTy.getInputs() is empty. So we build the non-variadic callee type from
+ // the actual promoted argument types instead.
+ SmallVector<mlir::Type, 8> promotedArgTypes;
+ for (const CallArg &arg : args)
+ promotedArgTypes.push_back(convertType(arg.ty));
+ calleeTy = cir::FuncType::get(promotedArgTypes,
+ calleeTy.getReturnType(), /*isVarArg=*/false);
+
auto calleePtrTy = cir::PointerType::get(calleeTy);
mlir::Operation *fn = callee.getFunctionPointer();
diff --git a/clang/test/CIR/CodeGen/no-prototype.c b/clang/test/CIR/CodeGen/no-prototype.c
index d266ccb86448a..e5d4f601aec9f 100644
--- a/clang/test/CIR/CodeGen/no-prototype.c
+++ b/clang/test/CIR/CodeGen/no-prototype.c
@@ -82,3 +82,15 @@ int test5(int x) {
}
int noProto5(int x) { return x; }
// CHECK: cir.func {{.*}} no_proto {{.*}} @noProto5(%arg0: !s32i {{.+}}) -> !s32i
+
+// No-proto declaration without definition, called with multiple args of
+// different types. This is the "printf without a header" case and exercises
+// the promoted-arg-type path in emitCall.
+int noProto6();
+int test6(int x) {
+// CHECK: cir.func {{.*}} @test6
+ return noProto6("hello", x);
+ // CHECK: [[GGO:%.*]] = cir.get_global @noProto6 : !cir.ptr<!cir.func<(...) -> !s32i>>
+ // CHECK: [[CAST:%.*]] = cir.cast bitcast [[GGO]] : !cir.ptr<!cir.func<(...) -> !s32i>> -> !cir.ptr<!cir.func<(!cir.ptr<!s8i>, !s32i) -> !s32i>>
+ // CHECK: {{%.*}} = cir.call [[CAST]](%{{.*}}, %{{.*}}) : (!cir.ptr<!cir.func<(!cir.ptr<!s8i>, !s32i) -> !s32i>>, !cir.ptr<!s8i>, !s32i) -> !s32i
+}
More information about the cfe-commits
mailing list