- Add BlockDecl AST node.

- Modify BlockExpr to reference the BlockDecl.

This is "cleanup" necessary to improve our lookup semantics for blocks (to fix <rdar://problem/6272905> clang block rewriter: parameter to function not imported into block?).

Still some follow-up work to finish this (forthcoming).

llvm-svn: 57298
This commit is contained in:
Steve Naroff 2008-10-08 17:01:13 +00:00
parent d83529e8c4
commit 415d3d570a
11 changed files with 145 additions and 48 deletions

View File

@ -364,9 +364,11 @@ std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i,
std::string S = "static " + RT.getAsString() + " __" + std::string S = "static " + RT.getAsString() + " __" +
funcName + "_" + "block_func_" + utostr(i); funcName + "_" + "block_func_" + utostr(i);
BlockDecl *BD = CE->getBlockDecl();
if (isa<FunctionTypeNoProto>(AFT)) { if (isa<FunctionTypeNoProto>(AFT)) {
S += "()"; S += "()";
} else if (CE->arg_empty()) { } else if (BD->param_empty()) {
S += "(" + StructRef + " *__cself)"; S += "(" + StructRef + " *__cself)";
} else { } else {
const FunctionTypeProto *FT = cast<FunctionTypeProto>(AFT); const FunctionTypeProto *FT = cast<FunctionTypeProto>(AFT);
@ -375,15 +377,15 @@ std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i,
// first add the implicit argument. // first add the implicit argument.
S += StructRef + " *__cself, "; S += StructRef + " *__cself, ";
std::string ParamStr; std::string ParamStr;
for (BlockExpr::arg_iterator AI = CE->arg_begin(), for (BlockDecl::param_iterator AI = BD->param_begin(),
E = CE->arg_end(); AI != E; ++AI) { E = BD->param_end(); AI != E; ++AI) {
if (AI != CE->arg_begin()) S += ", "; if (AI != BD->param_begin()) S += ", ";
ParamStr = (*AI)->getName(); ParamStr = (*AI)->getName();
(*AI)->getType().getAsStringInternal(ParamStr); (*AI)->getType().getAsStringInternal(ParamStr);
S += ParamStr; S += ParamStr;
} }
if (FT->isVariadic()) { if (FT->isVariadic()) {
if (!CE->arg_empty()) S += ", "; if (!BD->param_empty()) S += ", ";
S += "..."; S += "...";
} }
S += ')'; S += ')';

View File

@ -16,10 +16,12 @@
#include "clang/AST/DeclBase.h" #include "clang/AST/DeclBase.h"
#include "clang/Parse/AccessSpecifier.h" #include "clang/Parse/AccessSpecifier.h"
#include "llvm/ADT/SmallVector.h"
namespace clang { namespace clang {
class Expr; class Expr;
class Stmt; class Stmt;
class CompoundStmt;
class StringLiteral; class StringLiteral;
class IdentifierInfo; class IdentifierInfo;
@ -981,6 +983,51 @@ protected:
void ReadInRec(llvm::Deserializer& D, ASTContext& C); void ReadInRec(llvm::Deserializer& D, ASTContext& C);
}; };
} // end namespace clang /// BlockDecl - This represents a block literal declaration, which is like an
/// unnamed FunctionDecl. For example:
/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body }
///
class BlockDecl : public Decl, public DeclContext {
llvm::SmallVector<ParmVarDecl*, 8> Args;
Stmt *Body;
protected:
BlockDecl(DeclContext *DC, SourceLocation CaretLoc,
ParmVarDecl **args, unsigned numargs, Stmt *body)
: Decl(Block, CaretLoc), DeclContext(Block),
Args(args, args+numargs), Body(body) {}
virtual ~BlockDecl();
virtual void Destroy(ASTContext& C);
public:
static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
ParmVarDecl **args, unsigned numargs,
CompoundStmt *body);
SourceLocation getCaretLocation() const { return getLocation(); }
Stmt *getBody() const { return Body; }
/// 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(); }
param_iterator param_begin() const { return Args.begin(); }
param_iterator param_end() const { return Args.end(); }
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return D->getKind() == Block; }
static bool classof(const TranslationUnitDecl *D) { return true; }
protected:
/// EmitImpl - Serialize this BlockDecl. Called by Decl::Emit.
virtual void EmitImpl(llvm::Serializer& S) const;
/// CreateImpl - Deserialize a BlockDecl. Called by Decl::Create.
static BlockDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
};
} // end namespace clang
#endif #endif

View File

