From: Steve Naroff Date: Fri, 10 Oct 2008 01:28:17 +0000 (+0000) Subject: Final phase of converting BlockDecls over to DeclContext. This is unfortunately a... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=090276f5e164d491a1bb3f541bafdb394f5e6f04;p=clang Final phase of converting BlockDecls over to DeclContext. This is unfortunately a largish/complex diff, however it was necessry to pass all the current block tests. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@57337 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index bb8c14c408..575daa5d90 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -990,24 +990,30 @@ protected: class BlockDecl : public Decl, public DeclContext { llvm::SmallVector 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::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. diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 1ebd25c65f..b165991c17 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -267,6 +267,8 @@ class DeclContext { static To *CastTo(const From *D) { Decl::Kind DK = KindTrait::getKind(D); switch(DK) { + case Decl::Block: + return static_cast(const_cast(D)); case Decl::TranslationUnit: return static_cast(const_cast(D)); case Decl::Namespace: diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index ee7b7a9389..a3272925b7 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -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. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index fe2e95d157..382b9ebd51 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -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(); - return new (Mem) BlockDecl(DC, L, args, numargs); + return new (Mem) BlockDecl(DC, L); } FieldDecl *FieldDecl::Create(ASTContext &C, SourceLocation L, diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index b42950ffc0..198bc4a19e 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -339,6 +339,8 @@ void Decl::Destroy(ASTContext& C) { DeclContext *DeclContext::getParent() const { if (ScopedDecl *SD = dyn_cast(this)) return SD->getDeclContext(); + else if (BlockDecl *BD = dyn_cast(this)) + return BD->getParentContext(); else return NULL; } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index c8d95cf053..d0f5eb2607 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -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)) { diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 0600ae1424..6ad65e5ba3 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index cdba6ec6ea..a6197dd2b7 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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(VD) || isa(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()) - return new BlockDeclRefExpr(VD, VD->getType(), Loc, true); + if (CurBlock && (CurBlock->TheDecl != VD->getDeclContext()) && + !isa(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()) + 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 BSI(CurBlock); llvm::OwningPtr Body(static_cast(body)); + PopDeclContext(); + // Pop off CurBlock, handle nested blocks. CurBlock = CurBlock->PrevBlockInfo;