nickdesaulniers added a comment.

In D155342#4511879 <https://reviews.llvm.org/D155342#4511879>, @rjmccall wrote:

>> We need to check the scopes like we would for direct goto, because we don't 
>> want to bypass non-trivial destructors.
>
> I think this is the basic misunderstanding here.  Direct `goto` is allowed to 
> jump out of scopes; it just runs destructors on the way.  It is only a direct 
> branch to the target block if there are no destructors along the path.
>
> Indirect `goto` is not allowed to jump out of scopes because, in general, the 
> labels could be in different scopes with different sets of destructors 
> required

Ah, got it.



================
Comment at: clang/lib/Sema/JumpDiagnostics.cpp:658
 
+    if (auto *G = dyn_cast<GCCAsmStmt>(Jump)) {
+      for (AddrLabelExpr *L : G->labels()) {
----------------
efriedma wrote:
> nickdesaulniers wrote:
> > rjmccall wrote:
> > > nickdesaulniers wrote:
> > > > rjmccall wrote:
> > > > > I think it would be good to leave a comment here like this:
> > > > > 
> > > > > > We know the possible destinations of an asm goto, but we don't have 
> > > > > > the
> > > > > > ability to add code along those control flow edges, so we have to 
> > > > > > diagnose
> > > > > > jumps both in and out of scopes, just like we do with an indirect 
> > > > > > goto.
> > > > Depending on your definition of "we" (clang vs. llvm), llvm does have 
> > > > the ability to add code along those edges.
> > > > 
> > > > See llvm/lib/CodeGen/CallBrPrepare.cpp.  I'll clarify in your comment 
> > > > that "clang does not split critical edges during code generation of 
> > > > llvm ... "
> > > Okay, so, I don't really know much about this feature.  I was thinking 
> > > that the branch might go directly into some other assembly block, which 
> > > would not be splittable.  If the branch just goes to an arbitrary basic 
> > > block in IR, then it would be straightforward for IRGen to just resolve 
> > > the destination blocks for `asm goto` labels to some new block that does 
> > > a normal `goto` to that label.  If we did that, we wouldn't need extra 
> > > restrictions here at all and could just check this like any other direct 
> > > branch.
> > > 
> > > We don't need to do that work right away, but the comment should probably 
> > > reflect the full state of affairs — "but clang's IR generation does not 
> > > currently know how to add code along these control flow edges, so we have 
> > > to diagnose jumps both in and out of scopes, like we do with indirect 
> > > goto.  If we ever add that ability to IRGen, this code could check these 
> > > jumps just like ordinary `goto`s."
> > > Okay, so, I don't really know much about this feature.
> > 
> > "Run this block of asm, then continue to either the next statement or one 
> > of the explicit labels in the label list."
> > 
> > ---
> > 
> > That comment still doesn't seem quite right to me.
> > 
> > `asm goto` is more like a direct `goto` or a switch in the sense that the 
> > cases or possible destination are known at compile time; that's not like 
> > indirect goto where you're jumping to literally anywhere.
> > 
> > We need to check the scopes like we would for direct `goto`, because we 
> > don't want to bypass non-trivial destructors.
> > 
> > ---
> > Interestingly, it looks like some of the cases 
> > inclang/test/Sema/asm-goto.cpp, `g++` permits, if you use the 
> > `-fpermissive` flag.  Clang doesn't error that it doesn't recognize that 
> > flag, but it doesn't seem to do anything in clang, FWICT playing with it in 
> > godbolt.
> > 
> > ---
> > 
> > That said, I would have thought
> > ```
> > void test4cleanup(int*);
> > // No errors expected.
> > void test4(void) {
> > l0:;
> >     int x __attribute__((cleanup(test4cleanup)));
> >     asm goto("# %l0"::::l0);
> > }
> > ```
> > To work with this change, but we still produce:
> > ```
> > x.c:6:5: error: cannot jump from this asm goto statement to one of its 
> > possible targets
> >     6 |     asm goto("# %l0"::::l0);
> >       |     ^
> > x.c:4:1: note: possible target of asm goto statement
> >     4 | l0:;
> >       | ^
> > x.c:5:9: note: jump exits scope of variable with __attribute__((cleanup))
> >     5 |     int x __attribute__((cleanup(test4cleanup)));
> >       |         ^
> > ```
> > Aren't those in the same scope though? I would have expected that to work 
> > just as if we had a direct `goto l0` rather than the `asm goto`.
> (There's some history here that the original implementation of asm goto 
> treated it semantically more like an indirect goto, including the use of 
> address-of-labels; for a variety of reasons, we changed it so it's more like 
> a switch statement.)
> 
> Suppose we have:
> 
> ```
> void test4cleanup(int*);
> void test4(void) {
>     asm goto("# %l0"::::l0);
> l0:;
>     int x __attribute__((cleanup(test4cleanup)));
>     asm goto("# %l0"::::l0);
> }
> ```
> 
> To make this work correctly, the first goto needs to branch directly to the 
> destination, but the second needs to branch to a call to test4cleanup().  
> It's probably not that hard to implement: instead of branching directly to 
> the destination bb, each edge out of the callbr needs to branch to a newly 
> created block, and that block needs to EmitBranchThroughCleanup() to the 
> final destination.  (We create such blocks anyway to handle output values, 
> but the newly created blocks branch directly to the destination BasicBlock 
> instead of using EmitBranchThroughCleanup().)
> 
> But until we implement that, we need the error message so we don't miscompile.
> but the second needs to branch to a call to test4cleanup().

GCC does not behave that way (i.e. if the branch is taken from the `asm goto` 
to `l0`, `test4cleanup` is //not// run).  In fact, if I remove the call to 
`DiagnoseIndirectOrAsmJump` below, we generate the same control flow that GCC 
12 does.  https://godbolt.org/z/Y6en3YsY1

Perhaps one could argue "that's surprising" or "not correct" but if we were to 
have such a difference then that would probably preclude the use of the unholy 
combination of `asm goto` and `__attribute__((cleanup()))` (famous last words).

Let me try again with the comment based on feedback thus far.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D155342/new/

https://reviews.llvm.org/D155342

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to