From b88fb87e1627b91b83f25a27cd10f9cdddc860f0 Mon Sep 17 00:00:00 2001 From: Leonard Chan Date: Tue, 9 Sep 2025 15:25:56 -0700 Subject: [PATCH] [clang] Do not diagnose conflicting types for cfi_unchecked_callee Clang would complain about conflicting types between a function declaration and definition if the declaraion was marked with the attribute but the definition wasn't. Do not treat this as an error. It should only be necessary to mark the declaration with the attribute. --- clang/docs/ReleaseNotes.rst | 3 +++ clang/lib/Sema/SemaDecl.cpp | 17 +++++++++++++++++ clang/test/AST/cfi-unchecked-callee.cpp | 9 +++++++++ .../Frontend/cfi-unchecked-callee-attribute.cpp | 4 ++++ 4 files changed, 33 insertions(+) create mode 100644 clang/test/AST/cfi-unchecked-callee.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9af55951a1d82..e5e241f65227b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -233,6 +233,9 @@ Removed Compiler Flags Attribute Changes in Clang -------------------------- +- The definition of a function declaration with ``[[clang::cfi_unchecked_callee]]`` inherits this + attribute, allowing the attribute to only be attached to the declaration. Prior, this would be + treated as an error where the definition and declaration would have differing types. Improvements to Clang's diagnostics ----------------------------------- diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 45cfb66996ce6..e10511cc7fc4e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3877,6 +3877,23 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S, RequiresAdjustment = true; } + // If the declaration is marked with cfi_unchecked_callee but the definition + // isn't, the definition is also cfi_unchecked_callee. + if (auto *FPT1 = OldType->getAs()) { + if (auto *FPT2 = NewType->getAs()) { + FunctionProtoType::ExtProtoInfo EPI1 = FPT1->getExtProtoInfo(); + FunctionProtoType::ExtProtoInfo EPI2 = FPT2->getExtProtoInfo(); + + if (EPI1.CFIUncheckedCallee && !EPI2.CFIUncheckedCallee) { + EPI2.CFIUncheckedCallee = true; + NewQType = Context.getFunctionType(FPT2->getReturnType(), + FPT2->getParamTypes(), EPI2); + NewType = cast(NewQType); + New->setType(NewQType); + } + } + } + // Merge regparm attribute. if (OldTypeInfo.getHasRegParm() != NewTypeInfo.getHasRegParm() || OldTypeInfo.getRegParm() != NewTypeInfo.getRegParm()) { diff --git a/clang/test/AST/cfi-unchecked-callee.cpp b/clang/test/AST/cfi-unchecked-callee.cpp new file mode 100644 index 0000000000000..af84996835930 --- /dev/null +++ b/clang/test/AST/cfi-unchecked-callee.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -ast-dump %s | FileCheck %s + + +// CHECK: FunctionDecl [[PTR:0x[a-z0-9]*]] {{.*}}func 'void () __attribute__((cfi_unchecked_callee))' +__attribute__((cfi_unchecked_callee)) +void func(void); + +// CHECK-NEXT: FunctionDecl {{0x[a-z0-9]*}} prev [[PTR]] {{.*}}func 'void () __attribute__((cfi_unchecked_callee))' +void func(void) {} diff --git a/clang/test/Frontend/cfi-unchecked-callee-attribute.cpp b/clang/test/Frontend/cfi-unchecked-callee-attribute.cpp index f2c4e9e2f8890..072f217ff7b19 100644 --- a/clang/test/Frontend/cfi-unchecked-callee-attribute.cpp +++ b/clang/test/Frontend/cfi-unchecked-callee-attribute.cpp @@ -233,3 +233,7 @@ void lambdas() { checked_func = checked_lambda; }; } + +CFI_UNCHECKED_CALLEE +void func(void); +void func(void) {} // No warning expected.