llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-codegen Author: Saleem Abdulrasool (compnerd) <details> <summary>Changes</summary> This attribute allows specifying a custom personality routine for a function, overriding the default emitted by Clang. The motivating use case is the Swift concurrency runtime, where C/C++ runtime functions need to act as barriers for exception propagation — the custom personality ensures exceptions do not propagate through these frames unchecked. More generally, this is useful whenever a language runtime is implemented in a host language with different EH semantics. LLVM IR already supports arbitrary personality functions on definitions; this attribute simply exposes that capability to the C/C++ frontend. --- Full diff: https://github.com/llvm/llvm-project/pull/185225.diff 10 Files Affected: - (modified) clang/include/clang/Basic/Attr.td (+7) - (modified) clang/include/clang/Basic/AttrDocs.td (+11) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+5) - (modified) clang/include/clang/Sema/Sema.h (+3) - (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+9) - (modified) clang/lib/Sema/SemaDecl.cpp (+2) - (modified) clang/lib/Sema/SemaDeclAttr.cpp (+27) - (added) clang/test/CodeGen/attr-personality-failures.c (+30) - (added) clang/test/CodeGen/attr-personality.c (+30) - (modified) clang/test/Misc/pragma-attribute-supported-attributes-list.test (+1) ``````````diff diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index befd671393c7c..8ab4aaa6f5781 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -5402,3 +5402,10 @@ def OverflowBehavior : TypeAttr { "variables, typedefs, and data members">; let Documentation = [Undocumented]; } + +def Personality : InheritableAttr { + let Spellings = [Clang<"personality">]; + let Args = [DeclArgument<Function, "Routine">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [PersonalityDocs]; +} diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 60dfdfc2f23f3..b8fedee234695 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -9876,3 +9876,14 @@ of the same size, while the GCC/Itanium variant packs all fields in a bitfield tightly. }]; } + +def PersonalityDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +``__attribute__((personality(<routine>)))`` is used to specify a personality +routine that is different from the language that is being used to implement the +function. This is a targeted, low-level feature aimed at language runtime +implementors who write runtime support code in C/C++ but need that code to +participate in a foreign language’s exception-handling or unwinding model. + }]; +} diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 0e6b3f51a5231..e6cc09165273d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2035,6 +2035,11 @@ def warn_wasm_dynamic_exception_spec_ignored : ExtWarn< "dynamic exception specifications with types are currently ignored in wasm">, InGroup<WebAssemblyExceptionSpec>; +def err_mismatched_personality + : Error<"personality routine in declaration does not match previous declaration">; +def err_attribute_personality_arg_not_function + : Error<"%0 argument is not a function">; + // C++ access checking def err_class_redeclared_with_different_access : Error< "%0 redeclared with '%1' access">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5917eb0ffbfe1..832e46286194a 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5024,6 +5024,9 @@ class Sema final : public SemaBase { StringRef ImplName, MutableArrayRef<StringRef> Aspects); + PersonalityAttr *mergePersonalityAttr(Decl *D, FunctionDecl *Routine, + const AttributeCommonInfo &CI); + /// AddAlignedAttr - Adds an aligned attribute to a particular declaration. void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, bool IsPackExpansion); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 870840783c0c8..1dee656b5f2d0 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -1655,6 +1655,15 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, PGO->verifyCounterMap(); + if (CurCodeDecl->hasAttr<PersonalityAttr>()) { + StringRef Identifier = + CurCodeDecl->getAttr<PersonalityAttr>()->getRoutine()->getName(); + llvm::FunctionCallee PersonalityRoutine = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty, true), + Identifier, {}, /*local=*/true); + Fn->setPersonalityFn(cast<llvm::Constant>(PersonalityRoutine.getCallee())); + } + // If we haven't marked the function nothrow through other means, do // a quick pass now to see if we can. if (!CurFn->doesNotThrow()) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 405832a446e10..40c84d7a5e4d9 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2970,6 +2970,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, NewAttr = S.OpenACC().mergeRoutineDeclAttr(*RD); else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr)) NewAttr = cast<InheritableAttr>(Attr->clone(S.Context)); + else if (const auto *PA = dyn_cast<PersonalityAttr>(Attr)) + NewAttr = S.mergePersonalityAttr(D, PA->getRoutine(), *PA); if (NewAttr) { NewAttr->setInherited(true); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 1b7f41061061d..91a9a2797841d 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7256,6 +7256,29 @@ static bool MustDelayAttributeArguments(const ParsedAttr &AL) { return false; } +PersonalityAttr *Sema::mergePersonalityAttr(Decl *D, FunctionDecl *Routine, + const AttributeCommonInfo &CI) { + if (PersonalityAttr *PA = D->getAttr<PersonalityAttr>()) { + const FunctionDecl *Personality = PA->getRoutine(); + if (Personality == Routine) + return nullptr; + Diag(PA->getLocation(), diag::err_mismatched_personality); + Diag(CI.getLoc(), diag::note_previous_attribute); + D->dropAttr<PersonalityAttr>(); + } + return ::new (Context) PersonalityAttr(Context, CI, Routine); +} + +static void handlePersonalityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *E = AL.getArgAsExpr(0); + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) + if (Attr *A = S.mergePersonalityAttr(D, FD, AL)) + return D->addAttr(A); + S.Diag(E->getExprLoc(), diag::err_attribute_personality_arg_not_function) + << AL.getAttrName(); +} + /// ProcessDeclAttribute - Apply the specific attribute to the specified decl if /// the attribute applies to decls. If the attribute is a type attribute, just /// silently ignore it if a GNU attribute. @@ -7898,6 +7921,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleNoPFPAttrField(S, D, AL); break; + case ParsedAttr::AT_Personality: + handlePersonalityAttr(S, D, AL); + break; + // Microsoft attributes: case ParsedAttr::AT_LayoutVersion: handleLayoutVersion(S, D, AL); diff --git a/clang/test/CodeGen/attr-personality-failures.c b/clang/test/CodeGen/attr-personality-failures.c new file mode 100644 index 0000000000000..a882a4135100b --- /dev/null +++ b/clang/test/CodeGen/attr-personality-failures.c @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -Oz -triple x86_64-unknown-linux-gnu -fexceptions -fsyntax-only %s -verify + +typedef __UINT64_TYPE__ uint64_t; + +typedef enum _Unwind_Reason_Code _Unwind_Reason_Code; +typedef enum _Unwind_Action _Unwind_Action; + +struct _Unwind_Exception; +struct _Unwind_Context; + +int __swift_personality_int; +_Unwind_Reason_Code __swift_personality_v0(int version, _Unwind_Action action, uint64_t exception_class, struct _Unwind_Exception *exception, struct _Unwind_Context *context); +_Unwind_Reason_Code __swift_personality_v1(int version, _Unwind_Action action, uint64_t exception_class, struct _Unwind_Exception *exception, struct _Unwind_Context *context); +_Unwind_Reason_Code __swift_personality_v2(int version, _Unwind_Action action, uint64_t exception_class, struct _Unwind_Exception *exception, struct _Unwind_Context *context); + +// expected-note@+2{{previous attribute is here}} +// expected-note@+1{{previous attribute is here}} +void __attribute__((__personality__(__swift_personality_v0))) function(void); +// expected-error@+1{{personality routine in declaration does not match previous declaration}} +void __attribute__((__personality__(__swift_personality_v1))) function(void); +// expected-note@+3{{previous attribute is here}} +// expected-error@+2{{personality routine in declaration does not match previous declaration}} +// expected-error@+1{{personality routine in declaration does not match previous declaration}} +void __attribute__((__personality__(__swift_personality_v1))) function(void) __attribute__((__personality__(__swift_personality_v2))); +// expected-error@+1{{'__personality__' argument is not a function}} +void __attribute__((__personality__(__swift_personality_int))) function(void) { +} + +// expected-warning@+1{{'__personality__' attribute only applies to functions}} +int variable __attribute__((__personality__(__swift_personality_v0))); diff --git a/clang/test/CodeGen/attr-personality.c b/clang/test/CodeGen/attr-personality.c new file mode 100644 index 0000000000000..91c587d0598d2 --- /dev/null +++ b/clang/test/CodeGen/attr-personality.c @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -Oz -triple x86_64-unknown-linux-gnu -fexceptions -o - -emit-llvm %s | FileCheck %s + +typedef __UINT64_TYPE__ uint64_t; + +void abort(void) __attribute__((__noreturn__)); + +typedef enum _Unwind_Reason_Code _Unwind_Reason_Code; +typedef enum _Unwind_Action _Unwind_Action; + +struct _Unwind_Exception; +struct _Unwind_Context; + +_Unwind_Reason_Code __swift_personality_v0(int version, _Unwind_Action action, uint64_t exception_class, struct _Unwind_Exception *exception, struct _Unwind_Context *context); + +void function(void); + +void __attribute__((__personality__(__swift_personality_v0))) function_with_custom_personality(void) { +} + +static void cleanup_int(int *p) { + *p = 0; +} + +void function_without_custom_personality(void) { + int variable __attribute__((__cleanup__(cleanup_int))) = 1; + function(); +} + +// CHECK-DAG: define dso_local void @function_with_custom_personality(){{.*}}personality ptr @__swift_personality_v0 +// CHECK-DAG: define dso_local void @function_without_custom_personality(){{.*}}personality ptr @__gcc_personality_v0 diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index fde8f14f5cd83..03b9a77ec1814 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -183,6 +183,7 @@ // CHECK-NEXT: ParamTypestate (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: PatchableFunctionEntry (SubjectMatchRule_function, SubjectMatchRule_objc_method) +// CHECK-NEXT: Personality (SubjectMatchRule_function) // CHECK-NEXT: Pointer (SubjectMatchRule_record_not_is_union) // CHECK-NEXT: PointerFieldProtection (SubjectMatchRule_record) // CHECK-NEXT: PreserveNone (SubjectMatchRule_hasType_functionType) `````````` </details> https://github.com/llvm/llvm-project/pull/185225 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
