r176186 - Better support for constructors with -cxx-abi microsoft, partly fixes PR12784

Timur Iskhodzhanov timurrrr at google.com
Wed Feb 27 05:46:31 PST 2013


Author: timurrrr
Date: Wed Feb 27 07:46:31 2013
New Revision: 176186

URL: http://llvm.org/viewvc/llvm-project?rev=176186&view=rev
Log:
Better support for constructors with -cxx-abi microsoft, partly fixes PR12784

Modified:
    cfe/trunk/lib/AST/MicrosoftMangle.cpp
    cfe/trunk/lib/CodeGen/CGCXX.cpp
    cfe/trunk/lib/CodeGen/CGCXXABI.cpp
    cfe/trunk/lib/CodeGen/CGCXXABI.h
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/lib/CodeGen/CGVTables.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp

Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=176186&r1=176185&r2=176186&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Wed Feb 27 07:46:31 2013
@@ -503,6 +503,10 @@ MicrosoftCXXNameMangler::mangleUnqualifi
       llvm_unreachable("Can't mangle Objective-C selector names here!");
       
     case DeclarationName::CXXConstructorName:
+      if (ND == Structor) {
+        assert(StructorType == Ctor_Complete &&
+               "Should never be asked to mangle a ctor other than complete");
+      }
       Out << "?0";
       break;
       

Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=176186&r1=176185&r2=176186&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Wed Feb 27 07:46:31 2013
@@ -183,14 +183,16 @@ void CodeGenModule::EmitCXXConstructors(
 
   // The constructor used for constructing this as a base class;
   // ignores virtual bases.
-  EmitGlobal(GlobalDecl(D, Ctor_Base));
+  if (getTarget().getCXXABI().hasConstructorVariants())
+    EmitGlobal(GlobalDecl(D, Ctor_Base));
 }
 
 void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor,
                                        CXXCtorType ctorType) {
   // The complete constructor is equivalent to the base constructor
   // for classes with no virtual bases.  Try to emit it as an alias.
-  if (ctorType == Ctor_Complete &&
+  if (getTarget().getCXXABI().hasConstructorVariants() &&
+      ctorType == Ctor_Complete &&
       !ctor->getParent()->getNumVBases() &&
       !TryEmitDefinitionAsAlias(GlobalDecl(ctor, Ctor_Complete),
                                 GlobalDecl(ctor, Ctor_Base)))

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=176186&r1=176185&r2=176186&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Wed Feb 27 07:46:31 2013
@@ -248,3 +248,12 @@ llvm::Constant *CGCXXABI::getMemberPoint
                                           E->path_begin(),
                                           E->path_end());
 }
+
+llvm::BasicBlock *CGCXXABI::EmitCtorCompleteObjectHandler(
+                                                         CodeGenFunction &CGF) {
+  if (CGM.getTarget().getCXXABI().hasConstructorVariants())
+    llvm_unreachable("shouldn't be called in this ABI");
+
+  ErrorUnsupportedABI(CGF, "complete object detection in ctor");
+  return 0;
+}

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=176186&r1=176185&r2=176186&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Wed Feb 27 07:46:31 2013
@@ -185,6 +185,8 @@ public:
                                          CanQualType &ResTy,
                                SmallVectorImpl<CanQualType> &ArgTys) = 0;
 
+  virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF);
+
   /// Build the signature of the given destructor variant by adding
   /// any required parameters.  For convenience, ResTy has been
   /// initialized to 'void' and ArgTys has been initialized with the
@@ -207,6 +209,14 @@ public:
   /// Emit the ABI-specific prolog for the function.
   virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
 
+  virtual void EmitConstructorCall(CodeGenFunction &CGF,
+                                   const CXXConstructorDecl *D,
+                                   CXXCtorType Type, bool ForVirtualBase,
+                                   bool Delegating,
+                                   llvm::Value *This,
+                                   CallExpr::const_arg_iterator ArgBeg,
+                                   CallExpr::const_arg_iterator ArgEnd) = 0;
+
   /// Emit the ABI-specific virtual destructor call.
   virtual RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
                                            const CXXDestructorDecl *Dtor,

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=176186&r1=176185&r2=176186&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Wed Feb 27 07:46:31 2013
@@ -15,6 +15,7 @@
 #include "CGDebugInfo.h"
 #include "CGRecordLayout.h"
 #include "CodeGenFunction.h"
