]> granicus.if.org Git - clang/commitdiff
More lambda work. Tweak the Sema interface slightly. Start adding the pieces to...
authorEli Friedman <eli.friedman@gmail.com>
Thu, 5 Jan 2012 03:35:19 +0000 (03:35 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Thu, 5 Jan 2012 03:35:19 +0000 (03:35 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147595 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/TypeLoc.h
include/clang/Sema/ScopeInfo.h
include/clang/Sema/Sema.h
lib/Parse/ParseExprCXX.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
test/Parser/objcxx0x-lambda-expressions.mm

index 40a9006b78c5ef733900d317b582135a41636c87..d2fb12b26eeddc2256d9a531674d9e2b873d0551 100644 (file)
@@ -1078,6 +1078,10 @@ public:
     getLocalData()->TrailingReturn = Trailing;
   }
 
+  ArrayRef<ParmVarDecl *> getParams() const {
+    return ArrayRef<ParmVarDecl *>(getParmArray(), getNumArgs());
+  }
+
   // ParmVarDecls* are stored after Info, one for each argument.
   ParmVarDecl **getParmArray() const {
     return (ParmVarDecl**) getExtraLocalData();
index 9ef6d3c4b3d77c3ab8b9ff48e916fb1219c567c1..caa4c1a6c885480ff3f5666b78432286a3fcf34b 100644 (file)
@@ -45,11 +45,17 @@ public:
 /// \brief Retains information about a function, method, or block that is
 /// currently being parsed.
 class FunctionScopeInfo {
+protected:
+  enum ScopeKind {
+    SK_Function,
+    SK_Block,
+    SK_Lambda
+  };
+  
 public:
-
-  /// \brief Whether this scope information structure defined information for
-  /// a block.
-  bool IsBlockInfo;
+  /// \brief What kind of scope we are describing.
+  ///
+  ScopeKind Kind;
 
   /// \brief Whether this function contains a VLA, @try, try, C++
   /// initializer, or anything else that can't be jumped past.
@@ -96,7 +102,7 @@ public:
   }
   
   FunctionScopeInfo(DiagnosticsEngine &Diag)
-    : IsBlockInfo(false),
+    : Kind(SK_Function),
       HasBranchProtectedScope(false),
       HasBranchIntoScope(false),
       HasIndirectGoto(false),
@@ -141,15 +147,55 @@ public:
     : FunctionScopeInfo(Diag), TheDecl(Block), TheScope(BlockScope),
       CapturesCXXThis(false)
   {
-    IsBlockInfo = true;
+    Kind = SK_Block;
   }
 
   virtual ~BlockScopeInfo();
 
-  static bool classof(const FunctionScopeInfo *FSI) { return FSI->IsBlockInfo; }
+  static bool classof(const FunctionScopeInfo *FSI) { 
+    return FSI->Kind == SK_Block; 
+  }
   static bool classof(const BlockScopeInfo *BSI) { return true; }
 };
 
+class LambdaScopeInfo : public FunctionScopeInfo {
+public:
+  /// \brief The class that describes the lambda.
+  CXXRecordDecl *Lambda;
+  
+  /// \brief A mapping from the set of captured variables to the 
+  /// fields (within the lambda class) that represent the captured variables.
+  llvm::DenseMap<VarDecl *, FieldDecl *> CapturedVariables;
+  
+  /// \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;
+  
+  /// \brief The number of captures in the \c Captures list that are 
+  /// explicit captures.
+  unsigned NumExplicitCaptures;
+  
+  /// \brief The field associated with the captured 'this' pointer.
+  FieldDecl *ThisCapture;
+
+  LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda) 
+    : FunctionScopeInfo(Diag), Lambda(Lambda), 
+      NumExplicitCaptures(0), ThisCapture(0) 
+  {
+    Kind = SK_Lambda;
+  }
+    
+  virtual ~LambdaScopeInfo();
+  
+  static bool classof(const FunctionScopeInfo *FSI) { 
+    return FSI->Kind == SK_Lambda; 
+  }
+  static bool classof(const LambdaScopeInfo *BSI) { return true; }
+
+};
+
 }
 }
 
index 940ae2da98982901f55364cb324acfb1d2ced230..7bf2de492c213734fe709d94768c1fefc4ace52b 100644 (file)
@@ -767,8 +767,9 @@ public:
 
   void PushFunctionScope();
   void PushBlockScope(Scope *BlockScope, BlockDecl *Block);
-  void PopFunctionOrBlockScope(const sema::AnalysisBasedWarnings::Policy *WP =0,
-                               const Decl *D = 0, const BlockExpr *blkExpr = 0);
+  void PushLambdaScope(CXXRecordDecl *Lambda);
+  void PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP =0,
+                            const Decl *D = 0, const BlockExpr *blkExpr = 0);
 
   sema::FunctionScopeInfo *getCurFunction() const {
     return FunctionScopes.back();
@@ -3449,16 +3450,15 @@ public:
   /// initializer for the declaration 'Dcl'.
   void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl);
 
-  /// ActOnLambdaStart - This callback is invoked when a lambda expression is
-  /// started.
-  void ActOnLambdaStart(SourceLocation StartLoc, Scope *CurScope);
-
-  /// ActOnLambdaArguments - This callback allows processing of lambda arguments.
-  /// If there are no arguments, this is still invoked.
-  void ActOnLambdaArguments(Declarator &ParamInfo, Scope *CurScope);
+  /// ActOnStartOfLambdaDefinition - This is called just before we start
+  /// parsing the body of a lambda; it analyzes the explicit captures and 
+  /// arguments, and sets up various data-structures for the body of the
+  /// lambda.
+  void ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
+                                    Declarator &ParamInfo, Scope *CurScope);
 
   /// ActOnLambdaError - If there is an error parsing a lambda, this callback
-  /// is invoked to pop the information about the lambda from the action impl.
+  /// is invoked to pop the information about the lambda.
   void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope);
 
   /// ActOnLambdaExpr - This is called when the body of a lambda expression
index 96f8709ba56c6bef3b39a5374e20dbd84c13d0bd..e54858f747134989e7f74ae858b3da67a34b69d8 100644 (file)
@@ -711,8 +711,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
   PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc,
                                 "lambda expression parsing");
 
-  Actions.ActOnLambdaStart(LambdaBeginLoc, getCurScope());
-
   // Parse lambda-declarator[opt].
   DeclSpec DS(AttrFactory);
   Declarator D(DS, Declarator::LambdaExprContext);
@@ -792,11 +790,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
                                            DeclLoc, DeclEndLoc, D,
                                            TrailingReturnType),
                   Attr, DeclEndLoc);
-
-    // Inform sema that we are starting a block.
-    Actions.ActOnLambdaArguments(D, getCurScope());
   }
 
+  Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope());
+
   // Parse compound-statement.
   if (!Tok.is(tok::l_brace)) {
     Diag(Tok, diag::err_expected_lambda_body);
index c8199042b723a436526ea04341b2b4ef6449cdc9..6a77d8c673b885ba0ba52fd3aa93a9fbcaab0970 100644 (file)
@@ -55,6 +55,7 @@ void FunctionScopeInfo::Clear() {
 }
 
 BlockScopeInfo::~BlockScopeInfo() { }
+LambdaScopeInfo::~LambdaScopeInfo() { }
 
 PrintingPolicy Sema::getPrintingPolicy() const {
   PrintingPolicy Policy = Context.getPrintingPolicy();
@@ -828,8 +829,12 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
                                               BlockScope, Block));
 }
 
-void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP,
-                                   const Decl *D, const BlockExpr *blkExpr) {
+void Sema::PushLambdaScope(CXXRecordDecl *Lambda) {
+  FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics(), Lambda));
+}
+
+void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
+                                const Decl *D, const BlockExpr *blkExpr) {
   FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();  
   assert(!FunctionScopes.empty() && "mismatched push/pop!");
   
index f82026f89f98373ca46a5c86d0391d62c8ea14fd..8353c087d5b47302cb4bbd61a3edc897776ef037 100644 (file)
@@ -7207,7 +7207,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
   if (!IsInstantiation)
     PopDeclContext();
 
-  PopFunctionOrBlockScope(ActivePolicy, dcl);
+  PopFunctionScopeInfo(ActivePolicy, dcl);
   
   // If any errors have occurred, clear out any temporaries that may have
   // been leftover. This ensures that these temporaries won't be picked up for
index ad327ac755e326bdc210aaf5a6ca7766ed8648e1..46a47a22157b59e4c9439b91fe4a4179466e6877 100644 (file)
@@ -6784,7 +6784,7 @@ namespace {
     
     ~ImplicitlyDefinedFunctionScope() {
       S.PopExpressionEvaluationContext();
-      S.PopFunctionOrBlockScope();
+      S.PopFunctionScopeInfo();
     }
   };
 }
index 126468ee352b13824aebedf2f21449ba0d004aa2..8554e78636310dbb3766fab089f661dc88e38a8f 100644 (file)
@@ -8839,7 +8839,7 @@ void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
 
   // Pop off CurBlock, handle nested blocks.
   PopDeclContext();
-  PopFunctionOrBlockScope();
+  PopFunctionScopeInfo();
 }
 
 /// ActOnBlockStmtExpr - This is called when the body of a block statement
@@ -8931,7 +8931,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
   
   BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
   const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy();
-  PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result);
+  PopFunctionScopeInfo(&WP, Result->getBlockDecl(), Result);
 
   // If the block isn't obviously global, i.e. it captures anything at
   // all, mark this full-expression as needing a cleanup.
index e53e5cda621656b470d51fe53b95ce9930fb89fc..fd47dc75b21e7beeb1486e9806c61a70322a2dac 100644 (file)
@@ -4778,20 +4778,68 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc,
 // Lambdas.
 //===----------------------------------------------------------------------===//
 
-void Sema::ActOnLambdaStart(SourceLocation StartLoc, Scope *CurScope) {
-  // FIXME: Add lambda-scope
-  // FIXME: PushDeclContext
+void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
+                                        Declarator &ParamInfo,
+                                        Scope *CurScope) {
+  DeclContext *DC = CurContext;
+  while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isNamespace()))
+    DC = DC->getParent();
+
+  // Start constructing the lambda class.
+  CXXRecordDecl *Class = CXXRecordDecl::Create(Context, TTK_Class, DC,
+                                               Intro.Range.getBegin(),
+                                               /*IdLoc=*/SourceLocation(),
+                                               /*Id=*/0);
+  Class->startDefinition();
+  CurContext->addDecl(Class);
+
+  // 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.
+  TypeSourceInfo *MethodTyInfo;
+  MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
+
+  DeclarationName MethodName
+    = Context.DeclarationNames.getCXXOperatorName(OO_Call);
+  CXXMethodDecl *Method
+    = CXXMethodDecl::Create(Context,
+                            Class,
+                            ParamInfo.getSourceRange().getEnd(),
+                            DeclarationNameInfo(MethodName,
+                                                /*NameLoc=*/SourceLocation()),
+                            MethodTyInfo->getType(),
+                            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?
+
+  // Set the parameters on the decl, if specified.
+  if (isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc())) {
+    FunctionProtoTypeLoc Proto =
+        cast<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc());
+    Method->setParams(Proto.getParams());
+    CheckParmsForFunctionDef(Method->param_begin(),
+                             Method->param_end(),
+                             /*CheckParameterNames=*/false);
+  }
+
+  ProcessDeclAttributes(CurScope, Method, ParamInfo);
+
+  // FIXME: There's a bunch of missing checking etc;
+  // see ActOnBlockArguments
+
+  // 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);  
-}
-
-void Sema::ActOnLambdaArguments(Declarator &ParamInfo, Scope *CurScope) {
-  TypeSourceInfo *MethodTyInfo;
-  MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
+  PushExpressionEvaluationContext(PotentiallyEvaluated);
 
-  // FIXME: Build CXXMethodDecl
+  PushDeclContext(CurScope, Method);
 }
 
 void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) {
@@ -4800,8 +4848,8 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) {
   PopExpressionEvaluationContext();
 
   // Leave the context of the lambda.
-  // FIXME: PopDeclContext
-  // FIXME: Pop lambda-scope
+  PopDeclContext();
+  PopFunctionScopeInfo();
 }
 
 ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
index b9a96d6b2df2b0e1b164bbdd28cb5ed4e3525240..5cfb4f8c5a7cbf7b3d3c738801426fe246054bdd 100644 (file)
@@ -14,10 +14,7 @@ class C {
     [] {}; // expected-error {{lambda expressions are not supported yet}}
     [=] (int i) {}; // expected-error {{lambda expressions are not supported yet}}
     [&] (int) mutable -> void {}; // expected-error {{lambda expressions are not supported yet}}
-    // FIXME: this error occurs because we do not yet handle lambda scopes
-    // properly. I did not anticipate it because I thought it was a semantic (not
-    // syntactic) check.
-    [foo,bar] () { return 3; }; // expected-error {{void function 'f' should not return a value}} expected-error {{lambda expressions are not supported yet}}
+    [foo,bar] () { return 3; }; // expected-error {{lambda expressions are not supported yet}}
     [=,&foo] () {}; // expected-error {{lambda expressions are not supported yet}}
     [this] () {}; // expected-error {{lambda expressions are not supported yet}}
   }