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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits