]> granicus.if.org Git - clang/commitdiff
Final phase of converting BlockDecls over to DeclContext. This is unfortunately a...
authorSteve Naroff <snaroff@apple.com>
Fri, 10 Oct 2008 01:28:17 +0000 (01:28 +0000)
committerSteve Naroff <snaroff@apple.com>
Fri, 10 Oct 2008 01:28:17 +0000 (01:28 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@57337 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
include/clang/AST/DeclBase.h
include/clang/Parse/Action.h
lib/AST/Decl.cpp
lib/AST/DeclBase.cpp
lib/Parse/ParseExpr.cpp
lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp

index bb8c14c40880442de46c2b929c4a01e6f72459db..575daa5d90aada836f7a17443cef973dd9b5218d 100644 (file)
@@ -990,24 +990,30 @@ protected:
 class BlockDecl : public Decl, public DeclContext {
   llvm::SmallVector<ParmVarDecl*, 8> Args;
   Stmt *Body;
+  
+  // Since BlockDecl's aren't named/scoped, we need to store the context.
+  DeclContext *ParentContext;
 protected:
-  BlockDecl(DeclContext *DC, SourceLocation CaretLoc,
-            ParmVarDecl **args, unsigned numargs)
-    : Decl(Block, CaretLoc), DeclContext(Block), 
-      Args(args, args+numargs), Body(0) {}
+  BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
+    : Decl(Block, CaretLoc), DeclContext(Block), Body(0), ParentContext(DC) {}
 
   virtual ~BlockDecl();
   virtual void Destroy(ASTContext& C);
 
 public:
-  static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
-                           ParmVarDecl **args, unsigned numargs);
+  static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
 
   SourceLocation getCaretLocation() const { return getLocation(); }
 
   Stmt *getBody() const { return Body; }
   void setBody(Stmt *B) { Body = B; }
 
+  void setArgs(ParmVarDecl **args, unsigned numargs) {
+    Args.clear(); 
+    Args.insert(Args.begin(), args, args+numargs);
+  }
+  DeclContext *getParentContext() { return ParentContext; }
+  
   /// arg_iterator - Iterate over the ParmVarDecl's for this block.
   typedef llvm::SmallVector<ParmVarDecl*, 8>::const_iterator param_iterator;
   bool param_empty() const { return Args.empty(); }
@@ -1016,7 +1022,7 @@ public:
     
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return D->getKind() == Block; }
-  static bool classof(const TranslationUnitDecl *D) { return true; }  
+  static bool classof(const BlockDecl *D) { return true; }  
 
 protected:
   /// EmitImpl - Serialize this BlockDecl. Called by Decl::Emit.
index 1ebd25c65f402cfeaf0470cadb560b66ffd81d3d..b165991c172c3cb9b8bdaf5cdf6c84ae80d805bc 100644 (file)
@@ -267,6 +267,8 @@ class DeclContext {
   static To *CastTo(const From *D) {
     Decl::Kind DK = KindTrait<From>::getKind(D);
     switch(DK) {
+      case Decl::Block:
+        return static_cast<BlockDecl*>(const_cast<From*>(D));
       case Decl::TranslationUnit:
         return static_cast<TranslationUnitDecl*>(const_cast<From*>(D));
       case Decl::Namespace:
index ee7b7a938975054b9a1eef2fa2576ad71525bfeb..a3272925b796bc04b1f651ebbb8f6ef9c1ea8b69 100644 (file)
@@ -538,8 +538,11 @@ public:
 
   /// ActOnBlockStart - This callback is invoked when a block literal is
   /// started.  The result pointer is passed into the block finalizers.
-  virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope,
-                               Declarator &ParamInfo) {}
+  virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {}
+
+  /// ActOnBlockArguments - This callback allows processing of block arguments.
+  /// If there are no arguments, this is still invoked.
+  virtual void ActOnBlockArguments(Declarator &ParamInfo) {}
   
   /// ActOnBlockError - If there is an error parsing a block, this callback
   /// is invoked to pop the information about the block from the action impl.
index fe2e95d157939354978d102b4406c0c2b540126d..382b9ebd512f6e23c2fab7857a262afe66e7c248 100644 (file)
@@ -76,10 +76,9 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
                                 TypeSpecStartLoc);
 }
 
-BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, 
-                             ParmVarDecl **args, unsigned numargs) {
+BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
   void *Mem = C.getAllocator().Allocate<BlockDecl>();
-  return new (Mem) BlockDecl(DC, L, args, numargs);
+  return new (Mem) BlockDecl(DC, L);
 }
 
 FieldDecl *FieldDecl::Create(ASTContext &C, SourceLocation L,
index b42950ffc0b4fcc49b046bf3ca656b90631606b2..198bc4a19eca6e78314473efdd53a46a2db45ccc 100644 (file)
@@ -339,6 +339,8 @@ void Decl::Destroy(ASTContext& C) {
 DeclContext *DeclContext::getParent() const {
   if (ScopedDecl *SD = dyn_cast<ScopedDecl>(this))
     return SD->getDeclContext();
+  else if (BlockDecl *BD = dyn_cast<BlockDecl>(this))
+    return BD->getParentContext();
   else
     return NULL;
 }
index c8d95cf053c8830172e084844e2ede7aea3b3328..d0f5eb2607662f2dfec7a19c3538f3d86248d738 100644 (file)
@@ -1094,6 +1094,9 @@ Parser::ExprResult Parser::ParseBlockLiteralExpression() {
   // within or outside of the block.
   EnterScope(Scope::BlockScope|Scope::FnScope|Scope::BreakScope|
              Scope::ContinueScope|Scope::DeclScope);
+
+  // Inform sema that we are starting a block.
+  Actions.ActOnBlockStart(CaretLoc, CurScope);
   
   // Parse the return type if present.
   DeclSpec DS;
@@ -1119,7 +1122,7 @@ Parser::ExprResult Parser::ParseBlockLiteralExpression() {
   }
 
   // Inform sema that we are starting a block.
-  Actions.ActOnBlockStart(CaretLoc, CurScope, ParamInfo);
+  Actions.ActOnBlockArguments(ParamInfo);
   
   ExprResult Result = true;
   if (Tok.is(tok::l_brace)) {
index 0600ae142433ce223dfc18c7121d5dfcd5645dce..6ad65e5ba3ab1ba6850abfa4eecf6d7aebc8506d 100644 (file)
@@ -575,8 +575,11 @@ public:
 
   /// ActOnBlockStart - This callback is invoked when a block literal is
   /// started.
-  virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope,
-                               Declarator &ParamInfo);
+  virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope);
+  
+  /// ActOnBlockArguments - This callback allows processing of block arguments.
+  /// If there are no arguments, this is still invoked.
+  virtual void ActOnBlockArguments(Declarator &ParamInfo);
   
   /// ActOnBlockError - If there is an error parsing a block, this callback
   /// is invoked to pop the information about the block from the action impl.
index cdba6ec6ea6c91c76635a70ba964c816e791a263..a6197dd2b75edf3e777a08c791dea16cf9ebb460 100644 (file)
@@ -309,34 +309,6 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
                            StringToks[NumStringToks-1].getLocation());
 }
 
-/// DeclDefinedWithinScope - Return true if the specified decl is defined at or
-/// within the 'Within' scope.  The current Scope is CurScope.
-///
-/// FIXME: This method is extremely inefficient (linear scan), this should not
-/// be used in common cases. Replace with the more modern DeclContext. We need
-/// to make sure both assignments below produce an error.
-///
-/// int main(int argc) {
-///   int xx;
-///   ^(int X) {
-///     xx = 4; // error (variable is not assignable)
-///     argc = 3; // no error.
-///   };
-/// }
-///
-static bool DeclDefinedWithinScope(ScopedDecl *D, Scope *Within,
-                                   Scope *CurScope) {
-  while (1) {
-    assert(CurScope && "CurScope not nested within 'Within'?");
-
-    // Check this scope for the decl.
-    if (CurScope->isDeclScope(D)) return true;
-    
-    if (CurScope == Within) return false;
-    CurScope = CurScope->getParent();
-  }
-}
-
 /// ActOnIdentifierExpr - The parser read an identifier in expression context,
 /// validate it per-C99 6.5.1.  HasTrailingLParen indicates whether this
 /// identifier is used in a function call context.
@@ -373,17 +345,6 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
       return new PredefinedExpr(Loc, T, PredefinedExpr::ObjCSuper);
     }
   }
