tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane, tahonermann, shafik.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

  For the given test case, we were trying to initialize a member of C,
  which doesn't have any. Get the proper base pointer instead and
  initialize the members there.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D143466

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

Index: clang/test/AST/Interp/records.cpp
===================================================================
--- clang/test/AST/Interp/records.cpp
+++ clang/test/AST/Interp/records.cpp
@@ -252,6 +252,15 @@
 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 _B {};
+  constexpr _C c{12};
+};
+#endif
+
 namespace MI {
   class A {
   public:
Index: clang/lib/AST/Interp/Record.h
===================================================================
--- clang/lib/AST/Interp/Record.h
+++ clang/lib/AST/Interp/Record.h
@@ -61,6 +61,8 @@
   const Field *getField(const FieldDecl *FD) const;
   /// Returns a base descriptor.
   const Base *getBase(const RecordDecl *FD) const;
+  /// Returns a base descriptor.
+  const Base *getBase(QualType T) const;
   /// Returns a virtual base descriptor.
   const Base *getVirtualBase(const RecordDecl *RD) const;
   // Returns the destructor of the record, if any.
Index: clang/lib/AST/Interp/Record.cpp
===================================================================
--- clang/lib/AST/Interp/Record.cpp
+++ clang/lib/AST/Interp/Record.cpp
@@ -39,6 +39,16 @@
   return It->second;
 }
 
+const Record::Base *Record::getBase(QualType T) const {
+  if (!T->isRecordType())
+    return nullptr;
+
+  const RecordDecl *RD = T->getAs<RecordType>()->getDecl();
+  if (auto It = BaseMap.find(RD); It != BaseMap.end())
+    return It->second;
+  return nullptr;
+}
+
 const Record::Base *Record::getVirtualBase(const RecordDecl *FD) const {
   auto It = VirtualBaseMap.find(FD);
   assert(It != VirtualBaseMap.end() && "Missing virtual base");
Index: clang/lib/AST/Interp/Interp.cpp
===================================================================
--- clang/lib/AST/Interp/Interp.cpp
+++ clang/lib/AST/Interp/Interp.cpp
@@ -434,7 +434,7 @@
 
   // Check Fields in all bases
   for (const Record::Base &B : R->bases()) {
-    Pointer P = Pointer(BasePtr.block(), B.Offset);
+    Pointer P = BasePtr.atField(B.Offset);
     Result &= CheckFieldsInitialized(S, OpPC, P, B.R);
   }
 
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1419,12 +1419,12 @@
 
     unsigned InitIndex = 0;
     for (const Expr *Init : InitList->inits()) {
-      const Record::Field *FieldToInit = R->getField(InitIndex);
 
       if (!this->emitDupPtr(Initializer))
         return false;
 
       if (std::optional<PrimType> T = classify(Init)) {
+        const Record::Field *FieldToInit = R->getField(InitIndex);
         if (!this->visit(Init))
           return false;
 
@@ -1434,16 +1434,29 @@
         if (!this->emitPopPtr(Initializer))
           return false;
       } else {
-        // Non-primitive case. Get a pointer to the field-to-initialize
-        // on the stack and recurse into visitInitializer().
-        if (!this->emitGetPtrField(FieldToInit->Offset, Init))
-          return false;
+        // Initializer for a direct base class.
+        if (const Record::Base *B = R->getBase(Init->getType())) {
+          if (!this->emitGetPtrBasePop(B->Offset, Init))
+            return false;
 
-        if (!this->visitInitializer(Init))
-          return false;
+          if (!this->visitInitializer(Init))
+            return false;
 
-        if (!this->emitPopPtr(Initializer))
-          return false;
+          if (!this->emitPopPtr(Initializer))
+            return false;
+        } else {
+          const Record::Field *FieldToInit = R->getField(InitIndex);
+          // Non-primitive case. Get a pointer to the field-to-initialize
+          // on the stack and recurse into visitInitializer().
+          if (!this->emitGetPtrField(FieldToInit->Offset, Init))
+            return false;
+
+          if (!this->visitInitializer(Init))
+            return false;
+
+          if (!this->emitPopPtr(Initializer))
+            return false;
+        }
       }
       ++InitIndex;
     }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to