+#include "CGCXXABI.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/EvaluatedExprVisitor.h"
 #include "clang/AST/RecordLayout.h"
@@ -280,18 +281,16 @@ CodeGenFunction::GetAddressOfDerivedClas
   
   return Value;
 }
-                             
-/// GetVTTParameter - Return the VTT parameter that should be passed to a
-/// base constructor/destructor with virtual bases.
-static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD,
-                                    bool ForVirtualBase,
-                                    bool Delegating) {
+
+llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD,
+                                              bool ForVirtualBase,
+                                              bool Delegating) {
   if (!CodeGenVTables::needsVTTParameter(GD)) {
     // This constructor/destructor does not need a VTT parameter.
     return 0;
   }
   
-  const CXXRecordDecl *RD = cast<CXXMethodDecl>(CGF.CurFuncDecl)->getParent();
+  const CXXRecordDecl *RD = cast<CXXMethodDecl>(CurFuncDecl)->getParent();
   const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent();
 
   llvm::Value *VTT;
@@ -300,34 +299,33 @@ static llvm::Value *GetVTTParameter(Code
 
   if (Delegating) {
     // If this is a delegating constructor call, just load the VTT.
-    return CGF.LoadCXXVTT();
+    return LoadCXXVTT();
   } else if (RD == Base) {
     // If the record matches the base, this is the complete ctor/dtor
     // variant calling the base variant in a class with virtual bases.
-    assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) &&
+    assert(!CodeGenVTables::needsVTTParameter(CurGD) &&
            "doing no-op VTT offset in base dtor/ctor?");
     assert(!ForVirtualBase && "Can't have same class as virtual base!");
     SubVTTIndex = 0;
   } else {
-    const ASTRecordLayout &Layout = 
-      CGF.getContext().getASTRecordLayout(RD);
+    const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
     CharUnits BaseOffset = ForVirtualBase ? 
       Layout.getVBaseClassOffset(Base) : 
       Layout.getBaseClassOffset(Base);
 
     SubVTTIndex = 
-      CGF.CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset));
+      CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset));
     assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
   }
   
-  if (CodeGenVTables::needsVTTParameter(CGF.CurGD)) {
+  if (CodeGenVTables::needsVTTParameter(CurGD)) {
     // A VTT parameter was passed to the constructor, use it.
-    VTT = CGF.LoadCXXVTT();
-    VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
+    VTT = LoadCXXVTT();
+    VTT = Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
   } else {
     // We're the complete constructor, so get the VTT by name.
-    VTT = CGF.CGM.getVTables().GetAddrOfVTT(RD);
-    VTT = CGF.Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex);
+    VTT = CGM.getVTables().GetAddrOfVTT(RD);
+    VTT = Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex);
   }
 
   return VTT;
@@ -1103,27 +1101,46 @@ void CodeGenFunction::EmitCtorPrologue(c
 
   const CXXRecordDecl *ClassDecl = CD->getParent();
 
-  SmallVector<CXXCtorInitializer *, 8> MemberInitializers;
-  
-  for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
-       E = CD->init_end();
-       B != E; ++B) {
-    CXXCtorInitializer *Member = (*B);
-    
-    if (Member->isBaseInitializer()) {
-      EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
-    } else {
-      assert(Member->isAnyMemberInitializer() &&
-            "Delegating initializer on non-delegating constructor");
-      MemberInitializers.push_back(Member);
-    }
+  CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
+                                          E = CD->init_end();
+
+  llvm::BasicBlock *BaseCtorContinueBB = 0;
+  if (ClassDecl->getNumVBases() &&
+      !CGM.getTarget().getCXXABI().hasConstructorVariants()) {
+    // The ABIs that don't have constructor variants need to put a branch
+    // before the virtual base initialization code.
+    BaseCtorContinueBB = CGM.getCXXABI().EmitCtorCompleteObjectHandler(*this);
+    assert(BaseCtorContinueBB);
+  }
+
+  // Virtual base initializers first.
+  for (; B != E && (*B)->isBaseInitializer() && (*B)->isBaseVirtual(); B++) {
+    EmitBaseInitializer(*this, ClassDecl, *B, CtorType);
+  }
+
+  if (BaseCtorContinueBB) {
+    // Complete object handler should continue to the remaining initializers.
+    Builder.CreateBr(BaseCtorContinueBB);
+    EmitBlock(BaseCtorContinueBB);
+  }
+
+  // Then, non-virtual base initializers.
+  for (; B != E && (*B)->isBaseInitializer(); B++) {
+    assert(!(*B)->isBaseVirtual());
+    EmitBaseInitializer(*this, ClassDecl, *B, CtorType);
   }
 
   InitializeVTablePointers(ClassDecl);
 
+  // And finally, initialize class members.
   ConstructorMemcpyizer CM(*this, CD, Args);
-  for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I)
-    CM.addMemberInitializer(MemberInitializers[I]);
+  for (; B != E; B++) {
+    CXXCtorInitializer *Member = (*B);
+    assert(!Member->isBaseInitializer());
+    assert(Member->isAnyMemberInitializer() &&
+           "Delegating initializer on non-delegating constructor");
+    CM.addMemberInitializer(Member);
+  }
   CM.finish();
 }
 
