]> granicus.if.org Git - clang/commitdiff
Do not use CXXZeroValueInitExpr for class types. Instead, use
authorDouglas Gregor <dgregor@apple.com>
Wed, 7 Jul 2010 22:35:13 +0000 (22:35 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 7 Jul 2010 22:35:13 +0000 (22:35 +0000)
CXXConstructExpr/CXXTemporaryObjectExpr/CXXNewExpr as
appropriate. Fixes PR7556, and provides a slide codegen improvement
when copy-initializing a POD class type from a value-initialized
temporary. Previously, we weren't eliding the copy.

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

include/clang/AST/ExprCXX.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/CodeGen/CGExprCXX.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaStmt.cpp
test/CXX/class.access/p4.cpp
test/CodeGenCXX/default-arg-temps.cpp
test/CodeGenCXX/temporaries.cpp
test/SemaCXX/warn-unused-variables.cpp

index 6da32bacd304e65b2a2d68584c1460a00005437b..7915ab142a8b10a5f8ee551ddb4f2863aa41ea27 100644 (file)
@@ -822,12 +822,8 @@ public:
 ///
 /// This expression type represents a C++ "functional" cast
 /// (C++[expr.type.conv]) with N != 1 arguments that invokes a
-/// constructor to build a temporary object. If N == 0 but no
-/// constructor will be called (because the functional cast is
-/// performing a value-initialized an object whose class type has no
-/// user-declared constructors), CXXZeroInitValueExpr will represent
-/// the functional cast. Finally, with N == 1 arguments the functional
-/// cast expression will be represented by CXXFunctionalCastExpr.
+/// constructor to build a temporary object. With N == 1 arguments the 
+/// functional cast expression will be represented by CXXFunctionalCastExpr.
 /// Example:
 /// @code
 /// struct X { X(int, float); }
@@ -863,8 +859,7 @@ public:
 
 /// CXXZeroInitValueExpr - [C++ 5.2.3p2]
 /// Expression "T()" which creates a value-initialized rvalue of type
-/// T, which is either a non-class type or a class type without any
-/// user-defined constructors.
+/// T, which is a non-class type.
 ///
 class CXXZeroInitValueExpr : public Expr {
   SourceLocation TyBeginLoc;
index f88a0ae66415c6fd8f51cb4e429548d07e3fa3a9..0883eab0034bc16299fcef56622db1b6d40da237 100644 (file)
@@ -509,6 +509,9 @@ def err_access_dtor_vbase :
 def err_access_dtor_temp :
     Error<"temporary of type %0 has %select{private|protected}1 destructor">,
     NoSFINAE;
+def err_access_dtor_exception :
+    Error<"exception object of type %0 has %select{private|protected}1 "
+          "destructor">, NoSFINAE;
 def err_access_dtor_field :
     Error<"field of type %1 has %select{private|protected}2 destructor">,
     NoSFINAE;
index f2e6a11292b7ad053c381419dd27d464b837722b..ea1753bbc17e54c751b4d2dd3017eddb2510ded4 100644 (file)
@@ -572,9 +572,18 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
   }
 
   if (CXXConstructorDecl *Ctor = E->getConstructor()) {
-    CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false, 
-                               NewPtr, E->constructor_arg_begin(),
-                               E->constructor_arg_end());
+    // Per C++ [expr.new]p15, if we have an initializer, then we're performing
+    // direct initialization. C++ [dcl.init]p5 requires that we 
+    // zero-initialize storage if there are no user-declared constructors.
+    if (E->hasInitializer() && 
+        !Ctor->getParent()->hasUserDeclaredConstructor() &&
+        !Ctor->getParent()->isEmpty())
+      CGF.EmitNullInitialization(NewPtr, E->getAllocatedType());
+      
+    if (!Ctor->isTrivial())
+      CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false, 
+                                 NewPtr, E->constructor_arg_begin(),
+                                 E->constructor_arg_end());
 
     return;
   }
index 2c631064efb53aabe3e0e57fbf2f3bfb4a1142ac..3619193434e92c05fae48b3ce5ece1a094675501 100644 (file)
@@ -480,7 +480,7 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
 
   MarkDeclarationReferenced(E->getExprLoc(), Destructor);
   CheckDestructorAccess(E->getExprLoc(), Destructor,
-                        PDiag(diag::err_access_dtor_temp) << Ty);
+                        PDiag(diag::err_access_dtor_exception) << Ty);
   return false;
 }
 
@@ -566,27 +566,19 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
                                                      RParenLoc));
   }
 
