]> granicus.if.org Git - clang/commitdiff
Correctly destroy reference temporaries with global storage. Remove ErrorUnsupported...
authorAnders Carlsson <andersca@mac.com>
Sun, 27 Jun 2010 17:52:15 +0000 (17:52 +0000)
committerAnders Carlsson <andersca@mac.com>
Sun, 27 Jun 2010 17:52:15 +0000 (17:52 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106983 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGDeclCXX.cpp
lib/CodeGen/CGExpr.cpp
test/CodeGenCXX/references.cpp

index 7fdb895e8edf7f8529f633ed4e9fc09f8cb3da8e..3f4919fbe9c46b69e4dbc68efab221d52418c66e 100644 (file)
@@ -93,13 +93,9 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
     EmitDeclDestroy(*this, D, DeclPtr);
     return;
   }
-  if (Init->isLvalue(getContext()) == Expr::LV_Valid) {
-    RValue RV = EmitReferenceBindingToExpr(Init, &D);
-    EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, T);
-    return;
-  }
-  ErrorUnsupported(Init, 
-                   "global variable that binds reference to a non-lvalue");
+
+  RValue RV = EmitReferenceBindingToExpr(Init, &D);
+  EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, T);
 }
 
 void
@@ -373,11 +369,7 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
 
   if (D.getType()->isReferenceType()) {
     QualType T = D.getType();
-    // We don't want to pass true for IsInitializer here, because a static
-    // reference to a temporary does not extend its lifetime.
-    // FIXME: This is incorrect.
-    RValue RV = EmitReferenceBindingToExpr(D.getInit(),
-                                           /*InitializedDecl=*/0);
+    RValue RV = EmitReferenceBindingToExpr(D.getInit(), &D);
     EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T);
 
   } else
index 0d5369d0d3c180bc8afeb53a9432d94698c8e1c8..2bda5adb42b0819ce87244de0f67f8cee3bebe7b 100644 (file)
@@ -308,9 +308,9 @@ EmitExprForReferenceBinding(CodeGenFunction& CGF, const Expr* E,
           // the object we're binding to.
           QualType T = Adjustment.Field.Field->getType().getNonReferenceType()
                                                         .getUnqualifiedType();
-          Object = CGF.CreateTempAlloca(CGF.ConvertType(T), "lv");
-          LValue TempLV = 
-            LValue::MakeAddr(Object, Qualifiers::fromCVRMask(CVR));
+          Object = CreateReferenceTemporary(CGF, T, InitializedDecl);
+          LValue TempLV = LValue::MakeAddr(Object, 
+                                           Qualifiers::fromCVRMask(CVR));
           CGF.EmitStoreThroughLValue(CGF.EmitLoadOfLValue(LV, T), TempLV, T);
           break;
         }
@@ -348,20 +348,34 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
                                                    ReferenceTemporaryDtor,
                                                    InitializedDecl);
 
+  if (!ReferenceTemporaryDtor)
+    return RValue::get(Value);
+  
   // Make sure to call the destructor for the reference temporary.
-  if (ReferenceTemporaryDtor) {
+  if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl)) {
+    if (VD->hasGlobalStorage()) {
+      llvm::Constant *DtorFn = 
+        CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
+      CGF.EmitCXXGlobalDtorRegistration(DtorFn, 
+                                      cast<llvm::Constant>(ReferenceTemporary));
+      
+      return RValue::get(Value);
+    }
+  }
+  
+  {
     DelayedCleanupBlock Scope(*this);
     EmitCXXDestructorCall(ReferenceTemporaryDtor, Dtor_Complete, 
                           /*ForVirtualBase=*/false, ReferenceTemporary);
             
     // Make sure to jump to the exit block.
     EmitBranch(Scope.getCleanupExitBlock());
+  }
 
-    if (Exceptions) {
-      EHCleanupBlock Cleanup(*this);
-      EmitCXXDestructorCall(ReferenceTemporaryDtor, Dtor_Complete, 
-                            /*ForVirtualBase=*/false, ReferenceTemporary);
-    }
+  if (Exceptions) {
+    EHCleanupBlock Cleanup(*this);
+    EmitCXXDestructorCall(ReferenceTemporaryDtor, Dtor_Complete, 
+                          /*ForVirtualBase=*/false, ReferenceTemporary);
   }
 
   return RValue::get(Value);
index ed0c6f9d2d24f0bae275f97d3ea4391408f30872..d2ad980135538ebf78b37a7fa6f864531ec70606 100644 (file)
@@ -160,7 +160,7 @@ const int &f2() { return 0; }
 namespace N1 {
   const int foo = 1;
   // CHECK: @_ZN2N14test
-  int test(const int& arg = foo) {
+  void test(const int& arg = foo) {
     // Ensure this array is on the stack where we can set values instead of
     // being a global constant.
     // CHECK: %args_array = alloca
@@ -224,3 +224,37 @@ namespace N2 {
     i = 19;    
   }
 }
+
+namespace N3 {
+
+// PR7326
+
+struct A {
+  explicit A(int);
+  ~A();
+};
+
+// CHECK: define internal void @__cxx_global_var_init
+// CHECK: call void @_ZN2N31AC1Ei(%"class.N2::X"* @_ZGRN2N35sA123E, i32 123)
+// CHECK: call i32 @__cxa_atexit
+// CHECK: ret void
+const A &sA123 = A(123);
+}
+
+namespace N4 {
+  
+struct A {
+  A();
+  ~A();
+};
+
+void f() {
+  // CHECK: define void @_ZN2N41fEv
+  // CHECK: call void @_ZN2N41AC1Ev(%"class.N2::X"* @_ZGRZN2N41fEvE2ar)
+  // CHECK: call i32 @__cxa_atexit
+  // CHECK: ret void
+  static const A& ar = A();
+  
+}
+}
+