@@ -1622,6 +1639,7 @@ CodeGenFunction::EmitCXXConstructorCall(
                               Parent->getLocation());
   }
 
+  // If this is a trivial constructor, just emit what's needed.
   if (D->isTrivial()) {
     if (ArgBeg == ArgEnd) {
       // Trivial default constructor, no codegen required.
@@ -1641,14 +1659,9 @@ CodeGenFunction::EmitCXXConstructorCall(
     return;
   }
 
-  llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase,
-                                     Delegating);
-  llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
-
-  // FIXME: Provide a source location here.
-  EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
-                    VTT, getContext().getPointerType(getContext().VoidPtrTy),
-                    ArgBeg, ArgEnd);
+  // Non-trivial constructors are handled in an ABI-specific manner.
+  CGM.getCXXABI().EmitConstructorCall(*this, D, Type, ForVirtualBase,
+                                      Delegating, This, ArgBeg, ArgEnd);
 }
 
 void
@@ -1718,7 +1731,7 @@ CodeGenFunction::EmitDelegateCXXConstruc
   ++I;
 
   // vtt
-  if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType),
+  if (llvm::Value *VTT = GetVTTParameter(GlobalDecl(Ctor, CtorType),
                                          /*ForVirtualBase=*/false,
                                          /*Delegating=*/true)) {
     QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy);
@@ -1792,7 +1805,7 @@ void CodeGenFunction::EmitCXXDestructorC
                                             bool ForVirtualBase,
                                             bool Delegating,
                                             llvm::Value *This) {
-  llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type), 
+  llvm::Value *VTT = GetVTTParameter(GlobalDecl(DD, Type),
                                      ForVirtualBase, Delegating);
   llvm::Value *Callee = 0;
   if (getLangOpts().AppleKext)

Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=176186&r1=176185&r2=176186&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVTables.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVTables.cpp Wed Feb 27 07:46:31 2013
@@ -813,8 +813,12 @@ CodeGenVTables::GenerateClassData(const
   EmitVTableDefinition(VTable, Linkage, RD);
 
   if (RD->getNumVBases()) {
-    llvm::GlobalVariable *VTT = GetAddrOfVTT(RD);
-    EmitVTTDefinition(VTT, Linkage, RD);
+    if (!CGM.getTarget().getCXXABI().isMicrosoft()) {
+      llvm::GlobalVariable *VTT = GetAddrOfVTT(RD);
+      EmitVTTDefinition(VTT, Linkage, RD);
+    } else {
+      // FIXME: Emit vbtables here.
+    }
   }
 
   // If this is the magic class __cxxabiv1::__fundamental_type_info,

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=176186&r1=176185&r2=176186&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Feb 27 07:46:31 2013
@@ -1818,6 +1818,13 @@ public:
                                          const CXXRecordDecl *ClassDecl,
                                          const CXXRecordDecl *BaseClassDecl);
 
