diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/Sema.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 104 | ||||
-rw-r--r-- | lib/Sema/SemaExprMember.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 1 |
6 files changed, 88 insertions, 35 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 4ab960de0e..72073a1038 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -636,8 +636,16 @@ void Sema::ActOnEndOfTranslationUnit() { DeclContext *Sema::getFunctionLevelDeclContext() { DeclContext *DC = CurContext; - while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) - DC = DC->getParent(); + while (true) { + if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) { + DC = DC->getParent(); + } else if (isa<CXXMethodDecl>(DC) && + cast<CXXRecordDecl>(DC->getParent())->hasDefinition() && + cast<CXXRecordDecl>(DC->getParent())->isLambda()) { + DC = DC->getParent()->getParent(); + } + else break; + } return DC; } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 78e3c355d6..1888d65ad9 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1751,7 +1751,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, case Sema::PCC_Expression: { if (SemaRef.getLangOptions().CPlusPlus) { // 'this', if we're in a non-static member function. - QualType ThisTy = SemaRef.getCurrentThisType(false); + QualType ThisTy = SemaRef.getCurrentThisType(); if (!ThisTy.isNull()) { Builder.AddResultTypeChunk(GetCompletionTypeString(ThisTy, SemaRef.Context, diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 14d3c045ce..f9fb3bc9fc 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1544,6 +1544,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, Diag(R.getNameLoc(), diagnostic) << Name << FixItHint::CreateInsertion(R.getNameLoc(), "this->"); QualType DepThisType = DepMethod->getThisType(Context); + CheckCXXThisCapture(R.getNameLoc()); CXXThisExpr *DepThis = new (Context) CXXThisExpr( R.getNameLoc(), DepThisType, false); TemplateArgumentListInfo TList; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 7c5ad0097f..5e7fb33d05 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -653,22 +653,8 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, return Owned(E); } -QualType Sema::getCurrentThisType(bool Capture) { - // Ignore block scopes: we can capture through them. - // Ignore nested enum scopes: we'll diagnose non-constant expressions - // where they're invalid, and other uses are legitimate. - // Don't ignore nested class scopes: you can't use 'this' in a local class. - DeclContext *DC = CurContext; - unsigned NumBlocks = 0; - while (true) { - if (isa<BlockDecl>(DC)) { - DC = cast<BlockDecl>(DC)->getDeclContext(); - ++NumBlocks; - } else if (isa<EnumDecl>(DC)) - DC = cast<EnumDecl>(DC)->getDeclContext(); - else break; - } - +QualType Sema::getCurrentThisType() { + DeclContext *DC = getFunctionLevelDeclContext(); QualType ThisTy; if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) { if (method && method->isInstance()) @@ -683,17 +669,63 @@ QualType Sema::getCurrentThisType(bool Capture) { ThisTy = Context.getPointerType(Context.getRecordType(RD)); } - if (!Capture || ThisTy.isNull()) - return ThisTy; - - // Mark that we're closing on 'this' in all the block scopes we ignored. - for (unsigned idx = FunctionScopes.size() - 1; - NumBlocks; --idx, --NumBlocks) - cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true; - return ThisTy; } +void Sema::CheckCXXThisCapture(SourceLocation Loc) { + // We don't need to capture this in an unevaluated context. + if (ExprEvalContexts.back().Context == Unevaluated) + return; + + // Otherwise, check that we can capture 'this'. + unsigned NumClosures = 0; + for (unsigned idx = FunctionScopes.size() - 1; idx != 0; idx--) { + if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(FunctionScopes[idx])) { + if (LSI->CapturesCXXThis) { + // This lambda already captures 'this'; there isn't anything more to do. + break; + } + if (LSI->Default == LCD_ByRef) { + // This lambda can implicitly capture 'this'; continue looking upwards. + // FIXME: Is this check correct? The rules in the standard are a bit + // unclear. + NumClosures++; + continue; + } + // This lambda can't implicitly capture 'this'; fail out. + // (We need to delay the diagnostic in the + // PotentiallyPotentiallyEvaluated case because it doesn't apply to + // unevaluated contexts.) + if (ExprEvalContexts.back().Context == PotentiallyPotentiallyEvaluated) + ExprEvalContexts.back() + .addDiagnostic(Loc, PDiag(diag::err_implicit_this_capture)); + else + Diag(Loc, diag::err_implicit_this_capture); + return; + } + if (isa<BlockScopeInfo>(FunctionScopes[idx])) { + NumClosures++; + continue; + } + break; + } + + // Mark that we're implicitly capturing 'this' in all the scopes we skipped. + // FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated + // contexts. + for (unsigned idx = FunctionScopes.size() - 1; + NumClosures; --idx, --NumClosures) { + if (BlockScopeInfo *BSI = dyn_cast<BlockScopeInfo>(FunctionScopes[idx])) { + BSI->CapturesCXXThis = true; + } else { + LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(FunctionScopes[idx]); + assert(LSI && "Unexpected closure"); + LSI->CapturesCXXThis = true; + LSI->Captures.push_back(LambdaScopeInfo::Capture::ThisCapture); + } + } +} + ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { /// C++ 9.3.2: In the body of a non-static member function, the keyword this /// is a non-lvalue expression whose value is the address of the object for @@ -702,6 +734,7 @@ ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { QualType ThisTy = getCurrentThisType(); if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use); + CheckCXXThisCapture(Loc); return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false)); } @@ -4791,14 +4824,11 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, /*IdLoc=*/SourceLocation(), /*Id=*/0); Class->startDefinition(); + Class->setLambda(true); CurContext->addDecl(Class); - // Introduce the lambda scope. - PushLambdaScope(Class); - - LambdaScopeInfo *LSI = getCurLambda(); - QualType ThisCaptureType; + llvm::SmallVector<LambdaScopeInfo::Capture, 4> Captures; llvm::DenseMap<const IdentifierInfo*, SourceLocation> CapturesSoFar; for (llvm::SmallVector<LambdaCapture, 4>::const_iterator C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; ++C) { @@ -4814,12 +4844,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, } ThisCaptureType = getCurrentThisType(); - if (ThisCaptureType.isNull()) { Diag(C->Loc, diag::err_invalid_this_use); continue; } - LSI->Captures.push_back(LambdaScopeInfo::Capture::ThisCapture); + CheckCXXThisCapture(C->Loc); + + Captures.push_back(LambdaScopeInfo::Capture::ThisCapture); continue; } @@ -4868,7 +4899,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // in the general case; see shouldCaptureValueReference. // FIXME: Should we be building a DeclRefExpr here? We don't really need // it until the point where we're actually building the LambdaExpr. - LSI->Captures.push_back(LambdaScopeInfo::Capture(Var, C->Kind)); + Captures.push_back(LambdaScopeInfo::Capture(Var, C->Kind)); } // Build the call operator; we don't really have all the relevant information @@ -4944,6 +4975,15 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, } } + // Introduce the lambda scope. + PushLambdaScope(Class); + + LambdaScopeInfo *LSI = getCurLambda(); + LSI->Default = Intro.Default; + if (!ThisCaptureType.isNull()) + LSI->CapturesCXXThis = true; + std::swap(LSI->Captures, Captures); + const FunctionType *Fn = MethodTy->getAs<FunctionType>(); QualType RetTy = Fn->getResultType(); if (RetTy != Context.DependentTy) { diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index 3e7f8314d5..e05360b87e 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -705,6 +705,7 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, } // Our base object expression is "this". + CheckCXXThisCapture(loc); baseObjectExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true); baseObjectIsPointer = true; @@ -854,6 +855,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, SourceLocation Loc = R.getNameLoc(); if (SS.getRange().isValid()) Loc = SS.getRange().getBegin(); + CheckCXXThisCapture(Loc); BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true); } @@ -1556,6 +1558,7 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation Loc = R.getNameLoc(); if (SS.getRange().isValid()) Loc = SS.getRange().getBegin(); + CheckCXXThisCapture(Loc); baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index ee846c3fc3..be89ed4462 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -10401,6 +10401,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, SourceLocation Loc = MemExpr->getMemberLoc(); if (MemExpr->getQualifier()) Loc = MemExpr->getQualifierLoc().getBeginLoc(); + CheckCXXThisCapture(Loc); Base = new (Context) CXXThisExpr(Loc, MemExpr->getBaseType(), /*isImplicit=*/true); |