[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