-  // If we are parsing a block, check the block parameter list.
-  if (CurBlock) {
-    BlockSemaInfo *BLK = CurBlock;
-    do {
-      for (unsigned i = 0, e = BLK->Params.size(); i != e && D == 0; ++i)
-        if (BLK->Params[i]->getIdentifier() == &II)
-          D = BLK->Params[i];
-      if (D) 
-        break; // Found!
-    } while ((BLK = BLK->PrevBlockInfo));  // Look through any enclosing blocks.
-  }
   if (D == 0) {
     // Otherwise, this could be an implicitly declared function reference (legal
     // in C90, extension in C99).
@@ -437,27 +398,26 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
   if (VD->isInvalidDecl())
     return true;
     
-  // If this reference is not in a block or if the referenced variable is
-  // within the block, create a normal DeclRefExpr.
-  //
   // FIXME: This will create BlockDeclRefExprs for global variables,
   // function references, etc which is suboptimal :) and breaks
   // things like "integer constant expression" tests.
   //
-  if (!CurBlock || DeclDefinedWithinScope(VD, CurBlock->TheScope, S) ||
-      isa<EnumConstantDecl>(VD) || isa<ParmVarDecl>(VD))
-    return new DeclRefExpr(VD, VD->getType(), Loc);
-  
-  // If we are in a block and the variable is outside the current block,
-  // bind the variable reference with a BlockDeclRefExpr.
-  
-  // The BlocksAttr indicates the variable is bound by-reference.
-  if (VD->getAttr<BlocksAttr>())
-    return new BlockDeclRefExpr(VD, VD->getType(), Loc, true);
+  if (CurBlock && (CurBlock->TheDecl != VD->getDeclContext()) &&
+      !isa<EnumConstantDecl>(VD)) {
+    // If we are in a block and the variable is outside the current block,
+    // bind the variable reference with a BlockDeclRefExpr.
     
-  // Variable will be bound by-copy, make it const within the closure.
-  VD->getType().addConst();
-  return new BlockDeclRefExpr(VD, VD->getType(), Loc, false);
+    // The BlocksAttr indicates the variable is bound by-reference.
+    if (VD->getAttr<BlocksAttr>())
+      return new BlockDeclRefExpr(VD, VD->getType(), Loc, true);
+      
+    // Variable will be bound by-copy, make it const within the closure.
+    VD->getType().addConst();
+    return new BlockDeclRefExpr(VD, VD->getType(), Loc, false);
+  }
+  // If this reference is not in a block or if the referenced variable is
+  // within the block, create a normal DeclRefExpr.
+  return new DeclRefExpr(VD, VD->getType(), Loc);
 }
 
 Sema::ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
@@ -2856,8 +2816,7 @@ Sema::ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond,
 //===----------------------------------------------------------------------===//
 
 /// ActOnBlockStart - This callback is invoked when a block literal is started.
-void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope,
-                           Declarator &ParamInfo) {
+void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
   // Analyze block parameters.
   BlockSemaInfo *BSI = new BlockSemaInfo();
   
@@ -2868,13 +2827,18 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope,
   BSI->ReturnType = 0;
   BSI->TheScope = BlockScope;
   
+  BSI->TheDecl = BlockDecl::Create(Context, CurContext, CaretLoc);
+  PushDeclContext(BSI->TheDecl);
+}
+
+void Sema::ActOnBlockArguments(Declarator &ParamInfo) {
   // Analyze arguments to block.
   assert(ParamInfo.getTypeObject(0).Kind == DeclaratorChunk::Function &&
          "Not a function declarator!");
   DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getTypeObject(0).Fun;
   
-  BSI->hasPrototype = FTI.hasPrototype;
-  BSI->isVariadic = true;
+  CurBlock->hasPrototype = FTI.hasPrototype;
+  CurBlock->isVariadic = true;
   
   // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs function that takes
   // no arguments, not a function that takes a single void argument.
@@ -2883,14 +2847,19 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope,
       (!((ParmVarDecl *)FTI.ArgInfo[0].Param)->getType().getCVRQualifiers() &&
         ((ParmVarDecl *)FTI.ArgInfo[0].Param)->getType()->isVoidType())) {
     // empty arg list, don't push any params.
-    BSI->isVariadic = false;
+    CurBlock->isVariadic = false;
   } else if (FTI.hasPrototype) {
     for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
-      BSI->Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
-    BSI->isVariadic = FTI.isVariadic;
+      CurBlock->Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
+    CurBlock->isVariadic = FTI.isVariadic;
   }
-  BSI->TheDecl = BlockDecl::Create(Context, CurContext, CaretLoc,
-                                   &BSI->Params[0], BSI->Params.size());
+  CurBlock->TheDecl->setArgs(&CurBlock->Params[0], CurBlock->Params.size());
+  
+  for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(),
+       E = CurBlock->TheDecl->param_end(); AI != E; ++AI)
+    // If this has an identifier, add it to the scope stack.
+    if ((*AI)->getIdentifier())
+      PushOnScopeChains(*AI, CurBlock->TheScope);
 }
 
 /// ActOnBlockError - If there is an error parsing a block, this callback
@@ -2914,6 +2883,8 @@ Sema::ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, StmtTy *body,
   llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock);
   llvm::OwningPtr<CompoundStmt> Body(static_cast<CompoundStmt*>(body));
 
+  PopDeclContext();
+
   // Pop off CurBlock, handle nested blocks.
   CurBlock = CurBlock->PrevBlockInfo;