-  if (const RecordType *RT = Ty->getAs<RecordType>()) {
-    CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
-
-    if (NumExprs > 1 || !Record->hasTrivialConstructor() ||
-        !Record->hasTrivialDestructor()) {
-      InitializedEntity Entity = InitializedEntity::InitializeTemporary(Ty);
-      InitializationKind Kind
-        = NumExprs ? InitializationKind::CreateDirect(TypeRange.getBegin(), 
-                                                      LParenLoc, RParenLoc)
-                   : InitializationKind::CreateValue(TypeRange.getBegin(), 
-                                                     LParenLoc, RParenLoc);
-      InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs);
-      OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind,
-                                                move(exprs));
-
-      // FIXME: Improve AST representation?
-      return move(Result);
-    }
-
-    // Fall through to value-initialize an object of class type that
-    // doesn't have a user-declared default constructor.
+  if (Ty->isRecordType()) {
+    InitializedEntity Entity = InitializedEntity::InitializeTemporary(Ty);
+    InitializationKind Kind
+      = NumExprs ? InitializationKind::CreateDirect(TypeRange.getBegin(), 
+                                                    LParenLoc, RParenLoc)
+                 : InitializationKind::CreateValue(TypeRange.getBegin(), 
+                                                   LParenLoc, RParenLoc);
+    InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs);
+    OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind,
+                                              move(exprs));
+
+    // FIXME: Improve AST representation?
+    return move(Result);
   }
 
   // C++ [expr.type.conv]p1:
index 536222c37f011ac3d6fda270af58412abefa4698..6b7ff633724c3569896e62a853b92e017b943881 100644 (file)
@@ -2772,8 +2772,7 @@ static void TryValueInitialization(Sema &S,
       //    zero-initialized and, if T’s implicitly-declared default
       //    constructor is non-trivial, that constructor is called.
       if ((ClassDecl->getTagKind() == TTK_Class ||
-           ClassDecl->getTagKind() == TTK_Struct) &&
-          !ClassDecl->hasTrivialConstructor()) {
+           ClassDecl->getTagKind() == TTK_Struct)) {
         Sequence.AddZeroInitializationStep(Entity.getType());
         return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence);        
       }
index 1abcf205dd941fca57b02516c733cd2b38951ebd..9c8f48bfea17276535267ef5b7f611d9321a23b6 100644 (file)
@@ -92,12 +92,6 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
   
   if (const CXXExprWithTemporaries *Temps = dyn_cast<CXXExprWithTemporaries>(E))
     E = Temps->getSubExpr();
-  if (const CXXZeroInitValueExpr *Zero = dyn_cast<CXXZeroInitValueExpr>(E)) {
-    if (const RecordType *RecordT = Zero->getType()->getAs<RecordType>())
-      if (CXXRecordDecl *RecordD = dyn_cast<CXXRecordDecl>(RecordT->getDecl()))
-        if (!RecordD->hasTrivialDestructor())
-          return;
-  }
       
   if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
     if (E->getType()->isVoidType())
index 552c52f977eccd9e7dafcfc7f414d2d6022e996e..90a1449610f31b5c27a2452f426312f604e23c6a 100644 (file)
@@ -423,6 +423,7 @@ namespace test15 {
 
 // PR7281
 namespace test16 {
-  class A { ~A(); }; // expected-note {{declared private here}}
-  void b() { throw A(); } // expected-error{{temporary of type 'test16::A' has private destructor}}
+  class A { ~A(); }; // expected-note 2{{declared private here}}
+  void b() { throw A(); } // expected-error{{temporary of type 'test16::A' has private destructor}} \
+  // expected-error{{exception object of type 'test16::A' has private destructor}}
 }
index e4a06770cd9bb5ae6cf701d0a77d225ea23c0324..c4419850f12d4dfc08468eda355cd7aa0105c158 100644 (file)
@@ -44,7 +44,6 @@ class obj{ int a; float b; double d; };
 // CHECK: define void @_Z1hv()
 void h() {
   // CHECK: call void @llvm.memset.p0i8.i64(
-  // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(
   obj o = obj();
 }
 
index eb543cb5455254f7c12f6fcf1d63e6602bbce482..9a397abfc0cfb65e4e6274959ad1a3e5b1cc83e6 100644 (file)
@@ -320,3 +320,21 @@ namespace UserConvertToValue {
     f(1);
   }
 }
+
+namespace PR7556 {
+  struct A { ~A(); }; 
+  struct B { int i; ~B(); }; 
+  struct C { int C::*pm; ~C(); }; 
+  // CHECK: define void @_ZN6PR75563fooEv()
+  void foo() { 
+    // CHECK: call void @_ZN6PR75561AD1Ev
+    A(); 
+    // CHECK: call void @llvm.memset.p0i8.i64
+    // CHECK: call void @_ZN6PR75561BD1Ev
+    B();
+    // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64
+    // CHECK: call void @_ZN6PR75561CD1Ev
+    C();
+    // CHECK-NEXT: ret void
+  }
+}
index 5ef7e7002f65abbd10720f996a3a71c841258032..6992cdcd0902a73299de5f4f005d3c4d152eef44 100644 (file)
@@ -26,7 +26,7 @@ namespace PR5531 {
   };
 
   void test() {
-    A(); // expected-warning{{expression result unused}}
+    A();
     B(17);
     C();
   }