efriedma added inline comments.

================
Comment at: clang/lib/CodeGen/CGExprConstant.cpp:1279
+      if (isa<MaterializeTemporaryExpr>(E))
+        return nullptr;
+
----------------
nickdesaulniers wrote:
> efriedma wrote:
> > nickdesaulniers wrote:
> > > efriedma wrote:
> > > > efriedma wrote:
> > > > > This needs a comment explaining why we're bailing out here.
> > > > We might need to do a recursive visit still, to handle the cases noted 
> > > > at 
> > > > https://en.cppreference.com/w/cpp/language/reference_initialization#Lifetime_of_a_temporary
> > > >  .  Not constructors, but other things.  I think we don't have existing 
> > > > testcases, but for example `typedef int x[2]; struct Z { int &&x, y; }; 
> > > > Z z = { x{1,2}[0], z.x=10 };`
> > > The AST for that test case:
> > > ```
> > > `-VarDecl 0x55809e1c6110 <col:45, col:71> col:47 used z 'Z':'Z' cinit
> > >   `-ExprWithCleanups 0x55809e1c6658 <col:51, col:71> 'Z':'Z'
> > >     `-InitListExpr 0x55809e1c64c8 <col:51, col:71> 'Z':'Z'
> > >       |-ArraySubscriptExpr 0x55809e1c63b8 <col:53, col:61> 'int' xvalue
> > >       | |-ImplicitCastExpr 0x55809e1c63a0 <col:53, col:58> 'int *' 
> > > <ArrayToPointerDecay>
> > >       | | `-MaterializeTemporaryExpr 0x55809e1c6388 <col:53, col:58> 
> > > 'x':'int[2]' xvalue extended by Var 0x55809e1c6110 'z' 'Z':'Z'
> > >       | |   `-CXXFunctionalCastExpr 0x55809e1c6310 <col:53, col:58> 
> > > 'x':'int[2]' functional cast to x <NoOp>
> > >       | |     `-InitListExpr 0x55809e1c62c0 <col:54, col:58> 'x':'int[2]'
> > >       | |       |-IntegerLiteral 0x55809e1c6230 <col:55> 'int' 1
> > >       | |       `-IntegerLiteral 0x55809e1c6250 <col:57> 'int' 2
> > >       | `-IntegerLiteral 0x55809e1c6338 <col:60> 'int' 0
> > >       `-ImplicitCastExpr 0x55809e1c6560 <col:64, col:68> 'int' 
> > > <LValueToRValue>
> > >         `-BinaryOperator 0x55809e1c6448 <col:64, col:68> 'int' lvalue '='
> > >           |-MemberExpr 0x55809e1c63f8 <col:64, col:66> 'int' lvalue .x 
> > > 0x55809e1c5fe0
> > >           | `-DeclRefExpr 0x55809e1c63d8 <col:64> 'Z':'Z' lvalue Var 
> > > 0x55809e1c6110 'z' 'Z':'Z'
> > >           `-IntegerLiteral 0x55809e1c6428 <col:68> 'int' 10
> > > ```
> > > my code at this revision `Diff 529732` (without recursive visitation) 
> > > produces:
> > > ```
> > > @_ZGR1z_ = internal global [2 x i32] [i32 1, i32 2], align 4
> > > @z = dso_local global { ptr, i32 } { ptr @_ZGR1z_, i32 10 }, align 8
> > > ```
> > > so yeah, it looks wrong and differs from the slow path (or behavior 
> > > before this patch).  I'm tempted to add an expensive check to calculate 
> > > both the slow and fast path and fail when they differ, though the subtle 
> > > test changes here show there are slight differences already.
> > > 
> > > So I guess we will need something like `HasAnyMaterializeTemporaryExpr` 
> > > from previous revisions of this patch.  One thing I don't like about that 
> > > approach; IIRC if I accidentally omit methods of the Visitor, I think it 
> > > produces the wrong answers.  Is there a better way to design such a 
> > > visitor?  I'm assuming that if you don't define the method, then the 
> > > visitor stops descending further into the AST. Is that correct?
> > Ideally, I think we fix LValueExprEvaluator::VisitMaterializeTemporaryExpr 
> > in ExprConstant so it only calls getOrCreateValue() and resets the value 
> > when we're actually evaluating the initializer of the corresponding 
> > variable.  If we're not, we should bail out or treat it as a temporary. But 
> > when I looked briefly, I couldn't figure out how to check that condition 
> > correctly.  If we do that, we don't need this workaround.
> > 
> > It's possible to, instead of using a visitor pattern, use a switch 
> > statement that lists out all the possible kinds of expressions. Some places 
> > do that, I think, but I'm not sure how much it helps in this context; even 
> > if all the possible expressions are listed out, that doesn't mean you 
> > managed to classify them correctly.
> > 
> > > though the subtle test changes here show there are slight differences 
> > > already
> > 
> > That's probably fixable?  The tests only show two kinds of difference; 
> > there can't be that many more.  Not sure how much work it is.
> > Ideally, I think we fix LValueExprEvaluator::VisitMaterializeTemporaryExpr 
> > in ExprConstant so it only calls getOrCreateValue() and resets the value 
> > when we're actually evaluating the initializer of the corresponding 
> > variable. If we're not, we should bail out or treat it as a temporary. But 
> > when I looked briefly, I couldn't figure out how to check that condition 
> > correctly. If we do that, we don't need this workaround.
> 
> That sounds way less brittle than the `HasAnyMaterializeTemporaryExpr` I've 
> mocked up here, or any switch-based approach which would have similar 
> deficits IMO.
> 
> Indeed, LValueExprEvaluator::VisitMaterializeTemporaryExpr gets called twice 
> for some reason. If I bail (`return false;` before calling 
> `getOrCreateValue`) the first but not the second, we produce the expected 
> result.
> 
> AFAICT, the first call is via `Sema::CheckCompleteVariableDeclaration` 
> (there's like 20 stack frames in between) from the parser and the second is 
> `CodeGen::CodeGenModule::EmitGlobalVarDefinition` (~10 frames inbetween).
> 
> I don't see how `LValueExprEvaluator::VisitMaterializeTemporaryExpr` could 
> have the context of its call chain like that, especially since there is so 
> many frames inbetween.  Perhaps we can avoid calling 
> `LValueExprEvaluator::VisitMaterializeTemporaryExpr` that initial time 
> somehow?
I suspect bailing out during Sema would have bad consequences.  We need to be 
able to handle something like the following, which I think requires the 
evaluation from Sema to succeed:

```
typedef int x[2];
struct Z { int &&x, y; };
constexpr Z z = { x{1,2}[0], z.x=10 };
constexpr int *xx = &z.x;
int *xxx = xx;
```

So we need to bail out for the second evaluation, not the first.

I think we should be able to store the necessary context information in the 
EvalInfo, if it's not already there.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D151587

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

Reply via email to