ayzhao marked 2 inline comments as done. ayzhao added inline comments.
================ Comment at: clang/lib/Sema/SemaExprCXX.cpp:1582-1596 + MultiExprArg ExprsToPass; + if (Exprs.size() == 1 && isa<CXXParenListInitExpr>(Exprs[0])) { + // C++20 [expr.static.cast]p4: + // An expression E can be explicitly converted to a type T...if T is an + // aggregate type ([dcl.init.aggr]) having a first element x and there is + // an implicit conversion sequence from E to the type of x + // ---------------- rsmith wrote: > ayzhao wrote: > > rsmith wrote: > > > The input to this function should be a syntactic initializer such as a > > > `ParenListExpr`, not an already-type-checked semantic initializer such as > > > a `CXXParenListInitExpr`. The right place to do this unwrapping is in > > > `TreeTransform::TransformInitializer`, where we unwrap various other > > > kinds of semantic initializer. > > > The right place to do this unwrapping is in > > > `TreeTransform::TransformInitializer`, where we unwrap various other > > > kinds of semantic initializer. > > > > So the `CXXParenListInitExpr` for `S` never gets passed to > > `TreeTransform::TransformInitializer` - rather, > > `TransformCXXParenListInitExpr(...)` calls `TransformExprs(...)` on its > > subexpressions. If the subexpression happens to be a `CXXConstructExpr`, > > then `TransformCXXConstructExpr` will call `TransformInitializer(...)`, > > which is [why we saw the CXXConstructExpr getting > > deleted](https://github.com/llvm/llvm-project/blob/4c483a046d2ff29ec2fd5bad6305f97424a2b880/clang/lib/Sema/TreeTransform.h#L13030-L13036) > > > > Interestingly enough, if we initialize `S` with a braced init-list (i.e. > > `S{(V&&) Vec}`), we never end up calling `TransformCXXConstructExpr(...)` > > since [we revert to the syntatic > > form.](https://github.com/llvm/llvm-project/blob/4c483a046d2ff29ec2fd5bad6305f97424a2b880/clang/lib/Sema/TreeTransform.h#L11584-L11585). > > > > > The input to this function should be a syntactic initializer such as a > > > `ParenListExpr`, not an already-type-checked semantic initializer such as > > > a `CXXParenListInitExpr`. > > > > We can probably do this by returning a `ParenListExpr` in > > `TransformCXXParenListInitExpr(...)`. This does cause some problems though. > > If we use a `ParenListExpr`, how would we know when to bail out in line > > 1551 (`!isa<InitListExpr>(Exprs[0]) && > > !isa<CXXParenListInitExpr>(Exprs[0])`)? Surely, not every instance of a > > `ParenListExpr` would be caused by a `CXXParenListInitExpr`, and if this > > were the case, that would be a pretty brittle assumption. Furthermore, we > > never create a `ParenListExpr` for a corresponding `CXXParenListInitExpr`. > > > > As an alternative, we could probably do something similar to > > `InitListExpr`, which has separate semantic and syntactic forms. Would that > > work? > > > > Also, in general, are the `TransformFooExpr(...)` functions supposed to > > return semantic or syntactic results? I seem to see a mix of both... > OK, I've looked at this a bit more. It looks to me like there are problems in > two places: > > 1) > [TreeTransform::RebuildCXXParenListInitExpr](https://github.com/llvm/llvm-project/blob/4c483a046d2ff29ec2fd5bad6305f97424a2b880/clang/lib/Sema/TreeTransform.h#L3889). > When transforming the subexpressions of a `CXXParenListInitExpr`, we call > `TransformExprs` passing `IsCall=true`, which means we call > `TransformInitializer` on each of them, which reverts them to syntactic form. > So we need to redo the semantic analysis for forming a `CXXParenListInitExpr` > here, and can't just create a new `CXXParenListInitExpr` node directly. > Probably the easiest way to handle that would be to produce a `ParenListExpr` > here instead. > > 2) > [Expr::getSubExprAsWritten](https://github.com/llvm/llvm-project/blob/4c483a046d2ff29ec2fd5bad6305f97424a2b880/clang/lib/AST/Expr.cpp#L1978) > ([reached via > here](https://github.com/llvm/llvm-project/blob/4c483a046d2ff29ec2fd5bad6305f97424a2b880/clang/lib/Sema/TreeTransform.h#L12070)) > is not properly handling `CXXParenListExpr` -- it should be stepping over it > to the single argument of the expression, which was the as-written > subexpression. > > But looking more into (2), it seems like there's a representational oddity > here, too. We use a `CXXFunctionalCastExpr` wrapping a `CXXParenListExpr` to > model both the case of `Aggregate(a)` (which is a functional cast, equivalent > by definition to `(Aggregate)a`) and the case of `Aggregate(a, b)` (which is > //not// a functional cast). I don't think that's necessarily a problem -- we > also incorrectly use `CXXFunctionalCastExpr` wrapping an `InitListExpr` for > `Aggregate{a, b}` -- but it means that `getSubExprAsWritten` will need to be > careful to only unwrap in the case where the parenthesized aggregate > initialization expression had exactly one element, and it's not ideal from a > source fidelity perspective. > > In the long term, I think we should split `CXXTemporaryObjectExpr` into two > -- an outer wrapper representing an explicit type construction expression of > the form `T(...)` or `T{...}` (excluding the case `T(a)` which is a > functional cast expression) and an inner `CXXConstructExpr` representing the > actual constructor call. And then we can represent parenthesized aggregate > initialization as either a `CXXTemporaryObjectExpr` wrapping a > `CXXParenListInitExpr` (when the number of arguments is not equal to 1) or a > `CXXFunctionalCastExpr` wrapping a `CXXParenListInitExpr` (when the number of > arguments is equal to 1) -- and similarly we can represent the case of > `(Aggregate)a` as a `CastExpr` wrapping a `CXXParenListInitExpr`. But for now > I think we can leave the representation as-is and make `TreeTranform` handle > it. > > (Incidentally, the name `CXXParenListInitExpr` seems confusing here -- there > aren't necessarily any parentheses involved, and the name really ought to > mention aggregate initialization. `CXXAggregateInitExpr` would make more > sense to me.) > > > If we use a `ParenListExpr`, how would we know when to bail out in line 1551 > > We should never see a `ParenListExpr` there (that would represent `T((a, > b))`, not `T(a, b)`, which would result in a comma expression not a > `ParenListExpr`). Instead, the caller of `BuildCXXTypeConstructExpr` should > convert the `ParenListExpr` into a list of expressions passed as `Exprs`, and > pass the locations of the parentheses as `LParenOrBraceLoc` and > `RParenOrBraceLoc`. > > In particular, I think it would make sense for > `TransformCXXFunctionalCastExpr` to detect when it's in this special case > where the thing it's transforming isn't a functional cast expression, and > call a different `Rebuild...` overload that takes a list of expressions > instead of a single expression. (It would make some sense to call > `RebuildCXXTemporaryObjectExpr` in this case.) > > > Also, in general, are the `TransformFooExpr(...)` functions supposed to > > return semantic or syntactic results? I seem to see a mix of both... > > The intent is that `TreeTransform` on an expression removes all implicit > nodes -- implicit conversions, semantic forms for initializers, and so on -- > and returns the node to how it would have been before it was given to `Sema` > as a subexpression. That means that the `Sema` functionality for building an > expression with a given set of arguments doesn't need to handle the case > where they've already been implicitly converted in some way, which gives us > consistent behavior between the initial parse and template instantiation. > > That means that when we see an expression being used as an initializer, we > want to strip off all the purely semantic pieces and revert it back to a > syntactic form -- that happens when transforming the initializer of a > variable, an argument to a function, etc -- and also when we transform an > expression that performed some kinds of conversions on its operands, we need > to redo those conversions when transforming it. Patch has been updated per this comment. PTAL. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D146465/new/ https://reviews.llvm.org/D146465 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits