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.