https://github.com/Prabhuk updated https://github.com/llvm/llvm-project/pull/210846
>From 6a5c5f34f46f1a83d09d69b2781e7cd65e2728c3 Mon Sep 17 00:00:00 2001 From: prabhukr <[email protected]> Date: Mon, 20 Jul 2026 23:30:26 +0000 Subject: [PATCH 1/5] [clang] Handle C11 style function signatures in call graph section --- .../clang/Basic/DiagnosticFrontendKinds.td | 4 ++++ clang/lib/CodeGen/CGCall.cpp | 10 +++++++++- clang/lib/CodeGen/CGCall.h | 19 ++++++++++--------- clang/lib/CodeGen/CGExpr.cpp | 5 +++-- clang/test/CodeGen/call-graph-section.c | 4 ++++ 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index a688b298f2bbd..b8db966e96ead 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -407,6 +407,10 @@ def warn_profile_data_misexpect : Warning< BackendInfo, InGroup<MisExpect>; } // end of instrumentation issue category +def warn_cgs_no_proto : Warning< + "indirect call to a function with no prototype will be treated as a wildcard in the call graph section">, + InGroup<DiagGroup<"call-graph-section-no-prototype">>; + def warn_ssaf_extract_tu_summary_file_unknown_output_format : Warning<"unknown output summary file format '%0' " "specified by '--ssaf-tu-summary-file=%1'">, diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 08cb9860f2f92..50d3bc2747246 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -30,6 +30,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/CodeGenOptions.h" +#include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/CodeGen/SwiftCallingConv.h" @@ -6296,13 +6297,20 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, else if (const auto *FPT = Callee.getAbstractInfo().getCalleeFunctionProtoType()) CST = QualType(FPT, 0); + else if (const auto *FT = + Callee.getAbstractInfo().getCalleeFunctionType()) + CST = QualType(FT, 0); else llvm_unreachable( "Cannot find the callee type to generate callee_type metadata."); // Set type identifier metadata of indirect calls for call graph section. - if (!CST.isNull()) + if (!CST.isNull()) { CGM.createCalleeTypeMetadataForIcall(CST, *callOrInvoke); + if (!CST->isFunctionProtoType() && + CGM.getCodeGenOpts().CallGraphSection) + CGM.getDiags().Report(Loc, diag::warn_cgs_no_proto); + } } } diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h index 5df7f0d08d070..9c5ffe89367e3 100644 --- a/clang/lib/CodeGen/CGCall.h +++ b/clang/lib/CodeGen/CGCall.h @@ -41,22 +41,23 @@ namespace CodeGen { /// Abstract information about a function or function prototype. class CGCalleeInfo { - /// The function prototype of the callee. - const FunctionProtoType *CalleeProtoTy; + /// The function type of the callee. + const FunctionType *CalleeFunctionTy; /// The function declaration of the callee. GlobalDecl CalleeDecl; public: - explicit CGCalleeInfo() : CalleeProtoTy(nullptr) {} - CGCalleeInfo(const FunctionProtoType *calleeProtoTy, GlobalDecl calleeDecl) - : CalleeProtoTy(calleeProtoTy), CalleeDecl(calleeDecl) {} - CGCalleeInfo(const FunctionProtoType *calleeProtoTy) - : CalleeProtoTy(calleeProtoTy) {} + explicit CGCalleeInfo() : CalleeFunctionTy(nullptr) {} + CGCalleeInfo(const FunctionType *calleeFunctionTy, GlobalDecl calleeDecl) + : CalleeFunctionTy(calleeFunctionTy), CalleeDecl(calleeDecl) {} + CGCalleeInfo(const FunctionType *calleeFunctionTy) + : CalleeFunctionTy(calleeFunctionTy) {} CGCalleeInfo(GlobalDecl calleeDecl) - : CalleeProtoTy(nullptr), CalleeDecl(calleeDecl) {} + : CalleeFunctionTy(nullptr), CalleeDecl(calleeDecl) {} + const FunctionType *getCalleeFunctionType() const { return CalleeFunctionTy; } const FunctionProtoType *getCalleeFunctionProtoType() const { - return CalleeProtoTy; + return dyn_cast_or_null<FunctionProtoType>(CalleeFunctionTy); } const GlobalDecl getCalleeDecl() const { return CalleeDecl; } }; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index dd42e9550316d..383a5f50b57a8 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -6646,7 +6646,8 @@ CGCallee CodeGenFunction::EmitCallee(const Expr *E) { dyn_cast_or_null<VarDecl>(E->getReferencedDeclOfCallee())) { GD = GlobalDecl(VD); } - CGCalleeInfo CalleeInfo(FunctionType->getAs<FunctionProtoType>(), GD); + CGCalleeInfo CalleeInfo(FunctionType->castAs<clang::FunctionType>(), + GD); CGCallee Callee(CalleeInfo, ConvertFuncrefToPtr(Result.first), Result.second); return Callee; @@ -6690,7 +6691,7 @@ CGCallee CodeGenFunction::EmitCallee(const Expr *E) { dyn_cast_or_null<VarDecl>(E->getReferencedDeclOfCallee())) GD = GlobalDecl(VD); - CGCalleeInfo calleeInfo(functionType->getAs<FunctionProtoType>(), GD); + CGCalleeInfo calleeInfo(functionType->castAs<clang::FunctionType>(), GD); CGPointerAuthInfo pointerAuth = CGM.getFunctionPointerAuthInfo(functionType); CGCallee callee(calleeInfo, ConvertFuncrefToPtr(calleePtr), pointerAuth); return callee; diff --git a/clang/test/CodeGen/call-graph-section.c b/clang/test/CodeGen/call-graph-section.c index cb2f9015b7ff5..52899ef20b790 100644 --- a/clang/test/CodeGen/call-graph-section.c +++ b/clang/test/CodeGen/call-graph-section.c @@ -6,6 +6,9 @@ // RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fexperimental-call-graph-section \ // RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,MS %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \ +// RUN: -emit-llvm -o /dev/null %s 2>&1 | FileCheck --check-prefixes=WARNING %s + // CHECK-LABEL: define {{(dso_local)?}} void @foo( // CHECK-SAME: {{.*}} !callgraph [[F_TVOID:![0-9]+]] void foo() { @@ -17,6 +20,7 @@ void bar() { void (*fp)() = foo; // ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] // MS: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] + // WARNING: warning: indirect call to a function with no prototype will be treated as a wildcard in the call graph section [-Wcall-graph-section-no-prototype] fp(); } >From fac539dad6f5c6cdef04b3f7864c7f652713556c Mon Sep 17 00:00:00 2001 From: prabhukr <[email protected]> Date: Tue, 21 Jul 2026 00:22:30 +0000 Subject: [PATCH 2/5] Improve warning text. --- .../clang/Basic/DiagnosticFrontendKinds.td | 2 +- clang/lib/CodeGen/CGCall.cpp | 11 ++++-- clang/test/CodeGen/call-graph-section.c | 36 +++++++++++++++++-- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index b8db966e96ead..ee85fd288fc1f 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -408,7 +408,7 @@ def warn_profile_data_misexpect : Warning< } // end of instrumentation issue category def warn_cgs_no_proto : Warning< - "indirect call to a function with no prototype will be treated as a wildcard in the call graph section">, + "indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: %0, type string: %1)%select{| even though arguments are passed at this call site}2">, InGroup<DiagGroup<"call-graph-section-no-prototype">>; def warn_ssaf_extract_tu_summary_file_unknown_output_format : diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 50d3bc2747246..c54686481fee5 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -6308,8 +6308,15 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (!CST.isNull()) { CGM.createCalleeTypeMetadataForIcall(CST, *callOrInvoke); if (!CST->isFunctionProtoType() && - CGM.getCodeGenOpts().CallGraphSection) - CGM.getDiags().Report(Loc, diag::warn_cgs_no_proto); + CGM.getCodeGenOpts().CallGraphSection) { + llvm::Metadata *MD = + CGM.CreateMetadataIdentifierForCallGraphType(CST); + StringRef TypeStr; + if (auto *MDS = dyn_cast_or_null<llvm::MDString>(MD)) + TypeStr = MDS->getString(); + CGM.getDiags().Report(Loc, diag::warn_cgs_no_proto) + << CST << TypeStr << !CallArgs.empty(); + } } } } diff --git a/clang/test/CodeGen/call-graph-section.c b/clang/test/CodeGen/call-graph-section.c index 52899ef20b790..60af5ee18fe5d 100644 --- a/clang/test/CodeGen/call-graph-section.c +++ b/clang/test/CodeGen/call-graph-section.c @@ -7,7 +7,7 @@ // RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,MS %s // RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \ -// RUN: -emit-llvm -o /dev/null %s 2>&1 | FileCheck --check-prefixes=WARNING %s +// RUN: -emit-llvm -o /dev/null %s 2>&1 | FileCheck --check-prefixes=WARN_NO_PROTOTYPE %s // CHECK-LABEL: define {{(dso_local)?}} void @foo( // CHECK-SAME: {{.*}} !callgraph [[F_TVOID:![0-9]+]] @@ -20,7 +20,7 @@ void bar() { void (*fp)() = foo; // ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] // MS: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] - // WARNING: warning: indirect call to a function with no prototype will be treated as a wildcard in the call graph section [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'void ()', type string: _ZTSFvE) [-Wcall-graph-section-no-prototype] fp(); } @@ -78,6 +78,34 @@ void stf() { fp_stparam(St2, &St2); } +struct my_struct; + +// CHECK-LABEL: define {{(dso_local)?}} ptr @create_my_struct( +// CHECK-SAME: {{.*}} !callgraph [[F_TMY_STRUCT:![0-9]+]] +struct my_struct *create_my_struct() { + return 0; +} + +// CHECK-LABEL: define {{(dso_local)?}} void @test_struct_ptr_return( +// CHECK-SAME: {{.*}} !callgraph [[F_TVOID]] +void test_struct_ptr_return() { + struct my_struct *(*fp)() = create_my_struct; + // ITANIUM: call {{.*}}, !callee_type [[F_TMY_STRUCT_CT:![0-9]+]] + // MS: call {{.*}}, !callee_type [[F_TMY_STRUCT_CT:![0-9]+]] + // WARN_NO_PROTOTYPE: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'struct my_struct *()', type string: _ZTSFP9my_structE) [-Wcall-graph-section-no-prototype] + fp(); +} + +// CHECK-LABEL: define {{(dso_local)?}} void @test_no_proto_with_args( +// CHECK-SAME: {{.*}} !callgraph [[F_TVOID]] +void test_no_proto_with_args() { + void (*fp)() = foo; + // ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] + // MS: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] + // WARN_NO_PROTOTYPE: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'void ()', type string: _ZTSFvE) even though arguments are passed at this call site [-Wcall-graph-section-no-prototype] + fp(1); +} + // ITANIUM: [[F_TVOID]] = !{!"_ZTSFvE"} // ITANIUM: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]} // ITANIUM: [[F_TPRIMITIVE]] = !{!"_ZTSFicfdE"} @@ -86,6 +114,8 @@ void stf() { // ITANIUM: [[F_TPTR_CT]] = !{[[F_TPTR:![0-9]+]]} // ITANIUM: [[F_TSTRUCT]] = !{!"_ZTSFv3st2PS_E"} // ITANIUM: [[F_TSTRUCT_CT]] = !{[[F_TSTRUCT:![0-9]+]]} +// ITANIUM: [[F_TMY_STRUCT]] = !{!"_ZTSFP9my_structE"} +// ITANIUM: [[F_TMY_STRUCT_CT]] = !{[[F_TMY_STRUCT:![0-9]+]]} // MS: [[F_TVOID]] = !{!"?6AX@Z"} // MS: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]} @@ -95,3 +125,5 @@ void stf() { // MS: [[F_TPTR_CT]] = !{[[F_TPTR:![0-9]+]]} // MS: [[F_TSTRUCT]] = !{!"?6AXUst2@@PEAU0@@Z"} // MS: [[F_TSTRUCT_CT]] = !{[[F_TSTRUCT:![0-9]+]]} +// MS: [[F_TMY_STRUCT]] = !{!"?6APEAUmy_struct@@@Z"} +// MS: [[F_TMY_STRUCT_CT]] = !{[[F_TMY_STRUCT:![0-9]+]]} >From 4459945f20f1095fd5d5e4184c4becfec9790af8 Mon Sep 17 00:00:00 2001 From: prabhukr <[email protected]> Date: Tue, 21 Jul 2026 17:36:02 +0000 Subject: [PATCH 3/5] Include MS ABI warnings too. --- clang/test/CodeGen/call-graph-section.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/clang/test/CodeGen/call-graph-section.c b/clang/test/CodeGen/call-graph-section.c index 60af5ee18fe5d..7a5f9efe322cb 100644 --- a/clang/test/CodeGen/call-graph-section.c +++ b/clang/test/CodeGen/call-graph-section.c @@ -7,7 +7,10 @@ // RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,MS %s // RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \ -// RUN: -emit-llvm -o /dev/null %s 2>&1 | FileCheck --check-prefixes=WARN_NO_PROTOTYPE %s +// RUN: -emit-llvm -o /dev/null %s 2>&1 | FileCheck --check-prefixes=WARN_NO_PROTOTYPE_ITANIUM %s + +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fexperimental-call-graph-section \ +// RUN: -emit-llvm -o /dev/null %s 2>&1 | FileCheck --check-prefixes=WARN_NO_PROTOTYPE_MS %s // CHECK-LABEL: define {{(dso_local)?}} void @foo( // CHECK-SAME: {{.*}} !callgraph [[F_TVOID:![0-9]+]] @@ -20,7 +23,8 @@ void bar() { void (*fp)() = foo; // ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] // MS: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] - // WARN_NO_PROTOTYPE: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'void ()', type string: _ZTSFvE) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'void ()', type string: _ZTSFvE) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'void ()', type string: ?6AX@Z) [-Wcall-graph-section-no-prototype] fp(); } @@ -92,7 +96,8 @@ void test_struct_ptr_return() { struct my_struct *(*fp)() = create_my_struct; // ITANIUM: call {{.*}}, !callee_type [[F_TMY_STRUCT_CT:![0-9]+]] // MS: call {{.*}}, !callee_type [[F_TMY_STRUCT_CT:![0-9]+]] - // WARN_NO_PROTOTYPE: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'struct my_struct *()', type string: _ZTSFP9my_structE) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'struct my_struct *()', type string: _ZTSFP9my_structE) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'struct my_struct *()', type string: ?6APEAUmy_struct@@@Z) [-Wcall-graph-section-no-prototype] fp(); } @@ -102,7 +107,8 @@ void test_no_proto_with_args() { void (*fp)() = foo; // ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] // MS: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] - // WARN_NO_PROTOTYPE: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'void ()', type string: _ZTSFvE) even though arguments are passed at this call site [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'void ()', type string: _ZTSFvE) even though arguments are passed at this call site [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'void ()', type string: ?6AX@Z) even though arguments are passed at this call site [-Wcall-graph-section-no-prototype] fp(1); } >From ef97b722fd89d2829c1ae045445becc5726dcb32 Mon Sep 17 00:00:00 2001 From: prabhukr <[email protected]> Date: Tue, 21 Jul 2026 20:30:39 +0000 Subject: [PATCH 4/5] Treat function type as variadic. --- .../clang/Basic/DiagnosticFrontendKinds.td | 2 +- clang/lib/CodeGen/CGCall.cpp | 3 +- clang/lib/CodeGen/CodeGenModule.cpp | 8 +++ .../CodeGen/call-graph-section-noprototype.c | 71 +++++++++++++++++++ clang/test/CodeGen/call-graph-section.c | 56 ++------------- 5 files changed, 88 insertions(+), 52 deletions(-) create mode 100644 clang/test/CodeGen/call-graph-section-noprototype.c diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index ee85fd288fc1f..35e65a02bde09 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -408,7 +408,7 @@ def warn_profile_data_misexpect : Warning< } // end of instrumentation issue category def warn_cgs_no_proto : Warning< - "indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: %0, type string: %1)%select{| even though arguments are passed at this call site}2">, + "indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: %0, type string: %1)">, InGroup<DiagGroup<"call-graph-section-no-prototype">>; def warn_ssaf_extract_tu_summary_file_unknown_output_format : diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index a5f14bc95a94f..e99d172523cd4 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -6368,8 +6368,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, StringRef TypeStr; if (auto *MDS = dyn_cast_or_null<llvm::MDString>(MD)) TypeStr = MDS->getString(); - CGM.getDiags().Report(Loc, diag::warn_cgs_no_proto) - << CST << TypeStr << !CallArgs.empty(); + CGM.getDiags().Report(Loc, diag::warn_cgs_no_proto) << CST << TypeStr; } } } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 8ce4063a3b780..6c955ace0c9f8 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -8651,6 +8651,14 @@ llvm::Metadata *CodeGenModule::CreateMetadataIdentifierGeneralized(QualType T) { llvm::Metadata * CodeGenModule::CreateMetadataIdentifierForCallGraphType(QualType T) { + if (auto *FNPT = T->getAs<FunctionNoProtoType>()) { + // For no-prototype functions, treat them as if they are variadic functions + // as we cannot determine the arguments for calls to these functions from + // call sites. + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = true; + T = getContext().getFunctionType(FNPT->getReturnType(), {}, EPI); + } return CreateMetadataIdentifierImpl(T, CallGraphMetadataIdMap, "", /*ForceString=*/true); } diff --git a/clang/test/CodeGen/call-graph-section-noprototype.c b/clang/test/CodeGen/call-graph-section-noprototype.c new file mode 100644 index 0000000000000..8847481be9e4c --- /dev/null +++ b/clang/test/CodeGen/call-graph-section-noprototype.c @@ -0,0 +1,71 @@ +// Tests that we assign appropriate identifiers to indirect calls and targets +// for no-prototype functions which are treated as if they are variadic functions +// in generating their type strings for call graph section. + +// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \ +// RUN: -emit-llvm -o /dev/null %s 2>&1 | FileCheck --check-prefixes=WARN_NO_PROTOTYPE_ITANIUM %s + +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fexperimental-call-graph-section \ +// RUN: -emit-llvm -o /dev/null %s 2>&1 | FileCheck --check-prefixes=WARN_NO_PROTOTYPE_MS %s + +// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \ +// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,ITANIUM %s + +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fexperimental-call-graph-section \ +// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,MS %s + +// CHECK-LABEL: define {{(dso_local)?}} void @foo( +// CHECK-SAME: {{.*}} !callgraph [[F_TVOID:![0-9]+]] +void foo() { +} + +// CHECK-LABEL: define {{(dso_local)?}} void @bar( +// CHECK-SAME: {{.*}} !callgraph [[F_TVOID]] +void bar() { + void (*fp)() = foo; + // ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] + // MS: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] + // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: 'void ()', type string: _ZTSFvzE) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: 'void ()', type string: ?6AXZZ) [-Wcall-graph-section-no-prototype] + fp(); +} + +struct my_struct; + +// CHECK-LABEL: define {{(dso_local)?}} ptr @create_my_struct( +// CHECK-SAME: {{.*}} !callgraph [[F_TMY_STRUCT:![0-9]+]] +struct my_struct *create_my_struct() { + return 0; +} + +// CHECK-LABEL: define {{(dso_local)?}} void @test_struct_ptr_return( +// CHECK-SAME: {{.*}} !callgraph [[F_TVOID]] +void test_struct_ptr_return() { + struct my_struct *(*fp)() = create_my_struct; + // ITANIUM: call {{.*}}, !callee_type [[F_TMY_STRUCT_CT:![0-9]+]] + // MS: call {{.*}}, !callee_type [[F_TMY_STRUCT_CT:![0-9]+]] + // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: 'struct my_struct *()', type string: _ZTSFP9my_structzE) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: 'struct my_struct *()', type string: ?6APEAUmy_struct@@ZZ) [-Wcall-graph-section-no-prototype] + fp(); +} + +// CHECK-LABEL: define {{(dso_local)?}} void @test_no_proto_with_args( +// CHECK-SAME: {{.*}} !callgraph [[F_TVOID]] +void test_no_proto_with_args() { + void (*fp)() = foo; + // ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] + // MS: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] + // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: 'void ()', type string: _ZTSFvzE) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: 'void ()', type string: ?6AXZZ) [-Wcall-graph-section-no-prototype] + fp(1); +} + +// ITANIUM: [[F_TVOID]] = !{!"_ZTSFvzE"} +// ITANIUM: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]} +// ITANIUM: [[F_TMY_STRUCT]] = !{!"_ZTSFP9my_structzE"} +// ITANIUM: [[F_TMY_STRUCT_CT]] = !{[[F_TMY_STRUCT:![0-9]+]]} + +// MS: [[F_TVOID]] = !{!"?6AXZZ"} +// MS: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]} +// MS: [[F_TMY_STRUCT]] = !{!"?6APEAUmy_struct@@ZZ"} +// MS: [[F_TMY_STRUCT_CT]] = !{[[F_TMY_STRUCT:![0-9]+]]} diff --git a/clang/test/CodeGen/call-graph-section.c b/clang/test/CodeGen/call-graph-section.c index 7a5f9efe322cb..5019d18425ec6 100644 --- a/clang/test/CodeGen/call-graph-section.c +++ b/clang/test/CodeGen/call-graph-section.c @@ -6,25 +6,17 @@ // RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fexperimental-call-graph-section \ // RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,MS %s -// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \ -// RUN: -emit-llvm -o /dev/null %s 2>&1 | FileCheck --check-prefixes=WARN_NO_PROTOTYPE_ITANIUM %s - -// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fexperimental-call-graph-section \ -// RUN: -emit-llvm -o /dev/null %s 2>&1 | FileCheck --check-prefixes=WARN_NO_PROTOTYPE_MS %s - // CHECK-LABEL: define {{(dso_local)?}} void @foo( // CHECK-SAME: {{.*}} !callgraph [[F_TVOID:![0-9]+]] -void foo() { +void foo(void) { } // CHECK-LABEL: define {{(dso_local)?}} void @bar( // CHECK-SAME: {{.*}} !callgraph [[F_TVOID]] -void bar() { - void (*fp)() = foo; +void bar(void) { + void (*fp)(void) = foo; // ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] // MS: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] - // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'void ()', type string: _ZTSFvE) [-Wcall-graph-section-no-prototype] - // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'void ()', type string: ?6AX@Z) [-Wcall-graph-section-no-prototype] fp(); } @@ -42,7 +34,7 @@ int *qux(char *a, float *b, double *c) { // CHECK-LABEL: define {{(dso_local)?}} void @corge( // CHECK-SAME: {{.*}} !callgraph [[F_TVOID]] -void corge() { +void corge(void) { int (*fp_baz)(char, float, double) = baz; // CHECK: call i32 {{.*}}, !callee_type [[F_TPRIMITIVE_CT:![0-9]+]] fp_baz('a', .0f, .0); @@ -66,7 +58,7 @@ void stparam(struct st2 a, struct st2 *b) {} // CHECK-LABEL: define {{(dso_local)?}} void @stf( // CHECK-SAME: {{.*}} !callgraph [[F_TVOID]] -void stf() { +void stf(void) { struct st1 St1; St1.fp = qux; // CHECK: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]] @@ -82,37 +74,7 @@ void stf() { fp_stparam(St2, &St2); } -struct my_struct; - -// CHECK-LABEL: define {{(dso_local)?}} ptr @create_my_struct( -// CHECK-SAME: {{.*}} !callgraph [[F_TMY_STRUCT:![0-9]+]] -struct my_struct *create_my_struct() { - return 0; -} - -// CHECK-LABEL: define {{(dso_local)?}} void @test_struct_ptr_return( -// CHECK-SAME: {{.*}} !callgraph [[F_TVOID]] -void test_struct_ptr_return() { - struct my_struct *(*fp)() = create_my_struct; - // ITANIUM: call {{.*}}, !callee_type [[F_TMY_STRUCT_CT:![0-9]+]] - // MS: call {{.*}}, !callee_type [[F_TMY_STRUCT_CT:![0-9]+]] - // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'struct my_struct *()', type string: _ZTSFP9my_structE) [-Wcall-graph-section-no-prototype] - // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'struct my_struct *()', type string: ?6APEAUmy_struct@@@Z) [-Wcall-graph-section-no-prototype] - fp(); -} - -// CHECK-LABEL: define {{(dso_local)?}} void @test_no_proto_with_args( -// CHECK-SAME: {{.*}} !callgraph [[F_TVOID]] -void test_no_proto_with_args() { - void (*fp)() = foo; - // ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] - // MS: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] - // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'void ()', type string: _ZTSFvE) even though arguments are passed at this call site [-Wcall-graph-section-no-prototype] - // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype; generating type metadata as if it took no arguments (type: 'void ()', type string: ?6AX@Z) even though arguments are passed at this call site [-Wcall-graph-section-no-prototype] - fp(1); -} - -// ITANIUM: [[F_TVOID]] = !{!"_ZTSFvE"} +// ITANIUM: [[F_TVOID]] = !{!"_ZTSFvvE"} // ITANIUM: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]} // ITANIUM: [[F_TPRIMITIVE]] = !{!"_ZTSFicfdE"} // ITANIUM: [[F_TPTR]] = !{!"_ZTSFPiPcPfPdE"} @@ -120,10 +82,8 @@ void test_no_proto_with_args() { // ITANIUM: [[F_TPTR_CT]] = !{[[F_TPTR:![0-9]+]]} // ITANIUM: [[F_TSTRUCT]] = !{!"_ZTSFv3st2PS_E"} // ITANIUM: [[F_TSTRUCT_CT]] = !{[[F_TSTRUCT:![0-9]+]]} -// ITANIUM: [[F_TMY_STRUCT]] = !{!"_ZTSFP9my_structE"} -// ITANIUM: [[F_TMY_STRUCT_CT]] = !{[[F_TMY_STRUCT:![0-9]+]]} -// MS: [[F_TVOID]] = !{!"?6AX@Z"} +// MS: [[F_TVOID]] = !{!"?6AXXZ"} // MS: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]} // MS: [[F_TPRIMITIVE]] = !{!"?6AHDMN@Z"} // MS: [[F_TPTR]] = !{!"?6APEAHPEADPEAMPEAN@Z"} @@ -131,5 +91,3 @@ void test_no_proto_with_args() { // MS: [[F_TPTR_CT]] = !{[[F_TPTR:![0-9]+]]} // MS: [[F_TSTRUCT]] = !{!"?6AXUst2@@PEAU0@@Z"} // MS: [[F_TSTRUCT_CT]] = !{[[F_TSTRUCT:![0-9]+]]} -// MS: [[F_TMY_STRUCT]] = !{!"?6APEAUmy_struct@@@Z"} -// MS: [[F_TMY_STRUCT_CT]] = !{[[F_TMY_STRUCT:![0-9]+]]} >From 2a1c847879181180879786d4ae472307a861327d Mon Sep 17 00:00:00 2001 From: prabhukr <[email protected]> Date: Tue, 21 Jul 2026 20:55:13 +0000 Subject: [PATCH 5/5] Print assumed type in the warning. Add a test case with non-void return type. --- .../clang/Basic/DiagnosticFrontendKinds.td | 2 +- clang/lib/CodeGen/CGCall.cpp | 12 ++++++- .../CodeGen/call-graph-section-noprototype.c | 33 +++++++++++++++---- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 35e65a02bde09..3abf39aed704d 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -408,7 +408,7 @@ def warn_profile_data_misexpect : Warning< } // end of instrumentation issue category def warn_cgs_no_proto : Warning< - "indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: %0, type string: %1)">, + "indirect call to a function with no prototype %0; generating callee_type metadata as if calling a variadic function %1 (type string: %2)">, InGroup<DiagGroup<"call-graph-section-no-prototype">>; def warn_ssaf_extract_tu_summary_file_unknown_output_format : diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index e99d172523cd4..cb630864c5eeb 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -6368,7 +6368,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, StringRef TypeStr; if (auto *MDS = dyn_cast_or_null<llvm::MDString>(MD)) TypeStr = MDS->getString(); - CGM.getDiags().Report(Loc, diag::warn_cgs_no_proto) << CST << TypeStr; + + QualType AssumedType = CST; + if (auto *FNPT = CST->getAs<FunctionNoProtoType>()) { + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = true; + AssumedType = CGM.getContext().getFunctionType( + FNPT->getReturnType(), {}, EPI); + } + + CGM.getDiags().Report(Loc, diag::warn_cgs_no_proto) + << CST << AssumedType << TypeStr; } } } diff --git a/clang/test/CodeGen/call-graph-section-noprototype.c b/clang/test/CodeGen/call-graph-section-noprototype.c index 8847481be9e4c..dc89daf956bc6 100644 --- a/clang/test/CodeGen/call-graph-section-noprototype.c +++ b/clang/test/CodeGen/call-graph-section-noprototype.c @@ -25,8 +25,8 @@ void bar() { void (*fp)() = foo; // ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] // MS: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] - // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: 'void ()', type string: _ZTSFvzE) [-Wcall-graph-section-no-prototype] - // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: 'void ()', type string: ?6AXZZ) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype 'void ()'; generating callee_type metadata as if calling a variadic function 'void (...)' (type string: _ZTSFvzE) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype 'void ()'; generating callee_type metadata as if calling a variadic function 'void (...)' (type string: ?6AXZZ) [-Wcall-graph-section-no-prototype] fp(); } @@ -44,8 +44,25 @@ void test_struct_ptr_return() { struct my_struct *(*fp)() = create_my_struct; // ITANIUM: call {{.*}}, !callee_type [[F_TMY_STRUCT_CT:![0-9]+]] // MS: call {{.*}}, !callee_type [[F_TMY_STRUCT_CT:![0-9]+]] - // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: 'struct my_struct *()', type string: _ZTSFP9my_structzE) [-Wcall-graph-section-no-prototype] - // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: 'struct my_struct *()', type string: ?6APEAUmy_struct@@ZZ) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype 'struct my_struct *()'; generating callee_type metadata as if calling a variadic function 'struct my_struct *(...)' (type string: _ZTSFP9my_structzE) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype 'struct my_struct *()'; generating callee_type metadata as if calling a variadic function 'struct my_struct *(...)' (type string: ?6APEAUmy_struct@@ZZ) [-Wcall-graph-section-no-prototype] + fp(); +} + +// CHECK-LABEL: define {{(dso_local)?}} i32 @baz( +// CHECK-SAME: {{.*}} !callgraph [[F_TINT:![0-9]+]] +int baz() { + return 1; +} + +// CHECK-LABEL: define {{(dso_local)?}} void @test_int_return( +// CHECK-SAME: {{.*}} !callgraph [[F_TVOID]] +void test_int_return() { + int (*fp)() = baz; + // ITANIUM: call {{.*}}, !callee_type [[F_TINT_CT:![0-9]+]] + // MS: call {{.*}}, !callee_type [[F_TINT_CT:![0-9]+]] + // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype 'int ()'; generating callee_type metadata as if calling a variadic function 'int (...)' (type string: _ZTSFizE) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype 'int ()'; generating callee_type metadata as if calling a variadic function 'int (...)' (type string: ?6AHZZ) [-Wcall-graph-section-no-prototype] fp(); } @@ -55,8 +72,8 @@ void test_no_proto_with_args() { void (*fp)() = foo; // ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] // MS: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]] - // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: 'void ()', type string: _ZTSFvzE) [-Wcall-graph-section-no-prototype] - // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype; generating callee_type metadata as if calling a variadic function (type: 'void ()', type string: ?6AXZZ) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_ITANIUM: warning: indirect call to a function with no prototype 'void ()'; generating callee_type metadata as if calling a variadic function 'void (...)' (type string: _ZTSFvzE) [-Wcall-graph-section-no-prototype] + // WARN_NO_PROTOTYPE_MS: warning: indirect call to a function with no prototype 'void ()'; generating callee_type metadata as if calling a variadic function 'void (...)' (type string: ?6AXZZ) [-Wcall-graph-section-no-prototype] fp(1); } @@ -64,8 +81,12 @@ void test_no_proto_with_args() { // ITANIUM: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]} // ITANIUM: [[F_TMY_STRUCT]] = !{!"_ZTSFP9my_structzE"} // ITANIUM: [[F_TMY_STRUCT_CT]] = !{[[F_TMY_STRUCT:![0-9]+]]} +// ITANIUM: [[F_TINT]] = !{!"_ZTSFizE"} +// ITANIUM: [[F_TINT_CT]] = !{[[F_TINT:![0-9]+]]} // MS: [[F_TVOID]] = !{!"?6AXZZ"} // MS: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]} // MS: [[F_TMY_STRUCT]] = !{!"?6APEAUmy_struct@@ZZ"} // MS: [[F_TMY_STRUCT_CT]] = !{[[F_TMY_STRUCT:![0-9]+]]} +// MS: [[F_TINT]] = !{!"?6AHZZ"} +// MS: [[F_TINT_CT]] = !{[[F_TINT:![0-9]+]]} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
