aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/Sema.cpp12
-rw-r--r--lib/Sema/SemaCodeComplete.cpp2
-rw-r--r--lib/Sema/SemaExpr.cpp1
-rw-r--r--lib/Sema/SemaExprCXX.cpp104
-rw-r--r--lib/Sema/SemaExprMember.cpp3
-rw-r--r--lib/Sema/SemaOverload.cpp1
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);