kinu added a comment.
Thanks, addressed the comments, PTAL~
================
Comment at: clang/lib/Analysis/FlowSensitive/Transfer.cpp:688-690
+ for ([[maybe_unused]] auto [Field, Loc] : FieldLocs) {
+ assert(ModeledFields.contains(cast_or_null<FieldDecl>(Field)));
+ }
----------------
mboehme wrote:
> https://llvm.org/docs/CodingStandards.html#don-t-use-braces-on-simple-single-statement-bodies-of-if-else-loop-statements
Does it work even if assert() is dropped? ... looks like it does. Ok, applied.
================
Comment at: clang/lib/Analysis/FlowSensitive/Transfer.cpp:672-673
+ // The types are same, or
+ GetCanonicalType(Field->getType()) ==
+ GetCanonicalType(Init->getType()) ||
+ // The field's type is T&, and initializer is T
----------------
mboehme wrote:
> mboehme wrote:
> > Again, this is the prvalue case, so I think you should simply be able to
> > use `QualType::getCanonicalType()`.
> Thinking about this again -- the field can, of course, have qualifiers, while
> the `Init` as a prvalue should not, so I think this should read
>
> ```
> Field->getType().getCanonicalType().getUnqualifiedType() ==
> Init->getType().getCanonicalType()
> ```
>
> Sorry for the back and forth!
No problem, thanks for clarifying the details, done.
================
Comment at: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp:1528-1530
+ F.x4 = F.x2;
+ F.x6 = 1;
+ F.x8 = 1;
----------------
mboehme wrote:
> mboehme wrote:
> > These lines seem unnecessary. The test only wants to check whether the
> > fields are modeled, not what their values are.
> >
> > If anything, leaving out these operations makes the test stronger: It then
> > tests whether the fields are modeled even if they are only initialized with
> > an empty `{}`.
> >
> > Then, once we leave out these operations, it's probably sufficient to give
> > each class in this test just a single member variable (which is another
> > nice simplification).
> Reopening the comment to discuss this line:
>
> > Then, once we leave out these operations, it's probably sufficient to give
> > each class in this test just a single member variable (which is another
> > nice simplification).
>
> I see that giving each class two member variables makes this test consistent
> with the test above -- but OTOH, we're testing exactly the same thing for
> both member variables, so maybe it's better on the whole to simplify the test
> by putting just one member variable in each class?
That's true for this test... now I made each class have only one member.
================
Comment at: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp:2191
+TEST(TransferTest, AssignmentOperatorWithInitAndInheritance) {
+ // This is a crash repro.
+ std::string Code = R"(
----------------
mboehme wrote:
> kinu wrote:
> > mboehme wrote:
> > > IIUC, the crash was happening because `copyRecord()` assumes that the
> > > source and destination have the same fields. More specifically, there was
> > > an unspoken invariant in the framework that a `RecordStorageLocation`
> > > should always contain exactly the fields returned by
> > > `DataflowAnalysisContext::getModeledFields()`), but our treatment of
> > > `InitListExpr` was violating this invariant.
> > >
> > > IOW, this wasn't really an issue with the way we treat copy/move
> > > operations but with `InitlistExpr`.
> > >
> > > I understand that we want to have a test the reproduces the exact
> > > circumstances that led to the crash, but maybe it's enough to have one of
> > > these, and have the focus of the testing be on testing the actual
> > > invariant that we want to maintain? IOW, maybe keep this test but delete
> > > the additional tests below?
> > Dropped the additional tests below.
> I still see more tests below? Suggest dropping these.
Ah I see what you mean. I dropped more!
================
Comment at: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp:2498
+TEST(TransferTest, ReturnStructWithInheritance) {
+ // This is a crash repro. (Returning a struct involves copy/move constructor)
+ std::string Code = R"(
----------------
mboehme wrote:
> kinu wrote:
> > mboehme wrote:
> > > I don't think this is true -- the `return S1` in `target()` will use NRVO.
> > >
> > > But I also don't think it's relevant -- I believe the crash this is
> > > reproducing was triggered by the `InitListExpr`, not the return statement?
> > >
> > > Given the other tests added in this patch, do we need this test?
> > It will use NRVO but in AST this still seems to generate CXXConstructExpr
> > with isCopyOrMoveConstructor() == true because omitting the ctor is not
> > mandatory in compilers.
> >
> > I can drop this one, but I'm also a bit torn because this was the original
> > crash repro that puzzled me a bit.
> >
> > I refined the comment to explain it a bit better; how does it look now?
> > It will use NRVO but in AST this still seems to generate CXXConstructExpr
> > with isCopyOrMoveConstructor() == true
>
> Ah, true, I see this now:
>
> https://godbolt.org/z/z9enG8cW7
>
> > because omitting the ctor is not mandatory in compilers.
>
> TIL that NRVO [isn't
> guaranteed](https://en.cppreference.com/w/cpp/language/copy_elision). (I
> always thought it was!)
>
> I'm still pretty sure though that the `CXXConstructExpr` will have
> `isElidable() == true`, and in this case we [don't call
> `copyRecord()`](https://github.com/llvm/llvm-project/blob/6c6a2d3445671ada6a58b9ab5ce4a1e11e3dd610/clang/lib/Analysis/FlowSensitive/Transfer.cpp#L474):
>
> ```
> if (S->isElidable()) {
> if (Value *Val = Env.getValue(*ArgLoc))
> Env.setValue(*S, *Val);
> } else {
> auto &Val = *cast<RecordValue>(Env.createValue(S->getType()));
> Env.setValue(*S, Val);
> copyRecord(*ArgLoc, Val.getLoc(), Env);
> }
> ```
>
> So I'm not sure that this repro actually triggers the crash? (Can you verify?
> If it does trigger the crash, where am I going wrong in my thinking above?)
>
> > I can drop this one, but I'm also a bit torn because this was the original
> > crash repro that puzzled me a bit.
>
> OK, good to know that this is the original scenario that triggered the crash.
>
> I still think it would be OK to keep only
> AssignmentOperatorWithInitAndInheritance because it also triggers a call to
> `copyRecord()` but does so in a more obvious fashion. And I think for a test
> it's actually useful if it's obvious what is happening.
> I'm still pretty sure though that the `CXXConstructExpr` will have
> `isElidable() == true`, and in this case we [don't call
> `copyRecord()`](https://github.com/llvm/llvm-project/blob/6c6a2d3445671ada6a58b9ab5ce4a1e11e3dd610/clang/lib/Analysis/FlowSensitive/Transfer.cpp#L474):
Interesting, so I looked into it:
Looks like after C++17 isElidable is no longer used in AST:
https://github.com/llvm/llvm-project/blob/2a603deec49cb6a27f3a29480ed8a133eef31cee/clang/include/clang/ASTMatchers/ASTMatchers.h#L8351
(So this test code doesn't take the branch)
NRVO seems to be handled around ReturnStmt, not in each Expr:
https://github.com/llvm/llvm-project/blob/2a603deec49cb6a27f3a29480ed8a133eef31cee/clang/lib/AST/Stmt.cpp#L1202
> [...] because it also triggers a call to `copyRecord()` but does so in a more
> obvious fashion. And I think for a test it's actually useful if it's obvious
> what is happening.
Makes sense, now I dropped this.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D159284/new/
https://reviews.llvm.org/D159284
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits