This is an archive of the discontinued LLVM Phabricator instance.

[Sema] Relax an assertion in BuildStmtExpr
ClosedPublic

Authored by ahatanak on May 18 2022, 4:33 PM.

Details

Summary

The assertion doesn't hold if there are temporaries created in the AsmStmt passed to the method.

Diff Detail

Event Timeline

ahatanak created this revision.May 18 2022, 4:33 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 18 2022, 4:33 PM
ahatanak requested review of this revision.May 18 2022, 4:33 PM

ping

I think the assertion is assuming StmtExpr is created only for GNU statement expressions, but it's created for asm statements too (see https://github.com/llvm/llvm-project/commit/3050d9bdb84e322e122219d54aedfe2d8ef7c51c).

The assertion was assuming "the expression doesn't need cleanups", have you considered adding a test that checks that the destructor of the temporary inside the asm statement is called, to ensure these temporaries are properly handled?

ahatanak updated this revision to Diff 432398.May 26 2022, 3:08 PM
ahatanak edited the summary of this revision. (Show Details)

Add a codegen test that checks destructors for temporaries inside asm statements are called.

akyrtzi accepted this revision.May 26 2022, 3:16 PM
This revision is now accepted and ready to land.May 26 2022, 3:16 PM
rsmith added a subscriber: rsmith.May 26 2022, 5:24 PM
rsmith added inline comments.
clang/test/CodeGenCXX/asm.cpp
22

Please add another statement here after the asm statement to check that the destructor is called at the end of the asm statement, not at the }.

rsmith added inline comments.May 26 2022, 5:29 PM
clang/lib/Sema/SemaExpr.cpp
15772–15773

Is it possible to pass a flag into here to indicate if we're really building an asm statement? I don't think we want to remove the assert for a user-written statement expression that happens to begin with an asm statement.

It's ironic that we're building a statement expression to wrap an asm statement in order to make sure that cleanups are handled properly, and the StmtExpr is asserting because it doesn't expect to need to handle cleanups...

ahatanak added inline comments.May 31 2022, 10:49 AM
clang/lib/Sema/SemaExpr.cpp
15772–15773

Maybe we can add a flag to StmtExpr and set it in Sema::MaybeCreateStmtWithCleanups to distinguish StmtExprs that are created for gnu statement expressions from those that aren't?

If we don't want to use StmtExpr for asm statements, maybe we have to create a new Stmt type just for that purpose as suggested in Sema::MaybeCreateStmtWithCleanups.

ahatanak updated this revision to Diff 434144.Jun 3 2022, 2:23 PM

Add a flag to StmtExpr that indicates whether it needs cleanup.

ahatanak updated this revision to Diff 434960.Jun 7 2022, 2:31 PM
ahatanak marked an inline comment as done.

Check that the destructor is called at the end of the asm.

The cleanups arise from expressions in the constraints, right? There are a number of places where ExprWithCleanups does not mean the cleanups are independently nested within that expression; it's notably not how it works ever for something as basic as a variable initializer. If we want the lifetime of temporaries in asm operands to include the full duration of the asm statement, I think we can just declare by fiat that that's how it works for AsmStmt instead of unnaturally wrapping things this way.

Or do we have a problem where the semantics are different for different kinds of asm statements?

No, I don't think there are any problems. We can probably just pop the cleanups at the end of the asm statement.

The original commit message said the asm calls had to be wrapped in StmtExprs because temporaries would get destroyed before the asm calls, but that doesn't seem to happen anymore. It looks like they'd be destroyed at the end of the enclosing scope instead.

Yeah, I think the appropriate thing is to just treat the entire asm statement like it's a single full-expression. As always, that implies an annoying lifetime for blocks and C compound literals.

ahatanak updated this revision to Diff 437248.Jun 15 2022, 10:59 AM

Stop wrapping a GCCAsmStmt with an ExprWithCleanups. Instead, just pop the cleanups after the asm statement to destruct the temporaries.

I've removed the call to ActOnFinishFullStmt in CoroutineStmtBuilder::makeOnFallthrough too. BuildCoreturnStmt calls ActOnFinishFullExpr, so I don't think it's necessary to call ActOnFinishFullStmt after that.

Adding more people to get more eyes on the changes I made to SemaCoroutine.cpp.

Adding more people to get more eyes on the changes I made to SemaCoroutine.cpp.

The change to SemaCoroutine.cpp might be good. But I feel like it is irreverent to the revision. If you want, could you please do the change in another revision?

ahatanak updated this revision to Diff 437566.Jun 16 2022, 9:11 AM

Revert the changes made to SemaCoroutine.cpp.

rjmccall added inline comments.Jun 16 2022, 10:59 AM
clang/lib/CodeGen/CGStmt.cpp
2291 ↗(On Diff #437566)

Do we need to do anything special when entering the full expressions to make sure that enclosing-block features like blocks and C compound literals have the right lifetime?

ahatanak updated this revision to Diff 437796.Jun 16 2022, 10:08 PM

Fix misleading comment and add a test case for C compound literal.

clang/lib/CodeGen/CGStmt.cpp
2291 ↗(On Diff #437566)

I don't think there is anything special we have to do here. The cleanups for both blocks and C compound literals are pushed by calling pushLifetimeExtendedDestroy so that their lifetime is extended till the end of the enclosing scope.

rjmccall accepted this revision.Jun 17 2022, 12:04 PM

Okay, LGTM then

This revision was landed with ongoing or failed builds.Jun 17 2022, 5:29 PM
This revision was automatically updated to reflect the committed changes.