Repository navigation
Conversation
…ergent Fixes #3489
| .and_then(|ret| ret.canonical_type().pointee_type()) | ||
| .is_some_and(|pointee| { | ||
| matches!( | ||
| pointee.canonical_type().kind(), |
There was a problem hiding this comment.
Is this the right check tho? What if I return an alias or so? What if I have both? E.g:
void (__attribute__((noreturn)) *take(int t))(int) __attribute__((noreturn));
void plain(int t) __attribute__((noreturn));There was a problem hiding this comment.
good catch, both of those broke. with the first version take_noreturn-style decls and a noreturn function returning a typedef'd fn pointer both lost -> !.
looked at what libclang actually spells:
void (__attribute__((noreturn)) *take(int))(int)→void (*(int))(int) __attribute__((noreturn))- the same plus a trailing
__attribute__((noreturn))→void (*(int) __attribute__((noreturn)))(int) __attribute__((noreturn)) fp f(int) __attribute__((noreturn))withfpa typedef →fp (int) __attribute__((noreturn))
so when the return type is spelled as a raw function pointer, the function's own attributes end up right after its params inside the (*...) group (depth 1), and depth 0 is the pointee's. for an alias (or anything else) it's still depth 0. pushed that: it now checks ret.kind() == CXType_Pointer on the non-canonical type (so aliases keep the old path) and looks at depth 1 in that case. args still sit at depth 2+, so the #2715 case is unchanged.
the test now covers plain, both, alias and alias + noreturn. all match main except take, which is the fix.
Fixes #3489. Thanks to @lwz23 for the report.
For
void (__attribute__((noreturn)) *take(int t))(int);libclang spells the function type asvoid (*(int))(int) __attribute__((noreturn)).FunctionSig::from_tylooks for__attribute__((noreturn))at parenthesis depth 0 of that spelling, but here the attribute belongs to the pointed-to function type, not totake, sotakewas emitted as-> !.When the return type is spelled as a raw function pointer, the function's own attributes follow its parameters inside the
(*...)group, e.g.void (*(int) __attribute__((noreturn)))(int) __attribute__((noreturn))for a function that is noreturn itself. So in that case the check now looks at depth 1 instead of 0. A return type spelled through a typedef (fp (int) __attribute__((noreturn))) and plain functions keep the depth-0 check, and argument attributes (the #2715/#2716 case) stay at depth 2+.The header test covers
take, a noreturn function returning a noreturn function pointer, the typedef'd return with and without noreturn, and a plain noreturn function. Onlytakechanges compared to main; the test fails without the change.