]> granicus.if.org Git - clang/commitdiff
Fix representation of compound literals for C++ objects with destructors.
authorJordan Rose <jordan_rose@apple.com>
Mon, 6 May 2013 16:48:12 +0000 (16:48 +0000)
committerJordan Rose <jordan_rose@apple.com>
Mon, 6 May 2013 16:48:12 +0000 (16:48 +0000)
Previously, this compound literal expression (a GNU extension in C++):

  (AggregateWithDtor){1, 2}

resulted in this AST:

 `-CXXBindTemporaryExpr [...] 'struct Point' (CXXTemporary [...])
   `-CompoundLiteralExpr [...] 'struct AggregateWithDtor'
     `-CXXBindTemporaryExpr [...] 'struct AggregateWithDtor' (CXXTemporary [...])
       `-InitListExpr [...] 'struct AggregateWithDtor'
         |-IntegerLiteral [...] 'int' 1
         `-IntegerLiteral [...] 'int' 2

Note the two CXXBindTemporaryExprs. The InitListExpr is really part of the
CompoundLiteralExpr, not an object in its own right. By introducing a new
entity initialization kind in Sema specifically for compound literals, we
avoid the treatment of the inner InitListExpr as a temporary.

 `-CXXBindTemporaryExpr [...] 'struct Point' (CXXTemporary [...])
   `-CompoundLiteralExpr [...] 'struct AggregateWithDtor'
     `-InitListExpr [...] 'struct AggregateWithDtor'
       |-IntegerLiteral [...] 'int' 1
       `-IntegerLiteral [...] 'int' 2

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

include/clang/Sema/Initialization.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaInit.cpp
test/SemaCXX/compound-literal.cpp

index 6e72ad3f4ae3c158c01c281eece6465af183ec19..58781ac628c404f796e269615bfb763e0edcb15e 100644 (file)
@@ -75,7 +75,10 @@ public:
     EK_ComplexElement,
     /// \brief The entity being initialized is the field that captures a 
     /// variable in a lambda.
-    EK_LambdaCapture
+    EK_LambdaCapture,
+    /// \brief The entity being initialized is the initializer for a compound
+    /// literal.
+    EK_CompoundLiteralInit
   };
   
 private:
@@ -118,8 +121,8 @@ private:
     /// low bit indicating whether the parameter is "consumed".
     uintptr_t Parameter;
     
-    /// \brief When Kind == EK_Temporary, the type source information for
-    /// the temporary.
+    /// \brief When Kind == EK_Temporary or EK_CompoundLiteralInit, the type
+    /// source information for the temporary.
     TypeSourceInfo *TypeInfo;
 
     struct LN LocAndNRVO;
@@ -287,7 +290,16 @@ public:
                                                    SourceLocation Loc) {
     return InitializedEntity(Var, Field, Loc);
   }
-                                                   
+
+  /// \brief Create the entity for a compound literal initializer.
+  static InitializedEntity InitializeCompoundLiteralInit(TypeSourceInfo *TSI) {
+    InitializedEntity Result(EK_CompoundLiteralInit, SourceLocation(),
+                             TSI->getType());
+    Result.TypeInfo = TSI;
+    return Result;
+  }
+
+
   /// \brief Determine the kind of initialization.
   EntityKind getKind() const { return Kind; }
   
@@ -302,7 +314,7 @@ public:
   /// \brief Retrieve complete type-source information for the object being 
   /// constructed, if known.
   TypeSourceInfo *getTypeSourceInfo() const {
-    if (Kind == EK_Temporary)
+    if (Kind == EK_Temporary || Kind == EK_CompoundLiteralInit)
       return TypeInfo;
     
     return 0;
index 18c1d8fb32b05a1bb514d0095b5c926247a06d9e..0c1065813eb65d01d8bcf89d411e85edb6f2810a 100644 (file)
@@ -4509,7 +4509,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
     return ExprError();
 
   InitializedEntity Entity
-    = InitializedEntity::InitializeTemporary(literalType);
+    = InitializedEntity::InitializeCompoundLiteralInit(TInfo);
   InitializationKind Kind
     = InitializationKind::CreateCStyleCast(LParenLoc, 
                                            SourceRange(LParenLoc, RParenLoc),
index 993e68bd67301cbdbea47e94084a90e92e6a36e9..de93adb6be1c8a85ffebc2ae130c01075f3cf6fd 100644 (file)
@@ -2394,6 +2394,7 @@ DeclarationName InitializedEntity::getName() const {
   case EK_VectorElement:
   case EK_ComplexElement:
   case EK_BlockElement:
+  case EK_CompoundLiteralInit:
     return DeclarationName();
   }
 
@@ -2420,6 +2421,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const {
   case EK_ComplexElement:
   case EK_BlockElement:
   case EK_LambdaCapture:
+  case EK_CompoundLiteralInit:
     return 0;
   }
 
@@ -2437,6 +2439,7 @@ bool InitializedEntity::allowsNRVO() const {
   case EK_Member:
   case EK_New:
   case EK_Temporary:
+  case EK_CompoundLiteralInit:
   case EK_Base:
   case EK_Delegating:
   case EK_ArrayElement:
@@ -4468,6 +4471,7 @@ getAssignmentAction(const InitializedEntity &Entity) {
   case InitializedEntity::EK_ComplexElement:
   case InitializedEntity::EK_BlockElement:
   case InitializedEntity::EK_LambdaCapture:
+  case InitializedEntity::EK_CompoundLiteralInit:
     return Sema::AA_Initializing;
   }
 
@@ -4490,6 +4494,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
   case InitializedEntity::EK_Exception:
   case InitializedEntity::EK_BlockElement:
   case InitializedEntity::EK_LambdaCapture:
+  case InitializedEntity::EK_CompoundLiteralInit:
     return false;
 
   case InitializedEntity::EK_Parameter:
@@ -4520,6 +4525,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
     case InitializedEntity::EK_Temporary:
     case InitializedEntity::EK_ArrayElement:
     case InitializedEntity::EK_Exception:
+    case InitializedEntity::EK_CompoundLiteralInit:
       return true;
   }
 
@@ -4601,6 +4607,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
   case InitializedEntity::EK_VectorElement:
   case InitializedEntity::EK_ComplexElement:
   case InitializedEntity::EK_BlockElement:
+  case InitializedEntity::EK_CompoundLiteralInit:
     return Initializer->getLocStart();
   }
   llvm_unreachable("missed an InitializedEntity kind?");
@@ -4828,6 +4835,31 @@ static bool isReferenceBinding(const InitializationSequence::Step &s) {
          s.Kind == InitializationSequence::SK_BindReferenceToTemporary;
 }
 
+/// Returns true if the parameters describe a constructor initialization of
+/// an explicit temporary object, e.g. "Point(x, y)".
+static bool isExplicitTemporary(const InitializedEntity &Entity,
+                                const InitializationKind &Kind,
+                                unsigned NumArgs) {
+  switch (Entity.getKind()) {
+  case InitializedEntity::EK_Temporary:
+  case InitializedEntity::EK_CompoundLiteralInit:
+    break;
+  default:
+    return false;
+  }
+
+  switch (Kind.getKind()) {
+  case InitializationKind::IK_DirectList:
+    return true;
+  // FIXME: Hack to work around cast weirdness.
+  case InitializationKind::IK_Direct:
+  case InitializationKind::IK_Value:
+    return NumArgs != 1;
+  default:
+    return false;
+  }
+}
+
 static ExprResult
 PerformConstructorInitialization(Sema &S,
                                  const InitializedEntity &Entity,
@@ -4878,11 +4910,7 @@ PerformConstructorInitialization(Sema &S,
     return ExprError();
 
 
-  if (Entity.getKind() == InitializedEntity::EK_Temporary &&
-      (Kind.getKind() == InitializationKind::IK_DirectList ||
-       (NumArgs != 1 && // FIXME: Hack to work around cast weirdness
-        (Kind.getKind() == InitializationKind::IK_Direct ||
-         Kind.getKind() == InitializationKind::IK_Value)))) {
+  if (isExplicitTemporary(Entity, Kind, NumArgs)) {
     // An explicitly-constructed temporary, e.g., X(1, 2).
     S.MarkFunctionReferenced(Loc, Constructor);
     if (S.DiagnoseUseOfDecl(Constructor, Loc))
@@ -4984,6 +5012,7 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {
   case InitializedEntity::EK_Parameter:
   case InitializedEntity::EK_Temporary:
   case InitializedEntity::EK_LambdaCapture:
+  case InitializedEntity::EK_CompoundLiteralInit:
     // The entity being initialized might not outlive the full-expression.
     return false;
   }
index fe0e45d3c6ab186db2c85a3fcdf930b72ee3011a..595747e40ce6ee418659756ceccdc85f416be2b4 100644 (file)
@@ -1,4 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++03 -verify -ast-dump %s > %t-03
+// RUN: FileCheck --input-file=%t-03 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -ast-dump %s > %t-11
+// RUN: FileCheck --input-file=%t-11 %s
+// RUN: FileCheck --input-file=%t-11 %s --check-prefix=CHECK-CXX11
 
 // http://llvm.org/PR7905
 namespace PR7905 {
@@ -12,3 +16,63 @@ void foo2() {
   (void)(M<short> []) {{3}};
 }
 }
+
+// Check compound literals mixed with C++11 list-initialization.
+namespace brace_initializers {
+  struct POD {
+    int x, y;
+  };
+  struct HasCtor {
+    HasCtor(int x, int y);
+  };
+  struct HasDtor {
+    int x, y;
+    ~HasDtor();
+  };
+  struct HasCtorDtor {
+    HasCtorDtor(int x, int y);
+    ~HasCtorDtor();
+  };
+
+  void test() {
+    (void)(POD){1, 2};
+    // CHECK-NOT: CXXBindTemporaryExpr {{.*}} 'struct brace_initializers::POD'
+    // CHECK: CompoundLiteralExpr {{.*}} 'struct brace_initializers::POD'
+    // CHECK-NEXT: InitListExpr {{.*}} 'struct brace_initializers::POD'
+    // CHECK-NEXT: IntegerLiteral {{.*}} 1{{$}}
+    // CHECK-NEXT: IntegerLiteral {{.*}} 2{{$}}
+
+    (void)(HasDtor){1, 2};
+    // CHECK: CXXBindTemporaryExpr {{.*}} 'struct brace_initializers::HasDtor'
+    // CHECK-NEXT: CompoundLiteralExpr {{.*}} 'struct brace_initializers::HasDtor'
+    // CHECK-NEXT: InitListExpr {{.*}} 'struct brace_initializers::HasDtor'
+    // CHECK-NEXT: IntegerLiteral {{.*}} 1{{$}}
+    // CHECK-NEXT: IntegerLiteral {{.*}} 2{{$}}
+
+#if __cplusplus >= 201103L
+    (void)(HasCtor){1, 2};
+    // CHECK-CXX11-NOT: CXXBindTemporaryExpr {{.*}} 'struct brace_initializers::HasCtor'
+    // CHECK-CXX11: CompoundLiteralExpr {{.*}} 'struct brace_initializers::HasCtor'
+    // CHECK-CXX11-NEXT: CXXTemporaryObjectExpr {{.*}} 'struct brace_initializers::HasCtor'
+    // CHECK-CXX11-NEXT: IntegerLiteral {{.*}} 1{{$}}
+    // CHECK-CXX11-NEXT: IntegerLiteral {{.*}} 2{{$}}
+
+    (void)(HasCtorDtor){1, 2};
+    // CHECK-CXX11: CXXBindTemporaryExpr {{.*}} 'struct brace_initializers::HasCtorDtor'
+    // CHECK-CXX11-NEXT: CompoundLiteralExpr {{.*}} 'struct brace_initializers::HasCtorDtor'
+    // CHECK-CXX11-NEXT: CXXTemporaryObjectExpr {{.*}} 'struct brace_initializers::HasCtorDtor'
+    // CHECK-CXX11-NEXT: IntegerLiteral {{.*}} 1{{$}}
+    // CHECK-CXX11-NEXT: IntegerLiteral {{.*}} 2{{$}}
+#endif
+  }
+
+  struct PrivateDtor {
+    int x, y;
+  private:
+    ~PrivateDtor(); // expected-note {{declared private here}}
+  };
+
+  void testPrivateDtor() {
+    (void)(PrivateDtor){1, 2}; // expected-error {{temporary of type 'brace_initializers::PrivateDtor' has private destructor}}
+  }
+}