+  /// GetVTTParameter - Return the VTT parameter that should be passed to a
+  /// base constructor/destructor with virtual bases.
+  /// FIXME: VTTs are Itanium ABI-specific, so the definition should move
+  /// to ItaniumCXXABI.cpp together with all the references to VTT.
+  llvm::Value *GetVTTParameter(GlobalDecl GD, bool ForVirtualBase,
+                               bool Delegating);
+
   void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
                                       CXXCtorType CtorType,
                                       const FunctionArgList &Args);

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=176186&r1=176185&r2=176186&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Wed Feb 27 07:46:31 2013
@@ -112,6 +112,14 @@ public:
 
   void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
 
+  void EmitConstructorCall(CodeGenFunction &CGF,
+                           const CXXConstructorDecl *D,
+                           CXXCtorType Type, bool ForVirtualBase,
+                           bool Delegating,
+                           llvm::Value *This,
+                           CallExpr::const_arg_iterator ArgBeg,
+                           CallExpr::const_arg_iterator ArgEnd);
+
   RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
                                    const CXXDestructorDecl *Dtor,
                                    CXXDtorType DtorType,
@@ -826,6 +834,23 @@ void ARMCXXABI::EmitInstanceFunctionProl
     CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
 }
 
+void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
+                                        const CXXConstructorDecl *D,
+                                        CXXCtorType Type, bool ForVirtualBase,
+                                        bool Delegating,
+                                        llvm::Value *This,
+                                        CallExpr::const_arg_iterator ArgBeg,
+                                        CallExpr::const_arg_iterator ArgEnd) {
+  llvm::Value *VTT = CGF.GetVTTParameter(GlobalDecl(D, Type), ForVirtualBase,
+                                         Delegating);
+  QualType VTTTy = getContext().getPointerType(getContext().VoidPtrTy);
+  llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
+
+  // FIXME: Provide a source location here.
+  CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
+                        VTT, VTTTy, ArgBeg, ArgEnd);
+}
+
 RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
                                                 const CXXDestructorDecl *Dtor,
                                                 CXXDtorType DtorType,

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=176186&r1=176185&r2=176186&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Wed Feb 27 07:46:31 2013
@@ -42,6 +42,8 @@ public:
                                  CanQualType &ResTy,
                                  SmallVectorImpl<CanQualType> &ArgTys);
 
+  llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF);
+
   void BuildDestructorSignature(const CXXDestructorDecl *Ctor,
                                 CXXDtorType Type,
                                 CanQualType &ResTy,
@@ -53,6 +55,14 @@ public:
 
   void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
 
+  void EmitConstructorCall(CodeGenFunction &CGF,
+                           const CXXConstructorDecl *D,
+                           CXXCtorType Type, bool ForVirtualBase,
+                           bool Delegating,
+                           llvm::Value *This,
+                           CallExpr::const_arg_iterator ArgBeg,
+                           CallExpr::const_arg_iterator ArgEnd);
+
   RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
                                    const CXXDestructorDecl *Dtor,
                                    CXXDtorType DtorType,
@@ -120,9 +130,36 @@ void MicrosoftCXXABI::BuildConstructorSi
                                  CanQualType &ResTy,
                                  SmallVectorImpl<CanQualType> &ArgTys) {
   // 'this' is already in place
-  // TODO: 'for base' flag
+
   // Ctor returns this ptr
   ResTy = ArgTys[0];
+
+  const CXXRecordDecl *Class = Ctor->getParent();
+  if (Class->getNumVBases()) {
+    // Constructors of classes with virtual bases take an implicit parameter.
+    ArgTys.push_back(CGM.getContext().IntTy);
+  }
+}
+
+llvm::BasicBlock *MicrosoftCXXABI::EmitCtorCompleteObjectHandler(
+                                                         CodeGenFunction &CGF) {
+  llvm::Value *IsMostDerivedClass = getStructorImplicitParamValue(CGF);
+  assert(IsMostDerivedClass &&
+         "ctor for a class with virtual bases must have an implicit parameter");
+  llvm::Value *IsCompleteObject
+    = CGF.Builder.CreateIsNotNull(IsMostDerivedClass, "is_complete_object");
+
+  llvm::BasicBlock *CallVbaseCtorsBB = CGF.createBasicBlock("ctor.init_vbases");
+  llvm::BasicBlock *SkipVbaseCtorsBB = CGF.createBasicBlock("ctor.skip_vbases");
+  CGF.Builder.CreateCondBr(IsCompleteObject,
+                           CallVbaseCtorsBB, SkipVbaseCtorsBB);
+
+  CGF.EmitBlock(CallVbaseCtorsBB);
+  // FIXME: emit vbtables somewhere around here.
+
+  // CGF will put the base ctor calls in this basic block for us later.
+
+  return SkipVbaseCtorsBB;
 }
 
 void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
