[cfe-commits] r149516 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/ScopeInfo.h include/clang/Sema/Sema.h lib/Sema/SemaExprCXX.cpp lib/Sema/SemaLookup.cpp test/SemaCXX/lambda-expressions.cpp
Douglas Gregor
dgregor at apple.com
Wed Feb 1 09:04:21 PST 2012
Author: dgregor
Date: Wed Feb 1 11:04:21 2012
New Revision: 149516
URL: http://llvm.org/viewvc/llvm-project?rev=149516&view=rev
Log:
Introduce the lambda scope before determining explicit captures, which
cleans up and improves a few things:
- We get rid of the ugly dance of computing all of the captures in
data structures that clone those of CapturingScopeInfo, centralizing
the logic for accessing/updating these data structures
- We re-use the existing capture logic for 'this', which actually
works now.
Cleaned up some diagnostic wording in minor ways as well.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/ScopeInfo.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaLookup.cpp
cfe/trunk/test/SemaCXX/lambda-expressions.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=149516&r1=149515&r2=149516&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Feb 1 11:04:21 2012
@@ -4066,8 +4066,8 @@
"%0 in capture list does not name a variable">;
def err_capture_non_automatic_variable : Error<
"%0 cannot be captured because it does not have automatic storage duration">;
-def err_implicit_this_capture : Error<
- "'this' cannot be implicitly captured in this context">;
+def err_this_capture : Error<
+ "'this' cannot be %select{implicitly |}0captured in this context">;
def err_lambda_capture_block : Error<
"__block variable %0 cannot be captured in a lambda">;
Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=149516&r1=149515&r2=149516&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Wed Feb 1 11:04:21 2012
@@ -18,7 +18,6 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/SetVector.h"
namespace clang {
@@ -206,6 +205,34 @@
CXXThisCaptureIndex = Captures.size();
}
+ /// \brief Determine whether the C++ 'this' is captured.
+ bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; }
+
+ /// \brief Retrieve the capture of C++ 'this', if it has been captured.
+ Capture &getCXXThisCapture() {
+ assert(isCXXThisCaptured() && "this has not been captured");
+ return Captures[CXXThisCaptureIndex - 1];
+ }
+
+ /// \brief Determine whether the given variable has been captured.
+ bool isCaptured(VarDecl *Var) const {
+ return CaptureMap.count(Var) > 0;
+ }
+
+ /// \brief Retrieve the capture of the given variable, if it has been
+ /// captured already.
+ Capture &getCapture(VarDecl *Var) {
+ assert(isCaptured(Var) && "Variable has not been captured");
+ return Captures[CaptureMap[Var] - 1];
+ }
+
+ const Capture &getCapture(VarDecl *Var) const {
+ llvm::DenseMap<VarDecl*, unsigned>::const_iterator Known
+ = CaptureMap.find(Var);
+ assert(Known != CaptureMap.end() && "Variable has not been captured");
+ return Captures[Known->second - 1];
+ }
+
static bool classof(const FunctionScopeInfo *FSI) {
return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda;
}
@@ -258,6 +285,11 @@
virtual ~LambdaScopeInfo();
+ /// \brief Note when
+ void finishedExplicitCaptures() {
+ NumExplicitCaptures = Captures.size();
+ }
+
static bool classof(const FunctionScopeInfo *FSI) {
return FSI->Kind == SK_Lambda;
}
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=149516&r1=149515&r2=149516&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Feb 1 11:04:21 2012
@@ -3085,7 +3085,12 @@
/// \brief Make sure the value of 'this' is actually available in the current
/// context, if it is a potentially evaluated context.
- void CheckCXXThisCapture(SourceLocation Loc);
+ ///
+ /// \param Loc The location at which the capture of 'this' occurs.
+ ///
+ /// \param Explicit Whether 'this' is explicitly captured in a lambda
+ /// capture list.
+ void CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false);
/// ActOnCXXBoolLiteral - Parse {true,false} literals.
ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind);
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=149516&r1=149515&r2=149516&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 1 11:04:21 2012
@@ -670,9 +670,9 @@
return ThisTy;
}
-void Sema::CheckCXXThisCapture(SourceLocation Loc) {
+void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) {
// We don't need to capture this in an unevaluated context.
- if (ExprEvalContexts.back().Context == Unevaluated)
+ if (ExprEvalContexts.back().Context == Unevaluated && !Explicit)
return;
// Otherwise, check that we can capture 'this'.
@@ -684,16 +684,19 @@
// 'this' is already being captured; there isn't anything more to do.
break;
}
+
if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref ||
- CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block) {
- // This closure can implicitly capture 'this'; continue looking upwards.
+ CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block ||
+ Explicit) {
+ // This closure can capture 'this'; continue looking upwards.
// FIXME: Is this check correct? The rules in the standard are a bit
// unclear.
NumClosures++;
+ Explicit = false;
continue;
}
// This context can't implicitly capture 'this'; fail out.
- Diag(Loc, diag::err_implicit_this_capture);
+ Diag(Loc, diag::err_this_capture) << Explicit;
return;
}
break;
@@ -4862,20 +4865,90 @@
Class->setLambda(true);
CurContext->addDecl(Class);
- QualType ThisCaptureType;
- llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
- unsigned CXXThisCaptureIndex = 0;
- llvm::SmallVector<LambdaScopeInfo::Capture, 4> Captures;
+ // Build the call operator; we don't really have all the relevant information
+ // at this point, but we need something to attach child declarations to.
+ QualType MethodTy;
+ TypeSourceInfo *MethodTyInfo;
+ if (ParamInfo.getNumTypeObjects() == 0) {
+ // C++11 [expr.prim.lambda]p4:
+ // If a lambda-expression does not include a lambda-declarator, it is as
+ // if the lambda-declarator were ().
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.TypeQuals |= DeclSpec::TQ_const;
+ MethodTy = Context.getFunctionType(Context.DependentTy,
+ /*Args=*/0, /*NumArgs=*/0, EPI);
+ MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
+ } else {
+ assert(ParamInfo.isFunctionDeclarator() &&
+ "lambda-declarator is a function");
+ DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo();
+
+ // C++11 [expr.prim.lambda]p5:
+ // This function call operator is declared const (9.3.1) if and only if
+ // the lambda-expressionâs parameter-declaration-clause is not followed
+ // by mutable. It is neither virtual nor declared volatile.
+ if (!FTI.hasMutableQualifier())
+ FTI.TypeQuals |= DeclSpec::TQ_const;
+ MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
+ // FIXME: Can these asserts actually fail?
+ assert(MethodTyInfo && "no type from lambda-declarator");
+ MethodTy = MethodTyInfo->getType();
+ assert(!MethodTy.isNull() && "no type from lambda declarator");
+ }
+
+ // C++11 [expr.prim.lambda]p5:
+ // The closure type for a lambda-expression has a public inline function
+ // call operator (13.5.4) whose parameters and return type are described by
+ // the lambda-expressionâs parameter-declaration-clause and
+ // trailing-return-type respectively.
+ DeclarationName MethodName
+ = Context.DeclarationNames.getCXXOperatorName(OO_Call);
+ CXXMethodDecl *Method
+ = CXXMethodDecl::Create(Context,
+ Class,
+ ParamInfo.getSourceRange().getEnd(),
+ DeclarationNameInfo(MethodName,
+ /*NameLoc=*/SourceLocation()),
+ MethodTy,
+ MethodTyInfo,
+ /*isStatic=*/false,
+ SC_None,
+ /*isInline=*/true,
+ /*isConstExpr=*/false,
+ ParamInfo.getSourceRange().getEnd());
+ Method->setAccess(AS_public);
+ Class->addDecl(Method);
+ Method->setLexicalDeclContext(DC); // FIXME: Minor hack.
+
+ ProcessDeclAttributes(CurScope, Method, ParamInfo);
+
+ // Enter a new evaluation context to insulate the block from any
+ // cleanups from the enclosing full-expression.
+ PushExpressionEvaluationContext(PotentiallyEvaluated);
+
+ PushDeclContext(CurScope, Method);
+
+ // Introduce the lambda scope.
+ PushLambdaScope(Class);
+ LambdaScopeInfo *LSI = getCurLambda();
+ if (Intro.Default == LCD_ByCopy)
+ LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
+ else if (Intro.Default == LCD_ByRef)
+ LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref;
+
+ // Handle explicit captures.
for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
- C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; ++C) {
+ C = Intro.Captures.begin(),
+ E = Intro.Captures.end();
+ C != E; ++C) {
if (C->Kind == LCK_This) {
// C++11 [expr.prim.lambda]p8:
// An identifier or this shall not appear more than once in a
// lambda-capture.
- if (!ThisCaptureType.isNull()) {
+ if (LSI->isCXXThisCaptured()) {
Diag(C->Loc, diag::err_capture_more_than_once)
<< "'this'"
- << SourceRange(Captures[CXXThisCaptureIndex].getLocation());
+ << SourceRange(LSI->getCXXThisCapture().getLocation());
continue;
}
@@ -4890,19 +4963,13 @@
// C++11 [expr.prim.lambda]p12:
// If this is captured by a local lambda expression, its nearest
// enclosing function shall be a non-static member function.
- ThisCaptureType = getCurrentThisType();
+ QualType ThisCaptureType = getCurrentThisType();
if (ThisCaptureType.isNull()) {
- Diag(C->Loc, diag::err_invalid_this_use);
+ Diag(C->Loc, diag::err_this_capture) << true;
continue;
}
- CheckCXXThisCapture(C->Loc);
-
- // FIXME: Need getCurCapture().
- bool isNested = getCurBlock() || getCurLambda();
- CXXThisCaptureIndex = Captures.size();
- CapturingScopeInfo::Capture Cap(CapturingScopeInfo::Capture::ThisCapture,
- isNested, C->Loc);
- Captures.push_back(Cap);
+
+ CheckCXXThisCapture(C->Loc, /*Explicit=*/true);
continue;
}
@@ -4939,7 +5006,7 @@
// for unqualified name lookup (3.4.1); each such lookup shall find a
// variable with automatic storage duration declared in the reaching
// scope of the local lambda expression.
- // FIXME: Check reaching scope.
+ // FIXME: Check reaching scope.
VarDecl *Var = R.getAsSingle<VarDecl>();
if (!Var) {
Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id;
@@ -4961,119 +5028,44 @@
// C++11 [expr.prim.lambda]p8:
// An identifier or this shall not appear more than once in a
// lambda-capture.
- if (CaptureMap.count(Var)) {
+ if (LSI->isCaptured(Var)) {
Diag(C->Loc, diag::err_capture_more_than_once)
<< C->Id
- << SourceRange(Captures[CaptureMap[Var]].getLocation());
+ << SourceRange(LSI->getCapture(Var).getLocation());
continue;
}
// FIXME: If this is capture by copy, make sure that we can in fact copy
// the variable.
- CaptureMap[Var] = Captures.size();
- Captures.push_back(LambdaScopeInfo::Capture(Var, C->Kind == LCK_ByRef,
- /*isNested*/false, C->Loc, 0));
- }
-
- // Build the call operator; we don't really have all the relevant information
- // at this point, but we need something to attach child declarations to.
- QualType MethodTy;
- TypeSourceInfo *MethodTyInfo;
- if (ParamInfo.getNumTypeObjects() == 0) {
- // C++11 [expr.prim.lambda]p4:
- // If a lambda-expression does not include a lambda-declarator, it is as
- // if the lambda-declarator were ().
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.TypeQuals |= DeclSpec::TQ_const;
- MethodTy = Context.getFunctionType(Context.DependentTy,
- /*Args=*/0, /*NumArgs=*/0, EPI);
- MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
- } else {
- assert(ParamInfo.isFunctionDeclarator() &&
- "lambda-declarator is a function");
- DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo();
-
- // C++11 [expr.prim.lambda]p5:
- // This function call operator is declared const (9.3.1) if and only if
- // the lambda- expressionâs parameter-declaration-clause is not followed
- // by mutable. It is neither virtual nor declared volatile.
- if (!FTI.hasMutableQualifier())
- FTI.TypeQuals |= DeclSpec::TQ_const;
- MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
- // FIXME: Can these asserts actually fail?
- assert(MethodTyInfo && "no type from lambda-declarator");
- MethodTy = MethodTyInfo->getType();
- assert(!MethodTy.isNull() && "no type from lambda declarator");
+ // FIXME: Unify with normal capture path, so we get all of the necessary
+ // nested captures.
+ LSI->AddCapture(Var, C->Kind == LCK_ByRef, /*isNested=*/false, C->Loc, 0);
}
-
- // C++11 [expr.prim.lambda]p5:
- // The closure type for a lambda-expression has a public inline function
- // call operator (13.5.4) whose parameters and return type are described by
- // the lambda-expressionâs parameter-declaration-clause and
- // trailing-return-type respectively.
- DeclarationName MethodName
- = Context.DeclarationNames.getCXXOperatorName(OO_Call);
- CXXMethodDecl *Method
- = CXXMethodDecl::Create(Context,
- Class,
- ParamInfo.getSourceRange().getEnd(),
- DeclarationNameInfo(MethodName,
- /*NameLoc=*/SourceLocation()),
- MethodTy,
- MethodTyInfo,
- /*isStatic=*/false,
- SC_None,
- /*isInline=*/true,
- /*isConstExpr=*/false,
- ParamInfo.getSourceRange().getEnd());
- Method->setAccess(AS_public);
- Class->addDecl(Method);
- Method->setLexicalDeclContext(DC); // FIXME: Is this really correct?
-
- ProcessDeclAttributes(CurScope, Method, ParamInfo);
-
- // Enter a new evaluation context to insulate the block from any
- // cleanups from the enclosing full-expression.
- PushExpressionEvaluationContext(PotentiallyEvaluated);
-
- PushDeclContext(CurScope, Method);
+ LSI->finishedExplicitCaptures();
// Set the parameters on the decl, if specified.
if (isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc())) {
FunctionProtoTypeLoc Proto =
- cast<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc());
+ cast<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc());
Method->setParams(Proto.getParams());
CheckParmsForFunctionDef(Method->param_begin(),
Method->param_end(),
/*CheckParameterNames=*/false);
-
+
// Introduce our parameters into the function scope
for (unsigned p = 0, NumParams = Method->getNumParams(); p < NumParams; ++p) {
ParmVarDecl *Param = Method->getParamDecl(p);
Param->setOwningFunction(Method);
-
+
// If this has an identifier, add it to the scope stack.
if (Param->getIdentifier()) {
CheckShadow(CurScope, Param);
-
+
PushOnScopeChains(Param, CurScope);
}
}
}
- // Introduce the lambda scope.
- PushLambdaScope(Class);
-
- LambdaScopeInfo *LSI = getCurLambda();
- LSI->CXXThisCaptureIndex = CXXThisCaptureIndex;
- std::swap(LSI->CaptureMap, CaptureMap);
- std::swap(LSI->Captures, Captures);
- LSI->NumExplicitCaptures = Captures.size();
- if (Intro.Default == LCD_ByCopy)
- LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
- else if (Intro.Default == LCD_ByRef)
- LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref;
-
const FunctionType *Fn = MethodTy->getAs<FunctionType>();
QualType RetTy = Fn->getResultType();
if (RetTy != Context.DependentTy) {
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=149516&r1=149515&r2=149516&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Wed Feb 1 11:04:21 2012
@@ -32,6 +32,7 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
Modified: cfe/trunk/test/SemaCXX/lambda-expressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/lambda-expressions.cpp?rev=149516&r1=149515&r2=149516&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/lambda-expressions.cpp (original)
+++ cfe/trunk/test/SemaCXX/lambda-expressions.cpp Wed Feb 1 11:04:21 2012
@@ -13,9 +13,9 @@
void ImplicitThisCapture() {
[](){(void)Member;}; // expected-error {{'this' cannot be implicitly captured in this context}} expected-error {{not supported yet}}
[&](){(void)Member;}; // expected-error {{not supported yet}}
- // FIXME: 'this' captures below don't actually work yet
- // FIXME: [this](){(void)Member;};
- // FIXME: [this]{[this]{};};
+ // 'this' captures below don't actually work yet
+ [this](){(void)Member;}; // expected-error{{lambda expressions are not supported yet}}
+ [this]{[this]{};}; // expected-error 2{{lambda expressions are not supported yet}}
[]{[this]{};};// expected-error {{'this' cannot be implicitly captured in this context}} expected-error 2 {{not supported yet}}
[]{Overload(3);}; // expected-error {{not supported yet}}
[]{Overload();}; // expected-error {{'this' cannot be implicitly captured in this context}} expected-error {{not supported yet}}
@@ -25,7 +25,7 @@
};
void f() {
- [this] () {}; // expected-error {{invalid use of 'this'}} expected-error {{not supported yet}}
+ [this] () {}; // expected-error {{'this' cannot be captured in this context}} expected-error {{not supported yet}}
}
}
More information about the cfe-commits
mailing list