[PATCH] D129531: [clang][C++20] P0960R3: Allow initializing aggregates from a parenthesized list of values
Alan Zhao via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 27 16:50:38 PDT 2022
ayzhao added a comment.
In D129531#3880875 <https://reviews.llvm.org/D129531#3880875>, @ayzhao wrote:
> In D129531#3873872 <https://reviews.llvm.org/D129531#3873872>, @royjacobson wrote:
>
>> Thanks for working on it! It looks really good. Please remember to update the feature test macro (__cpp_aggregate_paren_init).
>
> Done
>
>> Also, I think there's no test coverage for the ASTReader/Writer changes? I would like to see some as well.
>
> I added a precompiled header test. Currently, the ASTReader/Writer change is broken with the following error:
>
> ...
>
> I'm currently looking into this - I suspect it has to do with `CXXParenListInitExpr` storing all it's subexpressions in an `llvm::TrailingObjects` base class, but I have yet to confirm one way or another.
The PCH test is fixed now, so we now have coverage for the ASTReader/Writer changes.
================
Comment at: clang/lib/AST/Expr.cpp:3699
+ // FIXME: unimplemented
+ llvm_unreachable("unimplemented");
}
----------------
shafik wrote:
> cor3ntin wrote:
> > You can probably just fall through, a list of expression only has side effects if the individual expressions do, which the code just below is doing.
> On Discourse, the suggestion was made to have use `InitListExpr` as a base class and in that case I believe we should do the same that that we do for `InitListExpr`.
See the response from @ilya-biryukov for why I decided against inheriting from `InitListExpr`.
================
Comment at: clang/lib/AST/ExprClassification.cpp:446
+
+ case Expr::CXXParenListInitExprClass:
+ // FIXME: unimplemented
----------------
shafik wrote:
> This looks like we should handle this similar to `InitListExpr` but I am not sure if single element if it is bound to a reference can be an lvalue holds as well here as well CC @erichkeane
IMO; no.
I believe the comment for `InitListExpr` refers to statements like:
```
int a;
int &b{a};
```
This doesn't apply to `CXXParenListInitExprClass` because the corresponding statement with parentheses wouldn't be parsed as a `CXXParenListInitExpr` in the first place.
================
Comment at: clang/lib/AST/StmtPrinter.cpp:2459
+void StmtPrinter::VisitCXXParenListInitExpr(CXXParenListInitExpr *Node) {
+ // FIXME: unimplemented
+ llvm_unreachable("unimplemented");
----------------
shafik wrote:
> Assuming we go w/ `InitListExpr` as a base class then you should do something similar to ` StmtPrinter::VisitInitListExpr(...)` except with parens.
See the response from @ilya-biryukov for why I decided against inheriting from `InitListExpr`.
================
Comment at: clang/lib/Sema/TreeTransform.h:13922
+template <typename Derived>
+ExprResult
----------------
This is an extra change, but `clang-format` would always make it.
================
Comment at: clang/lib/Serialization/ASTReaderStmt.cpp:2179
+ for (unsigned I = 0; I < E->NumExprs; I++)
+ E->getTrailingObjects<Expr *>()[I] = Record.readSubExpr();
+}
----------------
ilya-biryukov wrote:
> ayzhao wrote:
> > ilya-biryukov wrote:
> > > FYI: I think this is where the crash comes from.
> > > We should allocate the trailing objects first.
> > > E.g. see how `PragmaCommentDecl::CreateDeserialized` does this.
> > This sounds like it could be the solution - thanks for looking at it!
> >
> > Currently, I'm working on the refactor that shafik@ suggested, which was to inherit from `InitListExpr`. Hopefully, that refactor will fix this issue as `InitListExpr` stores it's subexpressions in a class member instead of using `llvm::TrailingObjects`.
> Are we trying to share code between two implementations? If so, I suggest to consider alternatives, e.g. creating a new base class and inheriting both `InitListExpr` and `CXXParentInitListExpr` to share the common code.
>
> Inheriting `CXXParentInitListExpr` from `InitListExpr` breaks [Liskov substitution principle](https://en.wikipedia.org/wiki/Liskov_substitution_principle) and will likely to lead to bugs that are hard to chase. `InitListExpr` is widely used and means`{}`. `CXXParenInitListExpr` is not `{}` and we do not know in advance which code is going to work for both and which code is only valid for `{}`. Reviewing all callsites that use `InitListExpr` does not seem plausible. Note that in addition to Clang, there are also uses in ast-matchers and in clang-tidy checks (quite a few of those are downstream).
So I figured out why this was failing. When I created the `CXXParenListInitExpr` object on the heap in `ASTReader::ReadStmtFromStream(...)` below, I just called `new` without allocating any space for the `TrailingObjects`. This is fixed now, and the PCH test passes.
> Inheriting CXXParentInitListExpr from InitListExpr breaks Liskov substitution principle and will likely to lead to bugs that are hard to chase. InitListExpr is widely used and means`{}. CXXParenInitListExpr` is not {} and we do not know in advance which code is going to work for both and which code is only valid for {}. Reviewing all callsites that use InitListExpr does not seem plausible. Note that in addition to Clang, there are also uses in ast-matchers and in clang-tidy checks (quite a few of those are downstream).
+1, I am convinced that inheriting from `InitListExpr` is the wrong thing to do here. Additionally, when I tried to inherit from `InitListExpr`, I found that there were a lot of things in that class that were specific to `InitListExpr` that I had to wrap with an `if` statement to make it work with `CXXParenListInitExpr`, and that the amount of code that I had to add considerably decreases readability.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D129531/new/
https://reviews.llvm.org/D129531
More information about the cfe-commits
mailing list