[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