]> granicus.if.org Git - clang/commitdiff
Ensure that destructors are properly inovked when an exception leaves
authorSean Hunt <scshunt@csclub.uwaterloo.ca>
Tue, 3 May 2011 23:05:34 +0000 (23:05 +0000)
committerSean Hunt <scshunt@csclub.uwaterloo.ca>
Tue, 3 May 2011 23:05:34 +0000 (23:05 +0000)
the body of a delegating constructor call.

This means that the delegating constructor implementation should be
complete and correct, though there are some rough edges (diagnostic
quality with the cycle detection and using a deleted destructor).

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

lib/CodeGen/CGClass.cpp
lib/Sema/SemaDeclCXX.cpp
test/CodeGenCXX/cxx0x-delegating-ctors.cpp
test/SemaCXX/cxx0x-delegating-ctors.cpp

index 12946423adf43ef82f7b191509f8e5f833f3b200..cb4100871384c3b5b7022672f125c37074eae66e 100644 (file)
@@ -1270,6 +1270,23 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
            ReturnValueSlot(), DelegateArgs, Ctor);
 }
 
+namespace {
+  struct CallDelegatingCtorDtor : EHScopeStack::Cleanup {
+    const CXXDestructorDecl *Dtor;
+    llvm::Value *Addr;
+    CXXDtorType Type;
+
+    CallDelegatingCtorDtor(const CXXDestructorDecl *D, llvm::Value *Addr,
+                           CXXDtorType Type)
+      : Dtor(D), Addr(Addr), Type(Type) {}
+
+    void Emit(CodeGenFunction &CGF, bool IsForEH) {
+      CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
+                                Addr);
+    }
+  };
+}
+
 void
 CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor,
                                                   const FunctionArgList &Args) {
@@ -1280,8 +1297,17 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
   AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, false, /*Lifetime*/ true);
 
   EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot);
-}
 
+  const CXXRecordDecl *ClassDecl = Ctor->getParent();
+  if (CGM.getLangOptions().Exceptions && !ClassDecl->hasTrivialDestructor()) {
+    CXXDtorType Type =
+      CurGD.getCtorType() == Ctor_Complete ? Dtor_Complete : Dtor_Base;
+
+    EHStack.pushCleanup<CallDelegatingCtorDtor>(EHCleanup,
+                                                ClassDecl->getDestructor(),
+                                                ThisPtr, Type);
+  }
+}
 
 void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
                                             CXXDtorType Type,
index 94177b1d127d53c2b4ee34275f515537482903ba..6cd5e432412f080433a4870ffe4eaec7f6a96648 100644 (file)
@@ -2095,6 +2095,11 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
   memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*));
   Constructor->setCtorInitializers(initializer);
 
+  if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
+    MarkDeclarationReferenced(Initializer->getSourceLocation(), Dtor);
+    DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
+  }
+
   return false;
 }
 
index 5b432c769016c0a7bbefad87e61798c1a172e7c8..68f492fb9762d4cba216a698c3d3789028e37c3b 100644 (file)
@@ -22,27 +22,35 @@ delegator::delegator() {
   throw 0;
 }
 
+
+delegator::delegator(bool)
+{}
+
+// CHECK: define void @_ZN9delegatorC1Ec
+// CHECK: void @_ZN9delegatorC1Eb
+// CHECK: void @__cxa_throw
+// CHECK: lpad
+// CHECK: void @_ZN9delegatorD1Ev
+// CHECK: define void @_ZN9delegatorC2Ec
+// CHECK: void @_ZN9delegatorC2Eb
+// CHECK: void @__cxa_throw
+// CHECK: lpad
+// CHECK: invoke void @_ZN9delegatorD2Ev
+delegator::delegator(char)
+  : delegator(true) {
+  throw 0;
+}
+
 // CHECK: define void @_ZN9delegatorC1Ei
-// CHECK: call void @_ZN9delegatorC1Ev
+// CHECK: void @_ZN9delegatorC1Ev
 // CHECK-NOT: lpad
 // CHECK: ret
 // CHECK-NOT: lpad
 // CHECK: define void @_ZN9delegatorC2Ei
-// CHECK: call void @_ZN9delegatorC2Ev
+// CHECK: void @_ZN9delegatorC2Ev
 // CHECK-NOT: lpad
 // CHECK: ret
 // CHECK-NOT: lpad
 delegator::delegator(int)
   : delegator()
 {}
-
-delegator::delegator(bool)
-{}
-
-// CHECK: define void @_ZN9delegatorC2Ec
-// CHECK: call void @_ZN9delegatorC2Eb
-// CHECK: call void @__cxa_throw
-delegator::delegator(char)
-  : delegator(true) {
-  throw 0;
-}
index b211cb1fe004a052056fdcbb11e545ce12f1329d..6d0695dfa16f1d98c5d1bc40d8647bdc7f108dd7 100644 (file)
@@ -7,8 +7,9 @@ struct foo {
   foo(int, int);
   foo(bool);
   foo(char);
-  foo(float*);
-  foo(float&);
+  foo(const float*);
+  foo(const float&);
+  foo(void*);
 };
 
 // Good
@@ -25,12 +26,23 @@ foo::foo (bool) : foo(true) { // expected-error{{delegates to itself}}
 }
 
 // Good
-foo::foo (float* f) : foo(*f) {
+foo::foo (const float* f) : foo(*f) {
 }
 
 // FIXME: This should error
-foo::foo (float &f) : foo(&f) {
+foo::foo (const float &f) : foo(&f) {
 }
 
 foo::foo (char) : i(3), foo(3) { // expected-error{{must appear alone}}
 }
+
+// This should not cause an infinite loop
+foo::foo (void*) : foo(4.0f) {
+}
+
+struct deleted_dtor {
+  ~deleted_dtor() = delete; // expected-note{{function has been explicitly marked deleted here}}
+  deleted_dtor();
+  deleted_dtor(int) : deleted_dtor() // expected-error{{attempt to use a deleted function}}
+  {}
+};