-
Notifications
You must be signed in to change notification settings - Fork 15k
[clang][dataflow] Copy only the fields present in the current derived… #162100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3709,6 +3709,80 @@ TEST(TransferTest, StaticCastBaseToDerived) { | |
| }); | ||
| } | ||
|
|
||
| TEST(TransferTest, MultipleConstructionsFromStaticCastsBaseToDerived) { | ||
| std::string Code = R"cc( | ||
| struct Base {}; | ||
|
|
||
| struct DerivedOne : public Base { | ||
| // Need a field in one of the derived siblings that the other doesn't have. | ||
| int I; | ||
| }; | ||
|
|
||
| struct DerivedTwo : public Base {}; | ||
|
|
||
| int getInt(); | ||
|
|
||
| void target(Base* B) { | ||
| // Need something to cause modeling of I. | ||
| DerivedOne D1; | ||
| (void)D1.I; | ||
|
|
||
| // Switch cases are a reasonable pattern where the same variable might be | ||
| // safely cast to two different derived types within the same function | ||
| // without resetting the value of the variable. getInt is a stand-in for what | ||
| // is usually a function indicating the dynamic derived type. | ||
| switch (getInt()) { | ||
| case 1: | ||
| // Need a CXXConstructExpr or copy/move CXXOperatorCallExpr from each of | ||
| // the casts to derived types, cast from the same base variable, to | ||
| // trigger the copyRecord behavior. | ||
| (void)new DerivedOne(*static_cast<DerivedOne*>(B)); | ||
| break; | ||
| case 2: | ||
| (void)new DerivedTwo(*static_cast<DerivedTwo*>(B)); | ||
| break; | ||
| }; | ||
| } | ||
| )cc"; | ||
| runDataflow( | ||
| Code, | ||
| [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, | ||
| ASTContext &ASTCtx) { | ||
| // This is a crash repro. We used to crash when transferring the | ||
| // construction of DerivedTwo because B's StorageLocation had a child | ||
| // for the field I, but DerivedTwo doesn't. Now, we should only copy the | ||
| // fields from B that are present in DerivedTwo. | ||
| }); | ||
| } | ||
|
|
||
| TEST(TransferTest, CopyConstructionOfBaseAfterStaticCastsBaseToDerived) { | ||
| std::string Code = R"cc( | ||
| struct Base {}; | ||
|
|
||
| struct Derived : public Base { | ||
| // Need a field in Derived that is not in Base. | ||
| char C; | ||
| }; | ||
|
|
||
| void target(Base* B, Base* OtherB) { | ||
| Derived* D = static_cast<Derived*>(B); | ||
| *B = *OtherB; | ||
| // Need something to cause modeling of C. | ||
| (void)D->C; | ||
| } | ||
|
|
||
| )cc"; | ||
| runDataflow( | ||
| Code, | ||
| [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, | ||
| ASTContext &ASTCtx) { | ||
| // This is a crash repro. We used to crash when transferring the | ||
| // copy construction of B from OtherB because B's StorageLocation had a | ||
| // child for the field C, but Base doesn't. Now, we should only copy the | ||
|
||
| // fields from B that are present in Base. | ||
|
||
| }); | ||
| } | ||
|
|
||
| TEST(TransferTest, ExplicitDerivedToBaseCast) { | ||
| std::string Code = R"cc( | ||
| struct Base {}; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
out of curiosity, what alerted you to these changes?
does it help to canonicalize Ty first ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new calls in
copyRecordtogetSyntheticFieldswere passing in the type such that it was stringified with the "struct", which caused these existing callbacks to return empty maps.I don't think the API exposing the extension point for synthetic fields sets any sort of limits or expectations for whether the type passed to the callback is canonicalized, so I was hesitant to change the implementation to meet the expectations of a few brittle tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see, ok!