diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 6 | ||||
-rw-r--r-- | include/clang/Sema/Initialization.h | 45 | ||||
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 11 | ||||
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp | 9 |
6 files changed, 74 insertions, 9 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index d45f87cf36..c6923c6715 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4053,6 +4053,12 @@ let CategoryName = "Lambda Issue" in { def warn_falloff_nonvoid_lambda : Warning< "control reaches end of non-void lambda">, InGroup<ReturnType>; + def err_access_lambda_capture : Error< + // The ERRORs represent other special members that aren't constructors, in + // hopes that someone will bother noticing and reporting if they appear + "capture of variable '%0' as type %1 calls %select{private|protected}3 " + "%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}2constructor">, + AccessControl; } def err_operator_arrow_circular : Error< diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 3d8dfa4d5f..b66c2b4598 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -70,7 +70,10 @@ public: EK_BlockElement, /// \brief The entity being initialized is the real or imaginary part of a /// complex number. - EK_ComplexElement + EK_ComplexElement, + /// \brief The entity being initialized is the field that captures a + /// variable in a lambda. + EK_LambdaCapture }; private: @@ -85,7 +88,7 @@ private: QualType Type; union { - /// \brief When Kind == EK_Variable or EK_Member, the VarDecl or + /// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or /// FieldDecl, respectively. DeclaratorDecl *VariableOrMember; @@ -98,7 +101,7 @@ private: TypeSourceInfo *TypeInfo; struct { - /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the + /// \brief When Kind == EK_Result, EK_Exception, EK_New, the /// location of the 'return', 'throw', or 'new' keyword, /// respectively. When Kind == EK_Temporary, the location where /// the temporary is being created. @@ -118,6 +121,14 @@ private: /// EK_ComplexElement, the index of the array or vector element being /// initialized. unsigned Index; + + struct { + /// \brief The variable being captured by an EK_LambdaCapture. + VarDecl *Var; + + /// \brief The source location at which the capture occurs. + unsigned Location; + } Capture; }; InitializedEntity() { } @@ -147,6 +158,14 @@ private: InitializedEntity(ASTContext &Context, unsigned Index, const InitializedEntity &Parent); + /// \brief Create the initialization entity for a lambda capture. + InitializedEntity(VarDecl *Var, FieldDecl *Field, SourceLocation Loc) + : Kind(EK_LambdaCapture), Parent(0), Type(Field->getType()) + { + Capture.Var = Var; + Capture.Location = Loc.getRawEncoding(); + } + public: /// \brief Create the initialization entity for a variable. static InitializedEntity InitializeVariable(VarDecl *Var) { @@ -246,6 +265,13 @@ public: return InitializedEntity(Context, Index, Parent); } + /// \brief Create the initialization entity for a lambda capture. + static InitializedEntity InitializeLambdaCapture(VarDecl *Var, + FieldDecl *Field, + SourceLocation Loc) { + return InitializedEntity(Var, Field, Loc); + } + /// \brief Determine the kind of initialization. EntityKind getKind() const { return Kind; } @@ -317,6 +343,19 @@ public: EK_ComplexElement); this->Index = Index; } + + /// \brief Retrieve the variable for a captured variable in a lambda. + VarDecl *getCapturedVar() const { + assert(getKind() == EK_LambdaCapture && "Not a lambda capture!"); + return Capture.Var; + } + + /// \brief Determine the location of the capture when initializing + /// field from a captured variable in a lambda. + SourceLocation getCaptureLoc() const { + assert(getKind() == EK_LambdaCapture && "Not a lambda capture!"); + return SourceLocation::getFromRawEncoding(Capture.Location); + } }; /// \brief Describes the kind of initialization being performed, along with diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 03eb4c3142..57d5e43f96 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -1481,6 +1481,13 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, break; } + case InitializedEntity::EK_LambdaCapture: { + const VarDecl *Var = Entity.getCapturedVar(); + PD = PDiag(diag::err_access_lambda_capture); + PD << Var->getName() << Entity.getType() << getSpecialMember(Constructor); + break; + } + } return CheckConstructorAccess(UseLoc, Constructor, Access, PD); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index a11cba1bfb..b05f4d5623 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9625,8 +9625,6 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, // direct-initialized in increasing subscript order.) These // initializations are performed in the (unspecified) order in // which the non-static data members are declared. - // - // FIXME: Introduce an initialization entity for lambda captures. // Introduce a new evaluation context for the initialization, so // that temporaries introduced as part of the capture are retained @@ -9697,7 +9695,8 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, // of array-subscript entities. SmallVector<InitializedEntity, 4> Entities; Entities.reserve(1 + IndexVariables.size()); - Entities.push_back(InitializedEntity::InitializeMember(Field)); + Entities.push_back( + InitializedEntity::InitializeLambdaCapture(Var, Field, Loc)); for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I) Entities.push_back(InitializedEntity::InitializeElement(S.Context, 0, diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index deedff6502..1638693a2c 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2321,6 +2321,9 @@ DeclarationName InitializedEntity::getName() const { case EK_Member: return VariableOrMember->getDeclName(); + case EK_LambdaCapture: + return Capture.Var->getDeclName(); + case EK_Result: case EK_Exception: case EK_New: @@ -2356,6 +2359,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_VectorElement: case EK_ComplexElement: case EK_BlockElement: + case EK_LambdaCapture: return 0; } @@ -2379,6 +2383,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_VectorElement: case EK_ComplexElement: case EK_BlockElement: + case EK_LambdaCapture: break; } @@ -4210,6 +4215,7 @@ getAssignmentAction(const InitializedEntity &Entity) { case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_LambdaCapture: return Sema::AA_Initializing; } @@ -4231,6 +4237,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_Exception: case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_LambdaCapture: return false; case InitializedEntity::EK_Parameter: @@ -4253,6 +4260,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_LambdaCapture: return false; case InitializedEntity::EK_Variable: @@ -4323,6 +4331,9 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity, case InitializedEntity::EK_Variable: return Entity.getDecl()->getLocation(); + case InitializedEntity::EK_LambdaCapture: + return Entity.getCaptureLoc(); + case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_Member: case InitializedEntity::EK_Parameter: diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp index 1f7580eedc..e99130fcd6 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp @@ -4,12 +4,15 @@ template<typename T> void capture(const T&); class NonCopyable { NonCopyable(const NonCopyable&); // expected-note 2 {{implicitly declared private here}} +public: + void foo() const; }; void capture_by_copy(NonCopyable nc, NonCopyable &ncr) { - // FIXME: error messages should talk about capture - (void)[nc] { }; // expected-error{{field of type 'NonCopyable' has private copy constructor}} - (void)[ncr] { }; // expected-error{{field of type 'NonCopyable' has private copy constructor}} + (void)[nc] { }; // expected-error{{capture of variable 'nc' as type 'NonCopyable' calls private copy constructor}} + (void)[=] { + ncr.foo(); // expected-error{{capture of variable 'ncr' as type 'NonCopyable' calls private copy constructor}} + }(); } struct NonTrivial { |