]> granicus.if.org Git - clang/commitdiff
PR12067: When emitting an evaluated constant structure in C++11 mode, don't
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 23 Feb 2012 08:33:23 +0000 (08:33 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 23 Feb 2012 08:33:23 +0000 (08:33 +0000)
forget the vptrs.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151245 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExprConstant.cpp
test/CodeGenCXX/const-init-cxx11.cpp

index 4fc21fe708f8633d3f0994eb7cb3ec31751ad103..a074466ec5305c240d15852348b743a4761757a5 100644 (file)
@@ -53,9 +53,14 @@ private:
     NextFieldOffsetInChars(CharUnits::Zero()),
     LLVMStructAlignment(CharUnits::One()) { }
 
+  void AppendVTablePointer(BaseSubobject Base, llvm::Constant *VTable,
+                           const CXXRecordDecl *VTableClass);
+
   void AppendField(const FieldDecl *Field, uint64_t FieldOffset,
                    llvm::Constant *InitExpr);
 
+  void AppendBytes(CharUnits FieldOffsetInChars, llvm::Constant *InitCst);
+
   void AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
                       llvm::ConstantInt *InitExpr);
 
@@ -66,7 +71,9 @@ private:
   void ConvertStructToPacked();
 
   bool Build(InitListExpr *ILE);
-  void Build(const APValue &Val, QualType ValTy);
+  void Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase,
+             llvm::Constant *VTable, const CXXRecordDecl *VTableClass,
+             CharUnits BaseOffset);
   llvm::Constant *Finalize(QualType Ty);
 
   CharUnits getAlignment(const llvm::Constant *C) const {
@@ -81,14 +88,36 @@ private:
   }
 };
 
+void ConstStructBuilder::AppendVTablePointer(BaseSubobject Base,
+                                             llvm::Constant *VTable,
+                                             const CXXRecordDecl *VTableClass) {
+  // Find the appropriate vtable within the vtable group.
+  uint64_t AddressPoint =
+    CGM.getVTableContext().getVTableLayout(VTableClass).getAddressPoint(Base);
+  llvm::Value *Indices[] = {
+    llvm::ConstantInt::get(CGM.Int64Ty, 0),
+    llvm::ConstantInt::get(CGM.Int64Ty, AddressPoint)
+  };
+  llvm::Constant *VTableAddressPoint =
+    llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Indices);
+
+  // Add the vtable at the start of the object.
+  AppendBytes(CharUnits::Zero(), VTableAddressPoint);
+}
+
 void ConstStructBuilder::
 AppendField(const FieldDecl *Field, uint64_t FieldOffset,
             llvm::Constant *InitCst) {
-
   const ASTContext &Context = CGM.getContext();
 
   CharUnits FieldOffsetInChars = Context.toCharUnitsFromBits(FieldOffset);
 
+  AppendBytes(FieldOffsetInChars, InitCst);
+}
+
+void ConstStructBuilder::
+AppendBytes(CharUnits FieldOffsetInChars, llvm::Constant *InitCst) {
+
   assert(NextFieldOffsetInChars <= FieldOffsetInChars
          && "Field offset mismatch!");
 
@@ -399,23 +428,56 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
   return true;
 }
 
