[clang] 145f353 - [clang][dataflow] fix failing assert in copyRecord

Paul Semel via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 26 01:53:01 PDT 2023


Author: Paul Semel
Date: 2023-07-26T08:52:06Z
New Revision: 145f353fd67909e03c39b968b464ac625edde6cb

URL: https://github.com/llvm/llvm-project/commit/145f353fd67909e03c39b968b464ac625edde6cb
DIFF: https://github.com/llvm/llvm-project/commit/145f353fd67909e03c39b968b464ac625edde6cb.diff

LOG: [clang][dataflow] fix failing assert in copyRecord

When dealing with copy constructor, the compiler can emit an
UncheckedDerivedToBase implicit cast for the CXXConstructorExpr of the
base class. In such case, when trying to copy the src storage location
to its destination, we will fail on the assert checking that location
types are the same.

When copying from derived to base class, it is acceptable to break that
assumption to only copy common fields from the base class.

Note: the provided test crashes the process without the changes made to
copyRecord.

Differential Revision: https://reviews.llvm.org/D155844

Added: 
    

Modified: 
    clang/lib/Analysis/FlowSensitive/RecordOps.cpp
    clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Analysis/FlowSensitive/RecordOps.cpp b/clang/lib/Analysis/FlowSensitive/RecordOps.cpp
index 60144531c25186..95693f2e933a49 100644
--- a/clang/lib/Analysis/FlowSensitive/RecordOps.cpp
+++ b/clang/lib/Analysis/FlowSensitive/RecordOps.cpp
@@ -17,18 +17,27 @@
 void clang::dataflow::copyRecord(AggregateStorageLocation &Src,
                                  AggregateStorageLocation &Dst,
                                  Environment &Env) {
+  auto SrcType = Src.getType().getCanonicalType().getUnqualifiedType();
+  auto DstType = Dst.getType().getCanonicalType().getUnqualifiedType();
+
+  auto SrcDecl = SrcType->getAsCXXRecordDecl();
+  auto DstDecl = DstType->getAsCXXRecordDecl();
+
+  bool compatibleTypes =
+      SrcType == DstType ||
+      (SrcDecl && DstDecl && SrcDecl->isDerivedFrom(DstDecl));
+  (void)compatibleTypes;
+
   LLVM_DEBUG({
-    if (Dst.getType().getCanonicalType().getUnqualifiedType() !=
-        Src.getType().getCanonicalType().getUnqualifiedType()) {
+    if (!compatibleTypes) {
       llvm::dbgs() << "Source type " << Src.getType() << "\n";
       llvm::dbgs() << "Destination type " << Dst.getType() << "\n";
     }
   });
-  assert(Dst.getType().getCanonicalType().getUnqualifiedType() ==
-         Src.getType().getCanonicalType().getUnqualifiedType());
+  assert(compatibleTypes);
 
-  for (auto [Field, SrcFieldLoc] : Src.children()) {
-    StorageLocation *DstFieldLoc = Dst.getChild(*Field);
+  for (auto [Field, DstFieldLoc] : Dst.children()) {
+    StorageLocation *SrcFieldLoc = Src.getChild(*Field);
 
     assert(Field->getType()->isReferenceType() ||
            (SrcFieldLoc != nullptr && DstFieldLoc != nullptr));

diff  --git a/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp b/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp
index 2b4b64c74481fb..b4eb0f26bf76be 100644
--- a/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp
@@ -194,6 +194,40 @@ TEST(RecordOpsTest, RecordsEqual) {
       });
 }
 
+TEST(TransferTest, CopyRecordFromDerivedToBase) {
+  std::string Code = R"(
+    struct A {
+      int i;
+    };
+
+    struct B : public A {
+    };
+
+    void target(A a, B b) {
+      (void)a.i;
+      // [[p]]
+    }
+  )";
+  runDataflow(
+      Code,
+      [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+         ASTContext &ASTCtx) {
+        Environment Env = getEnvironmentAtAnnotation(Results, "p").fork();
+
+        const ValueDecl *IDecl = findValueDecl(ASTCtx, "i");
+        auto &A = getLocForDecl<AggregateStorageLocation>(ASTCtx, Env, "a");
+        auto &B = getLocForDecl<AggregateStorageLocation>(ASTCtx, Env, "b");
+
+        EXPECT_NE(Env.getValue(*A.getChild(*IDecl)),
+                  Env.getValue(*B.getChild(*IDecl)));
+
+        copyRecord(B, A, Env);
+
+        EXPECT_EQ(Env.getValue(*A.getChild(*IDecl)),
+                  Env.getValue(*B.getChild(*IDecl)));
+      });
+}
+
 } // namespace
 } // namespace test
 } // namespace dataflow


        


More information about the cfe-commits mailing list