Index: README.txt =================================================================== --- README.txt +++ README.txt @@ -24,3 +24,5 @@ If you find a bug in Clang, please file it in the LLVM bug tracker: http://llvm.org/bugs/ + +use llvm svn-revision 262784 \ No newline at end of file Index: include/clang/AST/LambdaCapture.h =================================================================== --- include/clang/AST/LambdaCapture.h +++ include/clang/AST/LambdaCapture.h @@ -35,11 +35,10 @@ /// This includes the case of a non-reference init-capture. Capture_ByCopy = 0x02 }; - llvm::PointerIntPair DeclAndBits; SourceLocation Loc; SourceLocation EllipsisLoc; - + bool IsStarThis : 1; friend class ASTStmtReader; friend class ASTStmtWriter; @@ -69,8 +68,12 @@ /// \brief Determine whether this capture handles the C++ \c this /// pointer. bool capturesThis() const { - return (DeclAndBits.getPointer() == nullptr) && - !(DeclAndBits.getInt() & Capture_ByCopy); + return ((DeclAndBits.getPointer() == nullptr) && + !(DeclAndBits.getInt() & Capture_ByCopy)) + || IsStarThis; + } + bool capturesStarThis() const { + return capturesThis() && IsStarThis; } /// \brief Determine whether this capture handles a variable. Index: include/clang/Basic/Lambda.h =================================================================== --- include/clang/Basic/Lambda.h +++ include/clang/Basic/Lambda.h @@ -33,6 +33,7 @@ /// is an expression. enum LambdaCaptureKind { LCK_This, ///< Capturing the \c this pointer + LCK_StarThis, /// < Capturing the \c *this object by value LCK_ByCopy, ///< Capturing by copy (a.k.a., by value) LCK_ByRef, ///< Capturing by reference LCK_VLAType ///< Capturing variable-length array type Index: include/clang/Sema/ScopeInfo.h =================================================================== --- include/clang/Sema/ScopeInfo.h +++ include/clang/Sema/ScopeInfo.h @@ -414,7 +414,7 @@ enum CaptureKind { Cap_ByCopy, Cap_ByRef, Cap_Block, Cap_This }; - + bool IsStarThis = false; /// The variable being captured (if we are not capturing 'this') and whether /// this is a nested capture. llvm::PointerIntPair VarAndNested; @@ -446,20 +446,25 @@ enum IsThisCapture { ThisCapture }; Capture(IsThisCapture, bool IsNested, SourceLocation Loc, - QualType CaptureType, Expr *Cpy) + QualType CaptureType, Expr *Cpy, const bool ByCopy) : VarAndNested(nullptr, IsNested), InitExprAndCaptureKind(Cpy, Cap_This), - Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {} + Loc(Loc), EllipsisLoc(), CaptureType(CaptureType), + IsStarThis(ByCopy) {} bool isThisCapture() const { return InitExprAndCaptureKind.getInt() == Cap_This; } + bool isStarThisCapture() const { + return IsStarThis; + } bool isVariableCapture() const { - return InitExprAndCaptureKind.getInt() != Cap_This && !isVLATypeCapture(); + return !isThisCapture() && !isVLATypeCapture(); } bool isCopyCapture() const { - return InitExprAndCaptureKind.getInt() == Cap_ByCopy && - !isVLATypeCapture(); + return (InitExprAndCaptureKind.getInt() == Cap_ByCopy && + !isVLATypeCapture()) || + IsStarThis; } bool isReferenceCapture() const { return InitExprAndCaptureKind.getInt() == Cap_ByRef; @@ -534,7 +539,7 @@ } void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType, - Expr *Cpy); + Expr *Cpy, bool ByCopy); /// \brief Determine whether the C++ 'this' is captured. bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; } @@ -854,9 +859,10 @@ inline void CapturingScopeInfo::addThisCapture(bool isNested, SourceLocation Loc, - QualType CaptureType, Expr *Cpy) { + QualType CaptureType, Expr *Cpy, + const bool ByCopy) { Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType, - Cpy)); + Cpy, ByCopy)); CXXThisCaptureIndex = Captures.size(); } Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -4619,7 +4619,8 @@ /// \return returns 'true' if failed, 'false' if success. bool CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false, bool BuildAndDiagnose = true, - const unsigned *const FunctionScopeIndexToStopAt = nullptr); + const unsigned *const FunctionScopeIndexToStopAt = nullptr, + bool ByCopy = false); /// \brief Determine whether the given type is the type of *this that is used /// outside of the body of a member function for a type that is currently Index: lib/AST/ExprCXX.cpp =================================================================== --- lib/AST/ExprCXX.cpp +++ lib/AST/ExprCXX.cpp @@ -882,17 +882,19 @@ LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit, LambdaCaptureKind Kind, VarDecl *Var, SourceLocation EllipsisLoc) - : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) + : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc), IsStarThis(false) { unsigned Bits = 0; if (Implicit) Bits |= Capture_Implicit; switch (Kind) { + case LCK_StarThis: + IsStarThis = true; case LCK_This: assert(!Var && "'this' capture cannot have a variable!"); break; - + case LCK_ByCopy: Bits |= Capture_ByCopy; // Fall through @@ -909,9 +911,11 @@ LambdaCaptureKind LambdaCapture::getCaptureKind() const { Decl *D = DeclAndBits.getPointer(); - bool CapByCopy = DeclAndBits.getInt() & Capture_ByCopy; + unsigned Bits = DeclAndBits.getInt(); + bool CapByCopy = Bits & Capture_ByCopy; if (!D) - return CapByCopy ? LCK_VLAType : LCK_This; + return CapByCopy ? LCK_VLAType + : (IsStarThis ? LCK_StarThis : LCK_This); return CapByCopy ? LCK_ByCopy : LCK_ByRef; } Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -2008,7 +2008,9 @@ case LCK_This: OS << "this"; break; - + case LCK_StarThis: + OS << "*this"; + break; case LCK_ByRef: if (Node->getCaptureDefault() != LCD_ByRef || Node->isInitCapture(C)) OS << '&'; Index: lib/AST/StmtProfile.cpp =================================================================== --- lib/AST/StmtProfile.cpp +++ lib/AST/StmtProfile.cpp @@ -1257,6 +1257,7 @@ C != CEnd; ++C) { ID.AddInteger(C->getCaptureKind()); switch (C->getCaptureKind()) { + case LCK_StarThis: case LCK_This: break; case LCK_ByRef: Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -826,9 +826,16 @@ LambdaThisCaptureField); if (LambdaThisCaptureField) { // If this lambda captures this, load it. - LValue ThisLValue = EmitLValueForLambdaField(LambdaThisCaptureField); - CXXThisValue = EmitLoadOfLValue(ThisLValue, + if (!LambdaThisCaptureField->getType()->isPointerType()) { + QualType LambdaTagType = getContext().getTagDeclType(LambdaThisCaptureField->getParent()); + LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue, LambdaTagType); + LValue ThisLValue = EmitLValueForField(LambdaLV, LambdaThisCaptureField); + CXXThisValue = ThisLValue.getAddress().getPointer(); + } else { + LValue ThisLValue = EmitLValueForLambdaField(LambdaThisCaptureField); + CXXThisValue = EmitLoadOfLValue(ThisLValue, SourceLocation()).getScalarVal(); + } } for (auto *FD : MD->getParent()->fields()) { if (FD->hasCapturedVLAType()) { Index: lib/Parse/ParseExprCXX.cpp =================================================================== --- lib/Parse/ParseExprCXX.cpp +++ lib/Parse/ParseExprCXX.cpp @@ -846,8 +846,13 @@ IdentifierInfo *Id = nullptr; SourceLocation EllipsisLoc; ExprResult Init; - - if (Tok.is(tok::kw_this)) { + + if (Tok.is(tok::star) && NextToken().is(tok::kw_this)) { + Kind = LCK_StarThis; + // FIXME: We should store our location for '*' for better diagnostic messages; + ConsumeToken(); // Consume '*' + Loc = ConsumeToken(); + } else if (Tok.is(tok::kw_this)) { Kind = LCK_This; Loc = ConsumeToken(); } else { Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10990,7 +10990,8 @@ } else if (C.capturesThis()) { LSI->addThisCapture(/*Nested*/ false, C.getLocation(), - S.getCurrentThisType(), /*Expr*/ nullptr); + S.getCurrentThisType(), /*Expr*/ nullptr, + !I->getType()->isPointerType()); } else { LSI->addVLATypeCapture(C.getLocation(), I->getType()); } Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -13253,7 +13253,7 @@ /// \brief Create a field within the lambda class for the variable /// being captured. -static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI, VarDecl *Var, +static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI, VarDecl *, QualType FieldType, QualType DeclRefType, SourceLocation Loc, bool RefersToCapturedVariable) { Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -849,7 +849,21 @@ cast(CurContext->getParent()->getParent())); // There are no cv-qualifiers for 'this' within default initializers, // per [expr.prim.general]p4. - return Context.getPointerType(ClassTy); + ThisTy = Context.getPointerType(ClassTy); + } + } + // Add const for '* this' capture if not mutable. + if (isLambdaCallOperator(CurContext)) { + LambdaScopeInfo *LSI = getCurLambda(); + assert(LSI); + if (LSI->isCXXThisCaptured()) { + auto C = LSI->getCXXThisCapture(); + QualType BaseType = ThisTy->getPointeeType(); + if (C.isStarThisCapture() && LSI->CallOperator->isConst() && + !BaseType.isConstQualified()) { + BaseType.addConst(); + ThisTy = Context.getPointerType(BaseType); + } } } return ThisTy; @@ -884,20 +898,37 @@ } } -static Expr *captureThis(ASTContext &Context, RecordDecl *RD, - QualType ThisTy, SourceLocation Loc) { +static Expr *captureThis(Sema &S, ASTContext &Context, RecordDecl *RD, + QualType ThisTy, SourceLocation Loc, + const bool ByCopy) { + QualType CaptureThisTy = ByCopy ? ThisTy->getPointeeType() : ThisTy; + FieldDecl *Field - = FieldDecl::Create(Context, RD, Loc, Loc, nullptr, ThisTy, - Context.getTrivialTypeSourceInfo(ThisTy, Loc), + = FieldDecl::Create(Context, RD, Loc, Loc, nullptr, CaptureThisTy, + Context.getTrivialTypeSourceInfo(CaptureThisTy, Loc), nullptr, false, ICIS_NoInit); Field->setImplicit(true); Field->setAccess(AS_private); RD->addDecl(Field); - return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/true); + Expr *This = new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/true); + if (ByCopy) { + Expr *StarThis = S.CreateBuiltinUnaryOp(Loc, + UO_Deref, + This).get(); + InitializedEntity Entity = InitializedEntity::InitializeLambdaCapture( + &S.Context.Idents.get("*this"), CaptureThisTy, Loc); + InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc); + InitializationSequence Init(S, Entity, InitKind, StarThis); + ExprResult ER = Init.Perform(S, Entity, InitKind, StarThis); + if (ER.isInvalid()) return nullptr; + return ER.get(); + } + return This; } bool Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit, - bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt) { + bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt, + const bool ByCopy) { // We don't need to capture this in an unevaluated context. if (isUnevaluatedContext() && !Explicit) return true; @@ -948,13 +979,15 @@ QualType ThisTy = getCurrentThisType(); if (LambdaScopeInfo *LSI = dyn_cast(CSI)) // For lambda expressions, build a field and an initializing expression. - ThisExpr = captureThis(Context, LSI->Lambda, ThisTy, Loc); + ThisExpr = captureThis(*this, Context, LSI->Lambda, ThisTy, Loc, ByCopy); else if (CapturedRegionScopeInfo *RSI = dyn_cast(FunctionScopes[idx])) - ThisExpr = captureThis(Context, RSI->TheRecordDecl, ThisTy, Loc); + ThisExpr = + captureThis(*this, Context, RSI->TheRecordDecl, ThisTy, Loc, + false/*ByCopy*/); bool isNested = NumClosures > 1; - CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr); + CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr, ByCopy); } return false; } @@ -968,6 +1001,7 @@ if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use); CheckCXXThisCapture(Loc); + return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false); } Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -924,7 +924,7 @@ = Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc; for (auto C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; PrevCaptureLoc = C->Loc, ++C) { - if (C->Kind == LCK_This) { + if (C->Kind == LCK_This || C->Kind == LCK_StarThis) { // C++11 [expr.prim.lambda]p8: // An identifier or this shall not appear more than once in a // lambda-capture. @@ -935,11 +935,11 @@ SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc)); continue; } - + // FIXME: Fix this comment from the wording for lambda '*this' wording. // C++11 [expr.prim.lambda]p8: // If a lambda-capture includes a capture-default that is =, the // lambda-capture shall not contain this [...]. - if (Intro.Default == LCD_ByCopy) { + if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis) { Diag(C->Loc, diag::err_this_capture_with_copy_default) << FixItHint::CreateRemoval( SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc)); @@ -955,7 +955,9 @@ continue; } - CheckCXXThisCapture(C->Loc, /*Explicit=*/true); + CheckCXXThisCapture(C->Loc, /*Explicit=*/true, /*BuildAndDiagnose*/ true, + /*FunctionScopeIndexToStopAtPtr*/ nullptr, + C->Kind == LCK_StarThis); continue; } @@ -1529,10 +1531,9 @@ // Handle 'this' capture. if (From.isThisCapture()) { Captures.push_back( - LambdaCapture(From.getLocation(), IsImplicit, LCK_This)); - CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(), - getCurrentThisType(), - /*isImplicit=*/true)); + LambdaCapture(From.getLocation(), IsImplicit, + From.isStarThisCapture() ? LCK_StarThis : LCK_This)); + CaptureInits.push_back(From.getInitExpr()); ArrayIndexStarts.push_back(ArrayIndexVars.size()); continue; } Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -10060,7 +10060,9 @@ // Capturing 'this' is trivial. if (C->capturesThis()) { - getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit()); + getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit(), + /*BuildAndDiagnose*/ true, nullptr, + C->capturesStarThis()); continue; } // Captured expression will be recaptured during captured variables Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -1497,10 +1497,12 @@ bool IsImplicit = Record[Idx++]; LambdaCaptureKind Kind = static_cast(Record[Idx++]); switch (Kind) { + case LCK_StarThis: case LCK_This: case LCK_VLAType: *ToCapture++ = Capture(Loc, IsImplicit, Kind, nullptr,SourceLocation()); break; + case LCK_ByCopy: case LCK_ByRef: VarDecl *Var = ReadDeclAs(Record, Idx); Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -5631,6 +5631,7 @@ Record.push_back(Capture.isImplicit()); Record.push_back(Capture.getCaptureKind()); switch (Capture.getCaptureKind()) { + case LCK_StarThis: case LCK_This: case LCK_VLAType: break; Index: test/CodeGenCXX/cxx1z-lambda-star-this.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/cxx1z-lambda-star-this.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -std=c++1y -triple i686-pc-windows-msvc -emit-llvm %s -o - | FileCheck %s +//CHECK: %[[A_LAMBDA:.*]] = type { %struct.A } +//CHECK: %[[B_LAMBDA:.*]] = type { %struct.B* } +struct A { + double a = 111; + auto foo() { return [*this] { return a; }; } +}; + +namespace ns1 { +int X = A{}.foo()(); +} //end ns1 + +//CHECK: @"\01?foo@A@@QAE?A?@@XZ"(%struct.A* %this, %class.anon* noalias sret %[[A_LAMBDA_RETVAL:.*]]) +// get the first object with the closure type, which is of type 'struct.A' +//CHECK: %0 = getelementptr inbounds %[[A_LAMBDA]], %[[A_LAMBDA]]* %[[A_LAMBDA_RETVAL]], i32 0, i32 0 +//CHECK: %1 = bitcast %struct.A* %0 to i8* +//CHECK: %2 = bitcast %struct.A* %this1 to i8* +// copy the contents ... +//CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %1, i8* %2, i32 8, i32 8, i1 false) + +struct B { + double b = 222; + auto bar() { return [this] { return b; }; }; +}; + +namespace ns2 { +int X = B{}.bar()(); +} +//CHECK: @"\01?bar@B@@QAE?A?@@XZ"(%struct.B* %this, %class.anon.0* noalias sret %agg.result) +//CHECK: %0 = getelementptr inbounds %class.anon.0, %class.anon.0* %agg.result, i32 0, i32 0 +//CHECK: store %struct.B* %this1, %struct.B** %0, align 4 \ No newline at end of file Index: test/SemaCXX/cxx1z-lambda-star-this.cpp =================================================================== --- /dev/null +++ test/SemaCXX/cxx1z-lambda-star-this.cpp @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -emit-llvm-only %s +// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS +// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING + + +namespace test_star_this { +namespace ns1 { +class A { + int x = 345; + auto foo() { + (void) [*this, this] { }; //expected-error{{'this' can appear only once}} + (void) [this] { ++x; }; + (void) [*this] { ++x; }; //expected-error{{read-only variable}} + (void) [*this] () mutable { ++x; }; + (void) [=] { return x; }; + (void) [&, this] { return x; }; + (void) [=, *this] { return x; }; + (void) [&, *this] { return x; }; + } +}; +} // end ns1 + +namespace ns2 { + class B { + B(const B&) = delete; //expected-note{{deleted here}} + int *x = (int *) 456; + void foo() { + (void)[this] { return x; }; + (void)[*this] { return x; }; //expected-error{{call to deleted}} + } + }; +} // end ns2 +namespace ns3 { + class B { + B(const B&) = delete; //expected-note2{{deleted here}} + + int *x = (int *) 456; + public: + template + void foo() { + (void)[this] { return x; }; + (void)[*this] { return x; }; //expected-error2{{call to deleted}} + } + + B() = default; + } b; + B *c = (b.foo(), nullptr); //expected-note{{in instantiation}} +} // end ns3 + +namespace ns4 { +template +class B { + B(const B&) = delete; //expected-note{{deleted here}} + double d = 3.14; + public: + template + auto foo() { + const auto &L = [*this] (auto a) mutable { //expected-error{{call to deleted}} + d += a; + return [this] (auto b) { return d +=b; }; + }; + } + + B() = default; +}; +void main() { + B b; + b.foo(); //expected-note{{in instantiation}} +} // end main +} // end ns4 +} //end ns test_star_this