[cfe-commits] r147706 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/ScopeInfo.h lib/Sema/SemaExprCXX.cpp test/SemaCXX/lambda-expressions.cpp
Eli Friedman
eli.friedman at gmail.com
Fri Jan 6 17:08:18 PST 2012
Author: efriedma
Date: Fri Jan 6 19:08:17 2012
New Revision: 147706
URL: http://llvm.org/viewvc/llvm-project?rev=147706&view=rev
Log:
Lambdas: semantic analysis of explicit captures.
This patch (and some of my other commits related to lambdas) is heavily based off of John Freeman's work-in-progress patches.
Added:
cfe/trunk/test/SemaCXX/lambda-expressions.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/ScopeInfo.h
cfe/trunk/lib/Sema/SemaExprCXX.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=147706&r1=147705&r2=147706&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jan 6 19:08:17 2012
@@ -3992,6 +3992,18 @@
"return in the catch of a function try block of a constructor is illegal">;
def err_lambda_unsupported : Error<"lambda expressions are not supported yet">;
+def err_capture_more_than_once : Error<
+ "%0 can appear only once in a capture list">;
+def err_reference_capture_with_reference_default : Error<
+ "'&' cannot precede a capture when the capture default is '&'">;
+def err_this_capture_with_copy_default : Error<
+ "'this' cannot appear in a capture list when the capture default is '='">;
+def err_copy_capture_with_copy_default : Error<
+ "'&' must precede a capture when the capture default is '='">;
+def err_capture_does_not_name_variable : Error<
+ "%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_operator_arrow_circular : Error<
"circular pointer delegation detected">;
Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=147706&r1=147705&r2=147706&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Fri Jan 6 19:08:17 2012
@@ -160,6 +160,29 @@
class LambdaScopeInfo : public FunctionScopeInfo {
public:
+
+ class Capture {
+ llvm::PointerIntPair<VarDecl*, 2, LambdaCaptureKind> InitAndKind;
+
+ public:
+ Capture(VarDecl *Var, LambdaCaptureKind Kind)
+ : InitAndKind(Var, Kind) {}
+
+ enum IsThisCapture { ThisCapture };
+ Capture(IsThisCapture)
+ : InitAndKind(0, LCK_This) {}
+
+ bool isThisCapture() const { return InitAndKind.getInt() == LCK_This; }
+ bool isVariableCapture() const { return !isThisCapture(); }
+ bool isCopyCapture() const { return InitAndKind.getInt() == LCK_ByCopy; }
+ bool isReferenceCapture() const { return InitAndKind.getInt() == LCK_ByRef; }
+
+ VarDecl *getVariable() const {
+ return InitAndKind.getPointer();
+ }
+
+ };
+
/// \brief The class that describes the lambda.
CXXRecordDecl *Lambda;
@@ -169,9 +192,7 @@
/// \brief The list of captured variables, starting with the explicit
/// captures and then finishing with any implicit captures.
- // TODO: This is commented out until an implementation of LambdaExpr is
- // committed.
- // llvm::SmallVector<LambdaExpr::Capture, 4> Captures;
+ llvm::SmallVector<Capture, 4> Captures;
/// \brief The number of captures in the \c Captures list that are
/// explicit captures.
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=147706&r1=147705&r2=147706&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Jan 6 19:08:17 2012
@@ -4793,6 +4793,84 @@
Class->startDefinition();
CurContext->addDecl(Class);
+ // Introduce the lambda scope.
+ PushLambdaScope(Class);
+
+ LambdaScopeInfo *LSI = getCurLambda();
+
+ QualType ThisCaptureType;
+ llvm::DenseMap<const IdentifierInfo*, SourceLocation> CapturesSoFar;
+ for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
+ C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; ++C) {
+ if (C->Kind == LCK_This) {
+ if (!ThisCaptureType.isNull()) {
+ Diag(C->Loc, diag::err_capture_more_than_once) << "'this'";
+ continue;
+ }
+
+ if (Intro.Default == LCD_ByCopy) {
+ Diag(C->Loc, diag::err_this_capture_with_copy_default);
+ continue;
+ }
+
+ ThisCaptureType = getCurrentThisType();
+
+ if (ThisCaptureType.isNull()) {
+ Diag(C->Loc, diag::err_invalid_this_use);
+ continue;
+ }
+ LSI->Captures.push_back(LambdaScopeInfo::Capture::ThisCapture);
+ continue;
+ }
+
+ assert(C->Id && "missing identifier for capture");
+
+ if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) {
+ Diag(C->Loc, diag::err_reference_capture_with_reference_default);
+ continue;
+ } else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
+ Diag(C->Loc, diag::err_copy_capture_with_copy_default);
+ continue;
+ }
+
+ llvm::DenseMap<const IdentifierInfo*, SourceLocation>::iterator Appearance;
+ bool IsFirstAppearance;
+ llvm::tie(Appearance, IsFirstAppearance)
+ = CapturesSoFar.insert(std::make_pair(C->Id, C->Loc));
+
+ if (!IsFirstAppearance) {
+ Diag(C->Loc, diag::err_capture_more_than_once) << C->Id;
+ continue;
+ }
+
+ DeclarationNameInfo Name(C->Id, C->Loc);
+ LookupResult R(*this, Name, LookupOrdinaryName);
+ CXXScopeSpec ScopeSpec;
+ LookupParsedName(R, CurScope, &ScopeSpec);
+ if (R.isAmbiguous())
+ continue;
+ if (R.empty())
+ if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, CTC_Unknown))
+ continue;
+
+ VarDecl *Var = R.getAsSingle<VarDecl>();
+ if (!Var) {
+ Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id;
+ continue;
+ }
+
+ if (!Var->hasLocalStorage()) {
+ Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
+ continue;
+ }
+
+ // FIXME: Actually capturing a variable is much more complicated than this
+ // 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));
+ }
+
// 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;
@@ -4837,17 +4915,12 @@
ProcessDeclAttributes(CurScope, Method, ParamInfo);
- // Introduce the lambda scope.
- PushLambdaScope(Class);
-
// Enter a new evaluation context to insulate the block from any
// cleanups from the enclosing full-expression.
PushExpressionEvaluationContext(PotentiallyEvaluated);
PushDeclContext(CurScope, Method);
- LambdaScopeInfo *LSI = getCurLambda();
-
// Set the parameters on the decl, if specified.
if (isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc())) {
FunctionProtoTypeLoc Proto =
Added: cfe/trunk/test/SemaCXX/lambda-expressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/lambda-expressions.cpp?rev=147706&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/lambda-expressions.cpp (added)
+++ cfe/trunk/test/SemaCXX/lambda-expressions.cpp Fri Jan 6 19:08:17 2012
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+namespace ExplicitCapture {
+ int GlobalVar; // expected-note {{declared here}}
+
+ namespace N {
+ int AmbiguousVar; // expected-note {{candidate}}
+ }
+ int AmbiguousVar; // expected-note {{candidate}}
+ using namespace N;
+
+ class C {
+ int x;
+
+ void f(int);
+ void f() {
+ int foo;
+
+ [foo, foo] () {}; // expected-error {{'foo' can appear only once}} expected-error {{not supported yet}}
+ [this, this] () {}; // expected-error {{'this' can appear only once}} expected-error {{not supported yet}}
+ [=, foo] () {}; // expected-error {{'&' must precede a capture when}} expected-error {{not supported yet}}
+ [=, &foo] () {}; // expected-error {{not supported yet}}
+ [=, this] () {}; // expected-error {{'this' cannot appear}} expected-error {{not supported yet}}
+ [&, foo] () {}; // expected-error {{not supported yet}}
+ [&, &foo] () {}; // expected-error {{'&' cannot precede a capture when}} expected-error {{not supported yet}}
+ [&, this] () {}; // expected-error {{not supported yet}}
+ [&f] () {}; // expected-error {{does not name a variable}} expected-error {{not supported yet}}
+ [&GlobalVar] () {}; // expected-error {{does not have automatic storage duration}} expected-error {{not supported yet}}
+ [&AmbiguousVar] () {} // expected-error {{reference to 'AmbiguousVar' is ambiguous}} expected-error {{not supported yet}}
+ [&Globalvar] () {}; // expected-error {{use of undeclared identifier 'Globalvar'; did you mean 'GlobalVar}}
+ }
+ };
+
+ void f() {
+ [this] () {}; // expected-error {{invalid use of 'this'}} expected-error {{not supported yet}}
+ }
+}
More information about the cfe-commits
mailing list