@ -27,6 +27,7 @@ class CXXRecordDecl;
class EnumDecl; class EnumDecl;
class ObjCMethodDecl; class ObjCMethodDecl;
class ObjCInterfaceDecl; class ObjCInterfaceDecl;
class BlockDecl;
/// Decl - This represents one declaration (or definition), e.g. a variable, /// Decl - This represents one declaration (or definition), e.g. a variable,
/// typedef, function, struct, etc. /// typedef, function, struct, etc.
@ -81,6 +82,7 @@ public:
ObjCPropertyImpl, ObjCPropertyImpl,
LinkageSpec, LinkageSpec,
FileScopeAsm, FileScopeAsm,
Block, // [DeclContext]
// For each non-leaf class, we now define a mapping to the first/last member // For each non-leaf class, we now define a mapping to the first/last member
// of the class, to allow efficient classof. // of the class, to allow efficient classof.
@ -243,6 +245,7 @@ protected:
/// EnumDecl /// EnumDecl
/// ObjCMethodDecl /// ObjCMethodDecl
/// ObjCInterfaceDecl /// ObjCInterfaceDecl
/// BlockDecl
/// ///
class DeclContext { class DeclContext {
/// DeclKind - This indicates which class this is. /// DeclKind - This indicates which class this is.
@ -295,6 +298,7 @@ public:
bool isFunctionOrMethod() const { bool isFunctionOrMethod() const {
switch (DeclKind) { switch (DeclKind) {
case Decl::Block:
case Decl::Function: case Decl::Function:
case Decl::CXXMethod: case Decl::CXXMethod:
case Decl::ObjCMethod: case Decl::ObjCMethod:
@ -320,6 +324,7 @@ public:
case Decl::Enum: case Decl::Enum:
case Decl::ObjCMethod: case Decl::ObjCMethod:
case Decl::ObjCInterface: case Decl::ObjCInterface:
case Decl::Block:
return true; return true;
default: default:
if (D->getKind() >= Decl::FunctionFirst && if (D->getKind() >= Decl::FunctionFirst &&
@ -339,6 +344,7 @@ public:
static bool classof(const EnumDecl *D) { return true; } static bool classof(const EnumDecl *D) { return true; }
static bool classof(const ObjCMethodDecl *D) { return true; } static bool classof(const ObjCMethodDecl *D) { return true; }
static bool classof(const ObjCInterfaceDecl *D) { return true; } static bool classof(const ObjCInterfaceDecl *D) { return true; }
static bool classof(const BlockDecl *D) { return true; }
private: private:
void EmitOutRec(llvm::Serializer& S) const; void EmitOutRec(llvm::Serializer& S) const;

View File

@ -28,6 +28,7 @@ namespace clang {
class IdentifierInfo; class IdentifierInfo;
class ParmVarDecl; class ParmVarDecl;
class ValueDecl; class ValueDecl;
class BlockDecl;
/// Expr - This represents one expression. Note that Expr's are subclasses of /// Expr - This represents one expression. Note that Expr's are subclasses of
/// Stmt. This allows an expression to be transparently used any place a Stmt /// Stmt. This allows an expression to be transparently used any place a Stmt
@ -1498,36 +1499,29 @@ public:
}; };
/// BlockExpr - Represent a block literal with a syntax: /// BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } /// ^{ statement-body } or ^(int arg1, float arg2){ statement-body }
class BlockExpr : public Expr { class BlockExpr : public Expr {
SourceLocation CaretLocation; protected:
llvm::SmallVector<ParmVarDecl*, 8> Args; BlockDecl *TheBlock;
Stmt *Body;
public: public:
BlockExpr(SourceLocation caretloc, QualType ty, ParmVarDecl **args, BlockExpr(BlockDecl *BD, QualType ty) : Expr(BlockExprClass, ty),
unsigned numargs, CompoundStmt *body) : Expr(BlockExprClass, ty), TheBlock(BD) {}
CaretLocation(caretloc), Args(args, args+numargs), Body(body) {}
SourceLocation getCaretLocation() const { return CaretLocation; } BlockDecl *getBlockDecl() { return TheBlock; }
// Convenience functions for probing the underlying BlockDecl.
SourceLocation getCaretLocation() const;
const Stmt *getBody() const;
Stmt *getBody();
virtual SourceRange getSourceRange() const {
return SourceRange(getCaretLocation(), getBody()->getLocEnd());
}
/// getFunctionType - Return the underlying function type for this block. /// getFunctionType - Return the underlying function type for this block.
const FunctionType *getFunctionType() const; const FunctionType *getFunctionType() const;
const CompoundStmt *getBody() const { return cast<CompoundStmt>(Body); }
CompoundStmt *getBody() { return cast<CompoundStmt>(Body); }
virtual SourceRange getSourceRange() const {
return SourceRange(getCaretLocation(), Body->getLocEnd());
}
/// arg_iterator - Iterate over the ParmVarDecl's for the arguments to this
/// block.
typedef llvm::SmallVector<ParmVarDecl*, 8>::const_iterator arg_iterator;
bool arg_empty() const { return Args.empty(); }
arg_iterator arg_begin() const { return Args.begin(); }
arg_iterator arg_end() const { return Args.end(); }
static bool classof(const Stmt *T) { static bool classof(const Stmt *T) {
return T->getStmtClass() == BlockExprClass; return T->getStmtClass() == BlockExprClass;
} }
@ -1536,7 +1530,7 @@ public:
// Iterators // Iterators
virtual child_iterator child_begin(); virtual child_iterator child_begin();
virtual child_iterator child_end(); virtual child_iterator child_end();
virtual void EmitImpl(llvm::Serializer& S) const; virtual void EmitImpl(llvm::Serializer& S) const;
static BlockExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C); static BlockExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
}; };

View File

@ -76,6 +76,13 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
TypeSpecStartLoc); TypeSpecStartLoc);
} }
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
ParmVarDecl **args, unsigned numargs,
CompoundStmt *body) {
void *Mem = C.getAllocator().Allocate<BlockDecl>();
return new (Mem) BlockDecl(DC, L, args, numargs, body);
}
FieldDecl *FieldDecl::Create(ASTContext &C, SourceLocation L, FieldDecl *FieldDecl::Create(ASTContext &C, SourceLocation L,
IdentifierInfo *Id, QualType T, Expr *BW) { IdentifierInfo *Id, QualType T, Expr *BW) {
void *Mem = C.getAllocator().Allocate<FieldDecl>(); void *Mem = C.getAllocator().Allocate<FieldDecl>();
@ -285,3 +292,20 @@ FieldDecl *RecordDecl::getMember(IdentifierInfo *II) {
return Members[i]; return Members[i];
return 0; return 0;
} }
//===----------------------------------------------------------------------===//
// BlockDecl Implementation
//===----------------------------------------------------------------------===//
BlockDecl::~BlockDecl() {
}
void BlockDecl::Destroy(ASTContext& C) {
if (Body)
Body->Destroy(C);
for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I)
(*I)->Destroy(C);
Decl::Destroy(C);
}

View File

@ -49,6 +49,7 @@ static unsigned nObjCPropertyDecl = 0;
static unsigned nObjCPropertyImplDecl = 0; static unsigned nObjCPropertyImplDecl = 0;
static unsigned nLinkageSpecDecl = 0; static unsigned nLinkageSpecDecl = 0;
static unsigned nFileScopeAsmDecl = 0; static unsigned nFileScopeAsmDecl = 0;
static unsigned nBlockDecls = 0;
static bool StatSwitch = false; static bool StatSwitch = false;
@ -77,6 +78,7 @@ const char *Decl::getDeclKindName() const {
case Union: return "Union"; case Union: return "Union";
case Class: return "Class"; case Class: return "Class";
case Enum: return "Enum"; case Enum: return "Enum";
case Block: return "Block";
} }
} }
@ -221,6 +223,7 @@ void Decl::addDeclKind(Kind k) {
case ObjCPropertyImpl: nObjCPropertyImplDecl++; break; case ObjCPropertyImpl: nObjCPropertyImplDecl++; break;
case LinkageSpec: nLinkageSpecDecl++; break; case LinkageSpec: nLinkageSpecDecl++; break;
case FileScopeAsm: nFileScopeAsmDecl++; break; case FileScopeAsm: nFileScopeAsmDecl++; break;
case Block: nBlockDecls++; break;
case ImplicitParam: case ImplicitParam:
case TranslationUnit: break; case TranslationUnit: break;

View File

@ -441,6 +441,22 @@ FunctionDecl* FunctionDecl::CreateImpl(Deserializer& D, ASTContext& C) {
return decl; return decl;
} }
void BlockDecl::EmitImpl(Serializer& S) const {
// FIXME: what about arguments?
S.Emit(getCaretLocation());
S.EmitOwnedPtr(Body);
}
BlockDecl* BlockDecl::CreateImpl(Deserializer& D, ASTContext& C) {
QualType Q = QualType::ReadVal(D);
SourceLocation L = SourceLocation::ReadVal(D);
/*CompoundStmt* BodyStmt = cast<CompoundStmt>(*/D.ReadOwnedPtr<Stmt>(C)/*)*/;
assert(0 && "Cannot deserialize BlockBlockExpr yet");
// FIXME: need to handle parameters.
//return new BlockBlockExpr(L, Q, BodyStmt);
return 0;
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// RecordDecl Serialization. // RecordDecl Serialization.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -217,6 +217,13 @@ const FunctionType *BlockExpr::getFunctionType() const {
getPointeeType()->getAsFunctionType(); getPointeeType()->getAsFunctionType();
} }
SourceLocation BlockExpr::getCaretLocation() const {
return TheBlock->getCaretLocation();
}
const Stmt *BlockExpr::getBody() const { return TheBlock->getBody(); }
Stmt *BlockExpr::getBody() { return TheBlock->getBody(); }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Generic Expression Routines // Generic Expression Routines
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -1400,8 +1407,8 @@ Stmt::child_iterator ObjCMessageExpr::child_end() {
} }
// Blocks // Blocks
Stmt::child_iterator BlockExpr::child_begin() { return &Body; } Stmt::child_iterator BlockExpr::child_begin() { return child_iterator(); }
Stmt::child_iterator BlockExpr::child_end() { return &Body+1; } Stmt::child_iterator BlockExpr::child_end() { return child_iterator(); }
Stmt::child_iterator BlockDeclRefExpr::child_begin() { return child_iterator();} Stmt::child_iterator BlockDeclRefExpr::child_begin() { return child_iterator();}
Stmt::child_iterator BlockDeclRefExpr::child_end() { return child_iterator(); } Stmt::child_iterator BlockDeclRefExpr::child_end() { return child_iterator(); }