@@ -153,9 +190,18 @@ void MicrosoftCXXABI::BuildInstanceFunct
   if (needThisReturn(CGF.CurGD)) {
     ResTy = Params[0]->getType();
   }
-  if (IsDeletingDtor(CGF.CurGD)) {
-    ASTContext &Context = getContext();
 
+  ASTContext &Context = getContext();
+  const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
+  if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
+    ImplicitParamDecl *IsMostDerived
+      = ImplicitParamDecl::Create(Context, 0,
+                                  CGF.CurGD.getDecl()->getLocation(),
+                                  &Context.Idents.get("is_most_derived"),
+                                  Context.IntTy);
+    Params.push_back(IsMostDerived);
+    getStructorImplicitParamDecl(CGF) = IsMostDerived;
+  } else if (IsDeletingDtor(CGF.CurGD)) {
     ImplicitParamDecl *ShouldDelete
       = ImplicitParamDecl::Create(Context, 0,
                                   CGF.CurGD.getDecl()->getLocation(),
@@ -171,6 +217,17 @@ void MicrosoftCXXABI::EmitInstanceFuncti
   if (needThisReturn(CGF.CurGD)) {
     CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
   }
+
+  const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
+  if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
+    assert(getStructorImplicitParamDecl(CGF) &&
+           "no implicit parameter for a constructor with virtual bases?");
+    getStructorImplicitParamValue(CGF)
+      = CGF.Builder.CreateLoad(
+          CGF.GetAddrOfLocalVar(getStructorImplicitParamDecl(CGF)),
+          "is_most_derived");
+  }
+
   if (IsDeletingDtor(CGF.CurGD)) {
     assert(getStructorImplicitParamDecl(CGF) &&
            "no implicit parameter for a deleting destructor?");
@@ -181,6 +238,29 @@ void MicrosoftCXXABI::EmitInstanceFuncti
   }
 }
 
+void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
+                                          const CXXConstructorDecl *D,
+                                          CXXCtorType Type, bool ForVirtualBase,
+                                          bool Delegating,
+                                          llvm::Value *This,
+                                          CallExpr::const_arg_iterator ArgBeg,
+                                          CallExpr::const_arg_iterator ArgEnd) {
+  assert(Type == Ctor_Complete || Type == Ctor_Base);
+  llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Ctor_Complete);
+
+  llvm::Value *ImplicitParam = 0;
+  QualType ImplicitParamTy;
+  if (D->getParent()->getNumVBases()) {
+    ImplicitParam = llvm::ConstantInt::get(CGM.Int32Ty, Type == Ctor_Complete);
+    ImplicitParamTy = getContext().IntTy;
+  }
+
+  // FIXME: Provide a source location here.
+  CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
+                        ImplicitParam, ImplicitParamTy,
+                        ArgBeg, ArgEnd);
+}
+
 RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
                                                   const CXXDestructorDecl *Dtor,
                                                   CXXDtorType DtorType,

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp?rev=176186&r1=176185&r2=176186&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp Wed Feb 27 07:46:31 2013
@@ -4,6 +4,8 @@
 // anywhere in the output.
 // RUN: FileCheck --check-prefix=DTORS %s < %t
 
