[PATCH] D55628: Add support for "labels" on push/pop directives in #pragma clang attribute
Aaron Ballman via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 19 05:49:37 PST 2018
aaron.ballman added a comment.
In D55628#1335841 <https://reviews.llvm.org/D55628#1335841>, @erik.pilkington wrote:
> After looking through some users of `#pragma clang attribute`, I don't think that the begin/end solution is what we want here. Some users of this attribute write macros that can expand to different attributes depending on their arguments, for instance:
>
> AVAILABILITY_BEGIN(macos(10.12)) // expands to an availability attribute
> AVAILABILITY_BEGIN(ios(10))
> // some code...
> AVAILABILITY_END
> AVAILABILITY_END
>
>
> This code makes sense and is safe, but in this case rewriting AVAILABILITY_BEGIN to use a hypothetical `pragma clang attribute begin`/`end` would be a breaking change, which isn't acceptable.
Good catch!
> So I think that we want stack semantics, but scoped within the `AVAILABILITY_BEGIN` macro's namespace. That way, we can support multiple `push`es in the same macro, without having having different macros accidentally pop each other.
>
> As for a syntax for this, I chose the following (basically, @dexonsmith's idea with a '.'):
>
> #pragma clang attribute NoReturn.push (__attribute__((noreturn)), apply_to=function)
> int foo();
> #pragma clang attribute NoReturn.pop
>
>
> I think the '.' makes the nested relationship (i.e. the push is contained within the namespace) more clear to C programmers, and hopefully clears up the confusion. @AaronBallman: WDYT?
This is definitely a novel syntax, but I like how clear it is that the label acts as the scope being pushed and popped. One question I have is with interactions from unlabeled pushes and pops:
#pragma clang attribute MyNamespace.push (__attribute__((annotate)), apply_to=function)
#pragma clang attribute push (__attribute__((annotate)), apply_to=function)
int some_func1();
#pragma clang attribute pop // does this pop the unlabeled push, or is it an error?
#pragma clang attribute MyNamespace.pop
Or, similarly:
#pragma clang attribute push (__attribute__((annotate)), apply_to=function)
#pragma clang attribute MyNamespace.push (__attribute__((annotate)), apply_to=function)
int some_func2();
#pragma clang attribute pop // does this pop the unlabeled push, or is it an error?
#pragma clang attribute MyNamespace.pop
I suspect the answer is that it pops the unlabeled push and is not an error, but I'd like to see a test case with it.
================
Comment at: clang/docs/LanguageExtensions.rst:2700
+Because multiple push directives can be nested, if you're writing a macro that
+expands to ``_Pragma("clang attribute")`` it's good hygiene (though not
----------------
Somewhere around here you should probably mention that an unlabeled pop does *not* act like a "pop any namespace" action but instead acts as a "pop the last unlabeled namespace" action. Some users may find that behavior surprising otherwise.
================
Comment at: clang/docs/LanguageExtensions.rst:2709-2714
+ #define ASSUME_NORETURN_BEGIN _Pragma("clang attribute AssumeNoreturn.push ([[noreturn]], apply_to = function)
+ #define ASSUME_NORETURN_END _Pragma("clang attribute AssumeNoreturn.pop")
+
+ ASSUME_NORETURN_BEGIN
+ void function(); // function has [[noreturn]]
+ ASSUME_NORETURN_END
----------------
I think it would be useful for the example to show the problematic situation this feature is meant to avoid.
================
Comment at: clang/lib/Parse/ParsePragma.cpp:3161
+ if (!Tok.is(tok::period)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_period)
+ << II;
----------------
Can you reuse `diag::err_expected_after` instead of making a new diagnostic?
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D55628/new/
https://reviews.llvm.org/D55628
More information about the cfe-commits
mailing list