There isn't anything inherently wrong with returning a label from a
statement expression. In practice, the Linux kernel uses this pattern to
materialize PCs.
Fixes PR38569
Differential D50805
Don't warn on returning the address of a label from a statement expression rnk on Aug 15 2018, 1:44 PM. Authored by
Details
There isn't anything inherently wrong with returning a label from a Fixes PR38569
Diff Detail
Event Timeline
Comment Actions There is no guarantee that you can use an address-of-label value from one function invocation in another invocation of the same function. GCC's documentation says it's the user's own problem to prevent inlining and cloning if the program requires an address-of-label extension to always produce the same value for multiple invocations of the function. It might make sense to suppress the warning in the case where the function is __attribute__((noinline)), though.
Comment Actions That's interesting. I'm pretty sure LLVM will not inline a function that has indirectbr to avoid this problem. I think the state machine use case is real, though, something like: void *f(void *startlabel) { common_work(); goto *startlabel; state1: return &&state2; state2: return &&state3; ... } I think that, ultimately, this warning isn't worth the code complexity in clang to support it. Suppressing it under noinline doesn't solve the original statement expression issue either, and creates more unnecessary code complexity. Are we really worried about users doing this? void *f() { return &&next; next: ... } void g() { void *pc = f(); goto *pc; // cross-functional frame re-entry! =D } Comment Actions
The code complexity is at most 11 lines (the 11 lines removed by this patch), which really isn't much. But there's an interface-complexity argument to be made, for sure. If you added a new option -Wret-addr-label as suggested above (for a total patch of +2 lines), then is it accurate to say:
And if nobody would enable it voluntarily... might as well eliminate it, right?
Comment Actions That nobody here can name a project that would enable it, does not mean that there is none, or that projects will decide in the future to use it, or that individual developers temporarily use. Besides, it'd be enabled by -Weverything. Comment Actions +1 i strongly believe this should just be adding a new diag group, not completely dropping the diagnostic. Comment Actions Per GCC's documentation, this code is wrong, and __attribute__((noinline, noclone)) must be used. However, GCC's behavior on that case is extremely interesting: https://godbolt.org/g/xesYK1 Note that it produces a warning about returning the address of a label, just like we do. But it also says that f cannot be inlined because it contains a computed goto. So perhaps the GCC documentation / spec for the feature is wrong.
True, but it's straightforward to fix the regression for the statement expression case. I don't think that affects whether we go further than that and remove the warning for the return case.
A little, yes. But I think this cross-function case alone would not justify an enabled-by-default warning with false-positives on the state machine case. So I think the question is, do we think the warnings on the state machine case are false positives or not? Some options I think are reasonable:
Or secret option 1b: we get the GCC folks to update their documentation to explicitly state that the presence of a computed goto in a function prevents inlining and cloning in all circumstances, and remove the warning. I've filed gcc.gnu.org/PR86983; hopefully we'll get more clarification on what the semantics of this extension are supposed to be there. Comment Actions Sounds good. I think, in the meantime, we all agree we can stop emitting this warning in the statement expression case. I'll upload a patch for that.
|
We should not be producing warnings on address-of-label cases for LK_StmtExprResult, similarly to what we do here for DeclRefExprs. If we fixed that (which I think is just a bug I introduced while refactoring this code), we'd no longer reject the example from the Linux kernel.