-void ConstStructBuilder::Build(const APValue &Val, QualType ValTy) {
-  RecordDecl *RD = ValTy->getAs<RecordType>()->getDecl();
+namespace {
+struct BaseInfo {
+  BaseInfo(const CXXRecordDecl *Decl, CharUnits Offset, unsigned Index)
+    : Decl(Decl), Offset(Offset), Index(Index) {
+  }
+
+  const CXXRecordDecl *Decl;
+  CharUnits Offset;
+  unsigned Index;
+
+  bool operator<(const BaseInfo &O) const { return Offset < O.Offset; }
+};
+}
+
+void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
+                               bool IsPrimaryBase, llvm::Constant *VTable,
+                               const CXXRecordDecl *VTableClass,
+                               CharUnits Offset) {
   const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
 
-  if (CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
+  if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
+    // Add a vtable pointer, if we need one and it hasn't already been added.
+    if (CD->isDynamicClass() && !IsPrimaryBase)
+      AppendVTablePointer(BaseSubobject(CD, Offset), VTable, VTableClass);
+
+    // Accumulate and sort bases, in order to visit them in address order, which
+    // may not be the same as declaration order.
+    llvm::SmallVector<BaseInfo, 8> Bases;
+    Bases.reserve(CD->getNumBases());
     unsigned BaseNo = 0;
-    for (CXXRecordDecl::base_class_iterator Base = CD->bases_begin(),
+    for (CXXRecordDecl::base_class_const_iterator Base = CD->bases_begin(),
          BaseEnd = CD->bases_end(); Base != BaseEnd; ++Base, ++BaseNo) {
-      // Build the base class subobject at the appropriately-offset location
-      // within this object.
+      assert(!Base->isVirtual() && "should not have virtual bases here");
       const CXXRecordDecl *BD = Base->getType()->getAsCXXRecordDecl();
       CharUnits BaseOffset = Layout.getBaseClassOffset(BD);
-      NextFieldOffsetInChars -= BaseOffset;
+      Bases.push_back(BaseInfo(BD, BaseOffset, BaseNo));
+    }
+    std::stable_sort(Bases.begin(), Bases.end());
 
-      Build(Val.getStructBase(BaseNo), Base->getType());
+    for (unsigned I = 0, N = Bases.size(); I != N; ++I) {
+      BaseInfo &Base = Bases[I];
+      // Build the base class subobject at the appropriately-offset location
+      // within this object.
+      NextFieldOffsetInChars -= Base.Offset;
+
+      bool IsPrimaryBase = Layout.getPrimaryBase() == Base.Decl;
+      Build(Val.getStructBase(Base.Index), Base.Decl, IsPrimaryBase,
+            VTable, VTableClass, Offset + Base.Offset);
 
-      NextFieldOffsetInChars += BaseOffset;
+      NextFieldOffsetInChars += Base.Offset;
     }
   }
 
@@ -532,7 +594,15 @@ llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM,
                                                 const APValue &Val,
                                                 QualType ValTy) {
   ConstStructBuilder Builder(CGM, CGF);
-  Builder.Build(Val, ValTy);
+
+  const RecordDecl *RD = ValTy->castAs<RecordType>()->getDecl();
+  const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD);
+  llvm::Constant *VTable = 0;
+  if (CD && CD->isDynamicClass())
+    VTable = CGM.getVTables().GetAddrOfVTable(CD);
+
+  Builder.Build(Val, RD, false, VTable, CD, CharUnits::Zero());
+
   return Builder.Finalize(ValTy);
 }
 
index 0ff8d10f673707b2852d3b966bd7e7c7f2ccfc53..5366d6d485585e94eea5425133b390a8f756fd77 100644 (file)
@@ -254,6 +254,42 @@ namespace NonLiteralConstexpr {
   }
 }
 
+// PR12067
+namespace VirtualMembers {
+  struct A {
+    constexpr A(double d) : d(d) {}
+    virtual void f();
+    double d;
+  };
+  struct B : A {
+    constexpr B() : A(2.0), c{'h', 'e', 'l', 'l', 'o'} {}
+    constexpr B(int n) : A(n), c{'w', 'o', 'r', 'l', 'd'} {}
+    virtual void g();
+    char c[5];
+  };
+  struct C {
+    constexpr C() : n(64) {}
+    int n;
+  };
+  struct D : C, A, B {
+    constexpr D() : A(1.0), B(), s(5) {}
+    short s;
+  };
+  struct E : D, B {
+    constexpr E() : B(3), c{'b','y','e'} {}
+    char c[3];
+  };
+
+  // CHECK: @_ZN14VirtualMembers1eE = global { i8**, double, i32, i8**, double, [5 x i8], i16, i8**, double, [5 x i8], [3 x i8] } { i8** getelementptr inbounds ([11 x i8*]* @_ZTVN14VirtualMembers1EE, i64 0, i64 2), double 1.000000e+00, i32 64, i8** getelementptr inbounds ([11 x i8*]* @_ZTVN14VirtualMembers1EE, i64 0, i64 5), double 2.000000e+00, [5 x i8] c"hello", i16 5, i8** getelementptr inbounds ([11 x i8*]* @_ZTVN14VirtualMembers1EE, i64 0, i64 9), double 3.000000e+00, [5 x i8] c"world", [3 x i8] c"bye" }
+  E e;
+
+  struct nsMemoryImpl {
+    virtual void f();
+  };
+  // CHECK: @_ZN14VirtualMembersL13sGlobalMemoryE = internal global { i8** } { i8** getelementptr inbounds ([3 x i8*]* @_ZTVN14VirtualMembers12nsMemoryImplE, i64 0, i64 2) }
+  static nsMemoryImpl sGlobalMemory;
+}
+
 // Constant initialization tests go before this point,
 // dynamic initialization tests go after.