View File

@ -895,26 +895,27 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
} }
void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
BlockDecl *BD = Node->getBlockDecl();
OS << "^"; OS << "^";
const FunctionType *AFT = Node->getFunctionType(); const FunctionType *AFT = Node->getFunctionType();
if (isa<FunctionTypeNoProto>(AFT)) { if (isa<FunctionTypeNoProto>(AFT)) {
OS << "()"; OS << "()";
} else if (!Node->arg_empty() || cast<FunctionTypeProto>(AFT)->isVariadic()) { } else if (!BD->param_empty() || cast<FunctionTypeProto>(AFT)->isVariadic()) {
const FunctionTypeProto *FT = cast<FunctionTypeProto>(AFT);
OS << '('; OS << '(';
std::string ParamStr; std::string ParamStr;
for (BlockExpr::arg_iterator AI = Node->arg_begin(), for (BlockDecl::param_iterator AI = BD->param_begin(),
E = Node->arg_end(); AI != E; ++AI) { E = BD->param_end(); AI != E; ++AI) {
if (AI != Node->arg_begin()) OS << ", "; if (AI != BD->param_begin()) OS << ", ";
ParamStr = (*AI)->getName(); ParamStr = (*AI)->getName();
(*AI)->getType().getAsStringInternal(ParamStr); (*AI)->getType().getAsStringInternal(ParamStr);
OS << ParamStr; OS << ParamStr;
} }
const FunctionTypeProto *FT = cast<FunctionTypeProto>(AFT);
if (FT->isVariadic()) { if (FT->isVariadic()) {
if (!Node->arg_empty()) OS << ", "; if (!BD->param_empty()) OS << ", ";
OS << "..."; OS << "...";
} }
OS << ')'; OS << ')';

View File

@ -1114,18 +1114,12 @@ ObjCStringLiteral* ObjCStringLiteral::CreateImpl(Deserializer& D, ASTContext& C)
void BlockExpr::EmitImpl(Serializer& S) const { void BlockExpr::EmitImpl(Serializer& S) const {
S.Emit(getType()); S.Emit(getType());
S.Emit(getCaretLocation()); S.EmitOwnedPtr(TheBlock);
S.EmitOwnedPtr(Body);
} }
BlockExpr* BlockExpr::CreateImpl(Deserializer& D, ASTContext& C) { BlockExpr* BlockExpr::CreateImpl(Deserializer& D, ASTContext& C) {
QualType Q = QualType::ReadVal(D); QualType T = QualType::ReadVal(D);
SourceLocation L = SourceLocation::ReadVal(D); return new BlockExpr(cast<BlockDecl>(D.ReadOwnedPtr<Decl>(C)),T);
/*CompoundStmt* BodyStmt = cast<CompoundStmt>(*/D.ReadOwnedPtr<Stmt>(C)/*)*/;
assert(0 && "Cannot deserialize BlockBlockExpr yet");
// FIXME: need to handle parameters.
//return new BlockBlockExpr(L, Q, BodyStmt);
return 0;
} }
void BlockDeclRefExpr::EmitImpl(Serializer& S) const { void BlockDeclRefExpr::EmitImpl(Serializer& S) const {

View File

@ -2931,8 +2931,11 @@ Sema::ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, StmtTy *body,
BSI->isVariadic); BSI->isVariadic);
BlockTy = Context.getBlockPointerType(BlockTy); BlockTy = Context.getBlockPointerType(BlockTy);
return new BlockExpr(CaretLoc, BlockTy, &BSI->Params[0], BSI->Params.size(),
Body.take()); BlockDecl *NewBD = BlockDecl::Create(Context, CurContext, CaretLoc,
&BSI->Params[0], BSI->Params.size(),
Body.take());
return new BlockExpr(NewBD, BlockTy);
} }
/// ExprsMatchFnType - return true if the Exprs in array Args have /// ExprsMatchFnType - return true if the Exprs in array Args have