jyu2 created this revision.
jyu2 added reviewers: cfe-commits, erichkeane, majnemer, rnk.
jyu2 set the repository for this revision to rL LLVM.
jyu2 added a project: clang-c.

The problem only happen on window ( A MSVC compatibility issues)

The nature of the problem is virtual base dtor called more than it is needed 
after exception throw in inheriting base class(with virtual bases) ctor.

The root problem is when throw happen, not all virtual base classes have been 
contructed, so not all virtual base dtors are need to call for ehcleanup.

clang has code to handle vbase initialization: basically add check for 
"complete object flag" before call to v-base ctor.
But that part is missing for cleanup code.

To fix this add similar code as v-base init to cleanup code, same algorithm.

1> Add new routine:
EmitDtorCompleteObjectHandler

With corresponding to EmitCtorCompleteObjectHandler

2> In the EmitDestructorCal
Call EmitDtorCompleteObjectHandler when generate ehcleanup inside ctor.

Just add check for "complete object flag" before call to v-base dtor.

Please let me know you need more info.


Repository:
  rL LLVM

https://reviews.llvm.org/D27358

Files:
  lib/CodeGen/MicrosoftCXXABI.cpp
  test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp

Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -164,6 +164,9 @@
   llvm::BasicBlock *
   EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
                                 const CXXRecordDecl *RD) override;
+  
+  llvm::BasicBlock *
+  EmitDtorCompleteObjectHandler(CodeGenFunction &CGF);
 
   void initializeHiddenVirtualInheritanceMembers(CodeGenFunction &CGF,
                                               const CXXRecordDecl *RD) override;
@@ -1127,6 +1130,25 @@
   return SkipVbaseCtorsBB;
 }
 
+llvm::BasicBlock *
+MicrosoftCXXABI::EmitDtorCompleteObjectHandler(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 *CallVbaseDtorsBB = CGF.createBasicBlock("Dtor.dtor_vbases");
+  llvm::BasicBlock *SkipVbaseDtorsBB = CGF.createBasicBlock("Dtor.skip_vbases");
+  CGF.Builder.CreateCondBr(IsCompleteObject,
+                           CallVbaseDtorsBB, SkipVbaseDtorsBB);
+
+  CGF.EmitBlock(CallVbaseDtorsBB);
+  // CGF will put the base dtor calls in this basic block for us later.
+    
+  return SkipVbaseDtorsBB;
+}
+
 void MicrosoftCXXABI::initializeHiddenVirtualInheritanceMembers(
     CodeGenFunction &CGF, const CXXRecordDecl *RD) {
   // In most cases, an override for a vbase virtual method can adjust
@@ -1502,11 +1524,24 @@
     This = adjustThisArgumentForVirtualFunctionCall(CGF, GlobalDecl(DD, Type),
                                                     This, false);
   }
+  
+  llvm::BasicBlock *BaseDtorEndBB = nullptr;
+  if (ForVirtualBase && isa<CXXConstructorDecl>(CGF.CurCodeDecl)) {
+    const CXXRecordDecl *ClassDecl =
+             cast<CXXConstructorDecl>(CGF.CurCodeDecl)->getParent();
+    if (ClassDecl != nullptr && ClassDecl->getNumVBases())
+      BaseDtorEndBB = EmitDtorCompleteObjectHandler(CGF);
+  }  
 
   CGF.EmitCXXDestructorCall(DD, Callee, This.getPointer(),
                             /*ImplicitParam=*/nullptr,
                             /*ImplicitParamTy=*/QualType(), nullptr,
                             getFromDtorType(Type));
+  if (BaseDtorEndBB) {
+    // Complete object handler should continue to be the remaining 
+    CGF.Builder.CreateBr(BaseDtorEndBB);
+    CGF.EmitBlock(BaseDtorEndBB);
+  } 
 }
 
 void MicrosoftCXXABI::emitVTableTypeMetadata(const VPtrInfo &Info,
Index: test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
===================================================================
--- test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
+++ test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
@@ -278,3 +278,41 @@
 // WIN32-LIFETIME: %[[bc2:.*]] = bitcast %"struct.lifetime_marker::C"* %[[c]] to i8*
 // WIN32-LIFETIME: call void @llvm.lifetime.end(i64 1, i8* %[[bc2]])
 }
+
+
+struct class_2 {
+  int var_0;
+  class_2() {};
+  virtual ~class_2() {
+  }
+};
+
+struct class_1 : virtual class_2 {
+  class_1() {throw "Unhandled exception";}
+  virtual ~class_1() {}
+};
+struct class_0 : class_1 {
+  class_0() ;
+  virtual ~class_0() {}
+};
+
+class_0::class_0() {
+  // WIN32: define x86_thiscallcc %struct.class_0* @"\01??0class_0@@QAE@XZ"(%struct.class_0* returned %this, i32 %is_most_derived) 
+  // WIN32: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
+  // WIN32: %[[IS_MOST_DERIVED_VAL:.*]] = load i32, i32* %[[IS_MOST_DERIVED_VAR]]
+  // WIN32: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
+  // WIN32: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
+  // WIN32: [[INIT_VBASES]]
+  // WIN32: br label %[[SKIP_VBASES]]
+  // WIN32: [[SKIP_VBASES]]
+// ehcleanup:
+  // WIN32: %[[CLEANUPPAD:.*]] = cleanuppad within none []
+  // WIN32-NEXT: bitcast %{{.*}}* %{{.*}} to i8*
+  // WIN32-NEXT: getelementptr inbounds i8, i8* %{{.*}}, i{{.*}} {{.}} 
+  // WIN32-NEXT: bitcast i8* %{{.*}} to %{{.*}}*
+  // WIN32-NEXT: %[[SHOULD_CALL_VBASE_DTOR:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
+  // WIN32-NEXT: br i1 %[[SHOULD_CALL_VBASE_DTOR]], label %[[DTOR_VBASE:.*]], label %[[SKIP_VBASE:.*]]
+  // WIN32: [[DTOR_VBASE]]
+  // WIN32: br label %[[SKIP_VBASE]]
+  // WIN32: [[SKIP_VBASE]]
+}
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to