diff options
author | Jordan Rose <jordan_rose@apple.com> | 2013-05-06 16:48:12 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2013-05-06 16:48:12 +0000 |
commit | 2624b8157660902303bfce5551cfdd38272d01e5 (patch) | |
tree | e189d230f3951bfe2b2dbb923459722a19890959 | |
parent | b8409215523e5478b8b0aa9cdcd10038cf7651fe (diff) |
Fix representation of compound literals for C++ objects with destructors.
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
-rw-r--r-- | include/clang/Sema/Initialization.h | 22 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 39 | ||||
-rw-r--r-- | test/SemaCXX/compound-literal.cpp | 66 |
4 files changed, 117 insertions, 12 deletions
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 6e72ad3f4a..58781ac628 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -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; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 18c1d8fb32..0c1065813e 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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), diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 993e68bd67..de93adb6be 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -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; } diff --git a/test/SemaCXX/compound-literal.cpp b/test/SemaCXX/compound-literal.cpp index fe0e45d3c6..595747e40c 100644 --- a/test/SemaCXX/compound-literal.cpp +++ b/test/SemaCXX/compound-literal.cpp @@ -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}} + } +} |