[clang] 968b417 - [clang][Interp] Fix derived-to-base casts for >1 levels

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 3 02:36:18 PDT 2023


Author: Timm Bäder
Date: 2023-04-03T11:35:55+02:00
New Revision: 968b4172f6a9878e56dc911f3f9df089d2a9134f

URL: https://github.com/llvm/llvm-project/commit/968b4172f6a9878e56dc911f3f9df089d2a9134f
DIFF: https://github.com/llvm/llvm-project/commit/968b4172f6a9878e56dc911f3f9df089d2a9134f.diff

LOG: [clang][Interp] Fix derived-to-base casts for >1 levels

The GetPtrBasePop op we were using only works for direct base classes.

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

Added: 
    

Modified: 
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.h
    clang/test/AST/Interp/records.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 733247787d760..ad802f72aad4c 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -85,15 +85,8 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
     if (!this->visit(SubExpr))
       return false;
 
-    const CXXRecordDecl *FromDecl = getRecordDecl(SubExpr);
-    assert(FromDecl);
-    const CXXRecordDecl *ToDecl = getRecordDecl(CE);
-    assert(ToDecl);
-    const Record *R = getRecord(FromDecl);
-    const Record::Base *ToBase = R->getBase(ToDecl);
-    assert(ToBase);
-
-    return this->emitGetPtrBasePop(ToBase->Offset, CE);
+    return this->emitDerivedToBaseCasts(getRecordTy(SubExpr->getType()),
+                                        getRecordTy(CE->getType()), CE);
   }
 
   case CK_FloatingCast: {
@@ -1873,6 +1866,38 @@ void ByteCodeExprGen<Emitter>::emitCleanup() {
     C->emitDestruction();
 }
 
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::emitDerivedToBaseCasts(
+    const RecordType *DerivedType, const RecordType *BaseType, const Expr *E) {
+  // Pointer of derived type is already on the stack.
+  const auto *FinalDecl = cast<CXXRecordDecl>(BaseType->getDecl());
+  const RecordDecl *CurDecl = DerivedType->getDecl();
+  const Record *CurRecord = getRecord(CurDecl);
+  assert(CurDecl && FinalDecl);
+  for (;;) {
+    assert(CurRecord->getNumBases() > 0);
+    // One level up
+    for (const Record::Base &B : CurRecord->bases()) {
+      const auto *BaseDecl = cast<CXXRecordDecl>(B.Decl);
+
+      if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) {
+        // This decl will lead us to the final decl, so emit a base cast.
+        if (!this->emitGetPtrBasePop(B.Offset, E))
+          return false;
+
+        CurRecord = B.R;
+        CurDecl = BaseDecl;
+        break;
+      }
+    }
+    if (CurDecl == FinalDecl)
+      return true;
+  }
+
+  llvm_unreachable("Couldn't find the base class?");
+  return false;
+}
+
 /// When calling this, we have a pointer of the local-to-destroy
 /// on the stack.
 /// Emit destruction of record types (or arrays of record types).

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 4baf5d433c9e0..af5b4678b0703 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -260,6 +260,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   }
 
   bool emitRecordDestruction(const Descriptor *Desc);
+  bool emitDerivedToBaseCasts(const RecordType *DerivedType,
+                              const RecordType *BaseType, const Expr *E);
 
 protected:
   /// Variable to storage mapping.

diff  --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index 448e1c0eb7223..188db827fe08b 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -250,6 +250,21 @@ struct S {
 constexpr S s;
 static_assert(s.m() == 1, "");
 
+#if __cplusplus >= 201703L
+namespace BaseInit {
+  class A {public: int a;};
+  class B : public A {};
+  class C : public A {};
+  class D : public B, public C {};
+
+  // FIXME: Enable this once we support the initialization.
+  // This initializes D::B::A::a and not D::C::A::a.
+  //constexpr D d{12};
+  //static_assert(d.B::a == 12);
+  //static_assert(d.C::a == 0);
+};
+#endif
+
 namespace MI {
   class A {
   public:


        


More information about the cfe-commits mailing list