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

Reply via email to