[clang] [Clang][attr] Add 'kcfi_salt' attribute (PR #141846)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 31 05:05:20 PDT 2025


================
@@ -3929,6 +3929,14 @@ def CFICanonicalJumpTable : InheritableAttr {
   let SimpleHandler = 1;
 }
 
+def CFISalt : DeclOrTypeAttr {
+  let Spellings = [Clang<"cfi_salt">];
+  let Args = [StringArgument<"Salt">];
+  let Subjects = SubjectList<[Function, Field, Var, TypedefName], ErrorDiag>;
----------------
AaronBallman wrote:

Yeah, it's specifically about the placement (it's complicated). If this is stuff you already know, feel free to ignore (not trying to mansplain, I just have no idea how much folks know about these kinds of details).

For attributes spelled with `__attribute__(())`, syntactic placement is not super critical because the attribute will "slide" around to whatever makes the most sense (declaration or type). But for attributes spelled with `[[]]`, placement is actually critical to the semantics. The rules of thumb there are, the attribute appertains to whatever is immediately to the left of the attribute; if the attribute is at the start of the line then it is either a stand-alone attribute (like `[[fallthrough]]`) or appertains to each declaration in a declaration group. As a concrete example:
```
[[foo]] int func [[bar]] (int x) [[baz]];
```
`foo` appertains to the declaration `func`, the only thing in the declaration group. `bar` also applies to `func` (as a declaration attribute as well). There is no difference in semantics between how either of those attributes are applied; you could put `[[foo, bar]]` in either place and it would mean exactly the same thing. `baz` appertains to the type `int (int)`.

So based on this previously being a `DeclOrTypeAttr` and the `Subjects` list, I would expect the following:
```
#define attr [[cfi_salt("I'm being lazy and using a macro")]]

attr void func(); // Appertains to the declaration of func
void func() attr; // Appertains to the type void()

attr int x, y, z; // Appertains to the declarations of x, y, and z
struct S {
  attr int x; // Appertains to the declaration of member x
};

typedef int attr foo; // Appertains to the type int, so anywhere you use foo, you get `int attr`.
typedef int bar attr; // Appertains to the declaration of foo, so anywhere you spell `bar`, you get `bar attr` which is an alias to type `int`

foo f;
bar b;
int i;
f = b; // Requires a conversion from `int` to `int attr`
i = b; // No conversions
i = f; // Requires a conversion from `int attr` to `int`
```
but this behavior is specific to `[[]]` spellings; for `__attribute__` we could make different decisions if we wanted as to what the attribute actually appertains to.

With your latest changes to use `TypeAttr`, that will never apply to a declaration and so I think the `Subjects` list should be `FunctionLike` (only) because it applies to either function types or function pointer types. For the typedef case, that means:
```
typedef void (*fp)() attr; // Applies to the function pointer type
// Instead of:
typedef void (*fp attr)(); // Applies to the declaration of `foo`, which would be diagnosed as an ignored attribute
```
(Again, this is specific to the behavior with the `[[]]` spelling.)

CC @erichkeane as attributes code owner in case he disagrees with anything I'm saying above or has better explanations.

https://github.com/llvm/llvm-project/pull/141846


More information about the cfe-commits mailing list