+namespace basic {
+
 class A {
  public:
   A() { }
@@ -13,37 +15,47 @@ class A {
 void no_constructor_destructor_infinite_recursion() {
   A a;
 
-// CHECK:      define linkonce_odr x86_thiscallcc %class.A* @"\01??0A@@QAE at XZ"(%class.A* %this)
-// CHECK:        [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca %class.A*, align 4
-// CHECK-NEXT:   store %class.A* %this, %class.A** [[THIS_ADDR]], align 4
-// CHECK-NEXT:   [[T1:%[.0-9A-Z_a-z]+]] = load %class.A** [[THIS_ADDR]]
-// CHECK-NEXT:   ret %class.A* [[T1]]
+// CHECK:      define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A at basic@@QAE at XZ"(%"class.basic::A"* %this)
+// CHECK:        [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca %"class.basic::A"*, align 4
+// CHECK-NEXT:   store %"class.basic::A"* %this, %"class.basic::A"** [[THIS_ADDR]], align 4
+// CHECK-NEXT:   [[T1:%[.0-9A-Z_a-z]+]] = load %"class.basic::A"** [[THIS_ADDR]]
+// CHECK-NEXT:   ret %"class.basic::A"* [[T1]]
 // CHECK-NEXT: }
 
 // Make sure that the destructor doesn't call itself:
-// CHECK: define {{.*}} @"\01??1A@@QAE at XZ"
-// CHECK-NOT: call void @"\01??1A@@QAE at XZ"
+// CHECK: define {{.*}} @"\01??1A at basic@@QAE at XZ"
+// CHECK-NOT: call void @"\01??1A at basic@@QAE at XZ"
 // CHECK: ret
 }
 
 struct B {
-  virtual ~B() {
+  B();
+};
+
+// Tests that we can define constructors outside the class (PR12784).
+B::B() {
+  // CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B at basic@@QAE at XZ"(%"struct.basic::B"* %this)
+  // CHECK: ret
+}
+
+struct C {
+  virtual ~C() {
 // Complete destructor first:
-// DTORS: define {{.*}} x86_thiscallcc void @"\01??1B@@UAE at XZ"(%struct.B* %this)
+// DTORS: define {{.*}} x86_thiscallcc void @"\01??1C at basic@@UAE at XZ"(%"struct.basic::C"* %this)
 
 // Then, the scalar deleting destructor (used in the vtable):
 // FIXME: add a test that verifies that the out-of-line scalar deleting
 // destructor is linkonce_odr too.
-// DTORS:      define linkonce_odr x86_thiscallcc void @"\01??_GB@@UAEPAXI at Z"(%struct.B* %this, i1 zeroext %should_call_delete)
+// DTORS:      define linkonce_odr x86_thiscallcc void @"\01??_GC at basic@@UAEPAXI at Z"(%"struct.basic::C"* %this, i1 zeroext %should_call_delete)
 // DTORS:        %[[FROMBOOL:[0-9a-z]+]] = zext i1 %should_call_delete to i8
 // DTORS-NEXT:   store i8 %[[FROMBOOL]], i8* %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 1
 // DTORS:        %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i8* %[[SHOULD_DELETE_VAR]]
-// DTORS:        call x86_thiscallcc void @"\01??1B@@UAE at XZ"(%struct.B* %[[THIS:[0-9a-z]+]])
+// DTORS:        call x86_thiscallcc void @"\01??1C at basic@@UAE at XZ"(%"struct.basic::C"* %[[THIS:[0-9a-z]+]])
 // DTORS-NEXT:   %[[CONDITION:[0-9]+]] = icmp eq i8 %[[SHOULD_DELETE_VALUE]], 0
 // DTORS-NEXT:   br i1 %[[CONDITION]], label %[[CONTINUE_LABEL:[0-9a-z._]+]], label %[[CALL_DELETE_LABEL:[0-9a-z._]+]]
 //
 // DTORS:      [[CALL_DELETE_LABEL]]
-// DTORS-NEXT:   %[[THIS_AS_VOID:[0-9a-z]+]] = bitcast %struct.B* %[[THIS]] to i8*
+// DTORS-NEXT:   %[[THIS_AS_VOID:[0-9a-z]+]] = bitcast %"struct.basic::C"* %[[THIS]] to i8*
 // DTORS-NEXT:   call void @"\01??3 at YAXPAX@Z"(i8* %[[THIS_AS_VOID]]) [[NUW:#[0-9]+]]
 // DTORS-NEXT:   br label %[[CONTINUE_LABEL]]
 //
@@ -54,55 +66,150 @@ struct B {
 };
 
 // Emits the vftable in the output.
-void B::foo() {}
+void C::foo() {}
 
 void check_vftable_offset() {
-  B b;
+  C c;
 // The vftable pointer should point at the beginning of the vftable.
-// CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %struct.B* {{.*}} to i8***
-// CHECK: store i8** getelementptr inbounds ([2 x i8*]* @"\01??_7B@@6B@", i64 0, i64 0), i8*** [[THIS_PTR]]
+// CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %"struct.basic::C"* {{.*}} to i8***
+// CHECK: store i8** getelementptr inbounds ([2 x i8*]* @"\01??_7C at basic@@6B@", i64 0, i64 0), i8*** [[THIS_PTR]]
 }
 
-void call_complete_dtor(B *obj_ptr) {
-// CHECK: define void @"\01?call_complete_dtor@@YAXPAUB@@@Z"(%struct.B* %obj_ptr)
-  obj_ptr->~B();
-// CHECK: %[[OBJ_PTR_VALUE:.*]] = load %struct.B** %{{.*}}, align 4
-// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %struct.B* %[[OBJ_PTR_VALUE]] to void (%struct.B*, i1)***
-// CHECK-NEXT: %[[VTABLE:.*]] = load void (%struct.B*, i1)*** %[[PVTABLE]]
-// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%struct.B*, i1)** %[[VTABLE]], i64 0
-// CHECK-NEXT: %[[VDTOR:.*]] = load void (%struct.B*, i1)** %[[PVDTOR]]
-// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%struct.B* %[[OBJ_PTR_VALUE]], i1 zeroext false)
+void call_complete_dtor(C *obj_ptr) {
+// CHECK: define void @"\01?call_complete_dtor at basic@@YAXPAUC at 1@@Z"(%"struct.basic::C"* %obj_ptr)
+  obj_ptr->~C();
+// CHECK: %[[OBJ_PTR_VALUE:.*]] = load %"struct.basic::C"** %{{.*}}, align 4
+// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i1)***
+// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i1)*** %[[PVTABLE]]
+// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i1)** %[[VTABLE]], i64 0
+// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i1)** %[[PVDTOR]]
+// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i1 zeroext false)
 // CHECK-NEXT: ret void
 }
 
-void call_deleting_dtor(B *obj_ptr) {
-// CHECK: define void @"\01?call_deleting_dtor@@YAXPAUB@@@Z"(%struct.B* %obj_ptr)
+void call_deleting_dtor(C *obj_ptr) {
+// CHECK: define void @"\01?call_deleting_dtor at basic@@YAXPAUC at 1@@Z"(%"struct.basic::C"* %obj_ptr)
   delete obj_ptr;
-// CHECK:      %[[OBJ_PTR_VALUE:.*]] = load %struct.B** %{{.*}}, align 4
-// CHECK:      {{.*}}:{{%{0,1}[0-9]*}}
-// CHECK-NEXT:   %[[PVTABLE:.*]] = bitcast %struct.B* %[[OBJ_PTR_VALUE]] to void (%struct.B*, i1)***
-// CHECK-NEXT:   %[[VTABLE:.*]] = load void (%struct.B*, i1)*** %[[PVTABLE]]
-// CHECK-NEXT:   %[[PVDTOR:.*]] = getelementptr inbounds void (%struct.B*, i1)** %[[VTABLE]], i64 0
-// CHECK-NEXT:   %[[VDTOR:.*]] = load void (%struct.B*, i1)** %[[PVDTOR]]
-// CHECK-NEXT:   call x86_thiscallcc void %[[VDTOR]](%struct.B* %[[OBJ_PTR_VALUE]], i1 zeroext true)
+// CHECK:      %[[OBJ_PTR_VALUE:.*]] = load %"struct.basic::C"** %{{.*}}, align 4
+// CHECK:      br i1 {{.*}}, label %[[DELETE_NULL:.*]], label %[[DELETE_NOTNULL:.*]]
+
+// CHECK:      [[DELETE_NOTNULL]]
+// CHECK-NEXT:   %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i1)***
+// CHECK-NEXT:   %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i1)*** %[[PVTABLE]]
+// CHECK-NEXT:   %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i1)** %[[VTABLE]], i64 0
+// CHECK-NEXT:   %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i1)** %[[PVDTOR]]
+// CHECK-NEXT:   call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i1 zeroext true)
 // CHECK:      ret void
 }
 
-struct C {
+struct D {
   static int foo();
 
-  C() {
+  D() {
     static int ctor_static = foo();
     // CHECK that the static in the ctor gets mangled correctly:
-    // CHECK: @"\01?ctor_static@?1???0C@@QAE at XZ@4HA"
+    // CHECK: @"\01?ctor_static@?1???0D at basic@@QAE at XZ@4HA"
   }
-  ~C() {
+  ~D() {
     static int dtor_static = foo();
     // CHECK that the static in the dtor gets mangled correctly:
-    // CHECK: @"\01?dtor_static@?1???1C@@QAE at XZ@4HA"
+    // CHECK: @"\01?dtor_static@?1???1D at basic@@QAE at XZ@4HA"
   }
 };
 
-void use_C() { C c; }
+void use_D() { D c; }
 
 // DTORS: attributes [[NUW]] = { nounwind{{.*}} }
+
+} // end namespace basic
+
+
+namespace constructors {
+
+struct A {
+  A() {}
+};
+
+struct B : A {
+  B();
+  ~B();
+};
+
+B::B() {
+  // CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B at constructors@@QAE at XZ"(%"struct.constructors::B"* %this)
+  // CHECK: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A at constructors@@QAE at XZ"(%"struct.constructors::A"* %{{.*}})
+  // CHECK: ret
+}
+
+struct C : virtual A {
+  C();
+};
+
+C::C() {
+  // CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C at constructors@@QAE at XZ"(%"struct.constructors::C"* %this, i32 %is_most_derived)
+  // TODO: make sure this works in the Release build too;
+  // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
+  // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
+  // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
+  // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
+  //
+  // CHECK: [[INIT_VBASES]]
+  // CHECK-NEXT: bitcast %"struct.constructors::C"* %{{.*}} to %"struct.constructors::A"*
+  // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A at constructors@@QAE at XZ"(%"struct.constructors::A"* %{{.*}})
+  // CHECK-NEXT: br label %[[SKIP_VBASES]]
+  //
+  // CHECK: [[SKIP_VBASES]]
+  // CHECK: @"\01??_7C at constructors@@6B@"
+  // CHECK: ret
+}
+
+void create_C() {
+  C c;
+  // CHECK: define void @"\01?create_C at constructors@@YAXXZ"()
+  // CHECK: call x86_thiscallcc %"struct.constructors::C"* @"\01??0C at constructors@@QAE at XZ"(%"struct.constructors::C"* %c, i32 1)
+  // CHECK: ret
+}
+
+struct D : C {
+  D();
+};
+
+D::D() {
+  // CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D at constructors@@QAE at XZ"(%"struct.constructors::D"* %this, i32 %is_most_derived) unnamed_addr
+  // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
+  // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
+  // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
+  // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
+  //
+  // CHECK: [[INIT_VBASES]]
+  // CHECK-NEXT: bitcast %"struct.constructors::D"* %{{.*}} to %"struct.constructors::A"*
+  // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A at constructors@@QAE at XZ"(%"struct.constructors::A"* %{{.*}})
+  // CHECK-NEXT: br label %[[SKIP_VBASES]]
+  //
+  // CHECK: [[SKIP_VBASES]]
+  // CHECK: call x86_thiscallcc %"struct.constructors::C"* @"\01??0C at constructors@@QAE at XZ"(%"struct.constructors::C"* %{{.*}}, i32 0)
+  // CHECK: ret
+}
+
+struct E : virtual C {
+  E();
+};
+
+E::E() {
+  // CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E at constructors@@QAE at XZ"(%"struct.constructors::E"* %this, i32 %is_most_derived) unnamed_addr
+  // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
+  // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
+  // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
+  // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
+  //
+  // CHECK: [[INIT_VBASES]]
+  // CHECK-NEXT: bitcast %"struct.constructors::E"* %{{.*}} to %"struct.constructors::A"*
+  // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A at constructors@@QAE at XZ"(%"struct.constructors::A"* %{{.*}})
+  // CHECK: call x86_thiscallcc %"struct.constructors::C"* @"\01??0C at constructors@@QAE at XZ"(%"struct.constructors::C"* %{{.*}}, i32 0)
+  // CHECK-NEXT: br label %[[SKIP_VBASES]]
+  //
+  // CHECK: [[SKIP_VBASES]]
+  // CHECK: ret
+}
+
+} // end namespace constructors





More information about the cfe-commits mailing list