[clang] [clang][dataflow] Fix assert-fail when calling assignment operator with by-value parameter. (PR #71384)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 6 04:14:12 PST 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-analysis
Author: None (martinboehme)
<details>
<summary>Changes</summary>
The code assumed that the source parameter of an assignment operator is always
passed by reference, but it is legal for it to be passed by value.
This patch includes a test that assert-fails without the fix.
---
Full diff: https://github.com/llvm/llvm-project/pull/71384.diff
2 Files Affected:
- (modified) clang/lib/Analysis/FlowSensitive/Transfer.cpp (+8-2)
- (modified) clang/unittests/Analysis/FlowSensitive/TransferTest.cpp (+37)
``````````diff
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index bb26e9f8dc8db85..8b2f8ecc5027e8a 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -514,8 +514,14 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
!Method->isMoveAssignmentOperator())
return;
- auto *LocSrc =
- cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Arg1));
+ RecordStorageLocation *LocSrc = nullptr;
+ if (Arg1->isPRValue()) {
+ if (auto *Val = cast_or_null<RecordValue>(Env.getValue(*Arg1)))
+ LocSrc = &Val->getLoc();
+ } else {
+ LocSrc =
+ cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Arg1));
+ }
auto *LocDst =
cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Arg0));
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 0f9f13df817075e..bd9b98178b5d4e3 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -2213,6 +2213,43 @@ TEST(TransferTest, AssignmentOperator) {
});
}
+// It's legal for the assignment operator to take its source parameter by value.
+// Check that we handle this correctly. (This is a repro -- we used to
+// assert-fail on this.)
+TEST(TransferTest, AssignmentOperator_ArgByValue) {
+ std::string Code = R"(
+ struct A {
+ int Baz;
+ A &operator=(A);
+ };
+
+ void target() {
+ A Foo = { 1 };
+ A Bar = { 2 };
+ Foo = Bar;
+ // [[p]]
+ }
+ )";
+ runDataflow(
+ Code,
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+ ASTContext &ASTCtx) {
+ const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+ const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
+
+ const auto &FooLoc =
+ getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo");
+ const auto &BarLoc =
+ getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar");
+
+ const auto *FooBazVal =
+ cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env));
+ const auto *BarBazVal =
+ cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env));
+ EXPECT_EQ(FooBazVal, BarBazVal);
+ });
+}
+
TEST(TransferTest, AssignmentOperatorFromBase) {
// This is a crash repro. We don't model the copy this case, so no
// expectations on the copied field of the base class are checked.
``````````
</details>
https://github.com/llvm/llvm-project/pull/71384
More information about the cfe-commits
mailing list