Add semantic analysis for "blocks".
Highlights... - 4 new AST nodes, BlockExpr, BlockStmtExpr, BlockExprExpr, BlockDeclRefExpr. - Sema::ActOnBlockStart(), ActOnBlockError(), ActOnBlockStmtExpr(), ActOnBlockExprExpr(), ActOnBlockReturnStmt(). Next steps... - hack Sema::ActOnIdentifierExpr() to deal with block decl refs. - add attribute handler for byref decls. - add test cases. llvm-svn: 55710
This commit is contained in:
parent
62be9ad270
commit
c540d66940
|
@ -1475,6 +1475,124 @@ private:
|
|||
InitListExpr() : Expr(InitListExprClass, QualType()) {}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Clang Extensions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// BlockExpr - Common base class between BlockStmtExpr and BlockExprExpr.
|
||||
class BlockExpr : public Expr {
|
||||
SourceLocation CaretLocation;
|
||||
llvm::SmallVector<ParmVarDecl*, 8> Args;
|
||||
protected:
|
||||
BlockExpr(StmtClass SC, QualType ty, SourceLocation caretloc,
|
||||
ParmVarDecl **args, unsigned numargs)
|
||||
: Expr(SC, ty), CaretLocation(caretloc), Args(args, args+numargs) {}
|
||||
public:
|
||||
SourceLocation getCaretLocation() const { return CaretLocation; }
|
||||
|
||||
/// getFunctionType - Return the underlying function type for this block.
|
||||
const FunctionType *getFunctionType() const;
|
||||
|
||||
/// 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) {
|
||||
return T->getStmtClass() == BlockStmtExprClass ||
|
||||
T->getStmtClass() == BlockExprExprClass;
|
||||
}
|
||||
static bool classof(const BlockExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// BlockStmtExpr - Represent a block literal with a syntax:
|
||||
/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body }
|
||||
class BlockStmtExpr : public BlockExpr {
|
||||
CompoundStmt *Body;
|
||||
public:
|
||||
BlockStmtExpr(SourceLocation CaretLoc, QualType Ty, ParmVarDecl **args,
|
||||
unsigned numargs, CompoundStmt *body) :
|
||||
BlockExpr(BlockStmtExprClass, Ty, CaretLoc,
|
||||
args, numargs), Body(body) {}
|
||||
|
||||
const CompoundStmt *getBody() const { return Body; }
|
||||
CompoundStmt *getBody() { return Body; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getCaretLocation(), Body->getLocEnd());
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == BlockStmtExprClass;
|
||||
}
|
||||
static bool classof(const BlockStmtExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static BlockStmtExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// BlockExprExpr - Represents a block literal with syntax:
|
||||
/// ^(expression) or ^(int arg1, float arg2)(expression)
|
||||
class BlockExprExpr : public BlockExpr {
|
||||
Expr *BodyExpr;
|
||||
public:
|
||||
BlockExprExpr(SourceLocation CaretLoc, QualType Ty, ParmVarDecl **args,
|
||||
unsigned numargs, Expr *body) :
|
||||
BlockExpr(BlockExprExprClass, Ty, CaretLoc,
|
||||
args, numargs), BodyExpr(body) {}
|
||||
|
||||
const Expr *getExpr() const { return BodyExpr; }
|
||||
Expr *getExpr() { return BodyExpr; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getCaretLocation(), BodyExpr->getLocEnd());
|
||||
}
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == BlockExprExprClass;
|
||||
}
|
||||
static bool classof(const BlockExprExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// BlockDeclRefExpr - A reference to a declared variable, function,
|
||||
/// enum, etc.
|
||||
class BlockDeclRefExpr : public Expr {
|
||||
ValueDecl *D;
|
||||
SourceLocation Loc;
|
||||
bool IsByRef;
|
||||
public:
|
||||
BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool ByRef) :
|
||||
Expr(BlockDeclRefExprClass, t), D(d), Loc(l), IsByRef(ByRef) {}
|
||||
|
||||
ValueDecl *getDecl() { return D; }
|
||||
const ValueDecl *getDecl() const { return D; }
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
bool isByRef() const { return IsByRef; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == BlockDeclRefExprClass;
|
||||
}
|
||||
static bool classof(const BlockDeclRefExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static BlockDeclRefExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
|
|
@ -108,8 +108,12 @@ STMT(76, ObjCPropertyRefExpr , Expr)
|
|||
// Clang Extensions.
|
||||
STMT(77, OverloadExpr , Expr)
|
||||
STMT(78, ShuffleVectorExpr , Expr)
|
||||
STMT(79, BlockExpr , Expr)
|
||||
STMT(80, BlockStmtExpr , BlockExpr)
|
||||
STMT(81, BlockExprExpr , BlockExpr)
|
||||
STMT(82, BlockDeclRefExpr , Expr)
|
||||
|
||||
LAST_EXPR(78)
|
||||
LAST_EXPR(82)
|
||||
|
||||
#undef STMT
|
||||
#undef FIRST_STMT
|
||||
|
|
|
@ -868,6 +868,12 @@ DIAG(err_qualified_block_pointer_type, ERROR,
|
|||
"qualifier specification on block pointer type not allowed")
|
||||
DIAG(err_nonfunction_block_type, ERROR,
|
||||
"block pointer to non-function type is invalid")
|
||||
DIAG(err_return_block_has_expr, ERROR,
|
||||
"void block should not return a value")
|
||||
DIAG(err_block_return_missing_expr, ERROR,
|
||||
"non-void block should return a value")
|
||||
DIAG(err_block_with_return_type_requires_args, ERROR,
|
||||
"block with explicit return type requires argument list")
|
||||
|
||||
// Expressions.
|
||||
DIAG(ext_sizeof_function_type, EXTENSION,
|
||||
|
@ -1124,6 +1130,10 @@ DIAG(warn_uninit_val, WARNING, "use of uninitialized variable")
|
|||
// Blocks
|
||||
DIAG(err_expected_block_lbrace, ERROR,
|
||||
"expected '{' in block literal")
|
||||
DIAG(err_goto_in_block, ERROR,
|
||||
"goto not allowed in closure literal")
|
||||
DIAG(err_return_in_block_expression, ERROR,
|
||||
"return not allowed in block expression literal")
|
||||
|
||||
// CFString checking
|
||||
DIAG(err_cfstring_literal_not_string_constant, ERROR,
|
||||
|
|
|
@ -282,6 +282,13 @@ InitListExpr::InitListExpr(SourceLocation lbraceloc,
|
|||
InitExprs.push_back(initexprs[i]);
|
||||
}
|
||||
|
||||
/// getFunctionType - Return the underlying function type for this closure.
|
||||
///
|
||||
const FunctionType *BlockExpr::getFunctionType() const {
|
||||
return getType()->getAsBlockPointerType()->
|
||||
getPointeeType()->getAsFunctionType();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Generic Expression Routines
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -1432,3 +1439,18 @@ Stmt::child_iterator ObjCMessageExpr::child_end() {
|
|||
return &SubExprs[0]+ARGS_START+getNumArgs();
|
||||
}
|
||||
|
||||
// Blocks
|
||||
Stmt::child_iterator BlockStmtExpr::child_begin() {
|
||||
return reinterpret_cast<Stmt**>(&Body);
|
||||
}
|
||||
Stmt::child_iterator BlockStmtExpr::child_end() {
|
||||
return reinterpret_cast<Stmt**>(&Body)+1;
|
||||
}
|
||||
|
||||
Stmt::child_iterator BlockExprExpr::child_begin() {
|
||||
return reinterpret_cast<Stmt**>(&BodyExpr);
|
||||
}
|
||||
Stmt::child_iterator BlockExprExpr::child_end() {
|
||||
return reinterpret_cast<Stmt**>(&BodyExpr)+1;
|
||||
}
|
||||
|
||||
|
|
|
@ -874,6 +874,46 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
|
|||
OS << "]";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
|
||||
OS << "^";
|
||||
|
||||
const FunctionType *AFT = Node->getFunctionType();
|
||||
|
||||
if (isa<FunctionTypeNoProto>(AFT)) {
|
||||
OS << "()";
|
||||
} else if (!Node->arg_empty() || cast<FunctionTypeProto>(AFT)->isVariadic()) {
|
||||
const FunctionTypeProto *FT = cast<FunctionTypeProto>(AFT);
|
||||
OS << '(';
|
||||
std::string ParamStr;
|
||||
for (BlockStmtExpr::arg_iterator AI = Node->arg_begin(),
|
||||
E = Node->arg_end(); AI != E; ++AI) {
|
||||
if (AI != Node->arg_begin()) OS << ", ";
|
||||
ParamStr = (*AI)->getName();
|
||||
(*AI)->getType().getAsStringInternal(ParamStr);
|
||||
OS << ParamStr;
|
||||
}
|
||||
|
||||
if (FT->isVariadic()) {
|
||||
if (!Node->arg_empty()) OS << ", ";
|
||||
OS << "...";
|
||||
}
|
||||
OS << ')';
|
||||
}
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitBlockStmtExpr(BlockStmtExpr *Node) {
|
||||
VisitBlockExpr(Node);
|
||||
PrintRawCompoundStmt(Node->getBody());
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitBlockExprExpr(BlockExprExpr *Node) {
|
||||
VisitBlockExpr(Node);
|
||||
PrintExpr(Node->getExpr());
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
|
||||
OS << Node->getDecl()->getName();
|
||||
}
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Stmt method implementations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -1108,6 +1108,38 @@ ObjCStringLiteral* ObjCStringLiteral::CreateImpl(Deserializer& D, ASTContext& C)
|
|||
return new ObjCStringLiteral(String,T,L);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Serialization for Clang Extensions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void BlockStmtExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.Emit(getCaretLocation());
|
||||
S.EmitOwnedPtr(Body);
|
||||
}
|
||||
|
||||
BlockStmtExpr* BlockStmtExpr::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;
|
||||
}
|
||||
|
||||
void BlockDeclRefExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(Loc);
|
||||
S.Emit(getType());
|
||||
S.EmitBool(false);
|
||||
S.EmitPtr(getDecl());
|
||||
}
|
||||
|
||||
BlockDeclRefExpr* BlockDeclRefExpr::CreateImpl(Deserializer& D, ASTContext& C) {
|
||||
assert(0 && "Cannot deserialize BlockDeclRefExpr yet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// C++ Serialization
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -87,7 +87,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
|
|||
}
|
||||
|
||||
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
|
||||
: PP(pp), Context(ctxt), Consumer(consumer), CurContext(0) {
|
||||
: PP(pp), Context(ctxt), Consumer(consumer), CurContext(0), CurBlock(0) {
|
||||
|
||||
// Get IdentifierInfo objects for known functions for which we
|
||||
// do extra checking.
|
||||
|
|
|
@ -64,6 +64,7 @@ namespace clang {
|
|||
class ObjCIvarDecl;
|
||||
class ObjCMethodDecl;
|
||||
class ObjCPropertyDecl;
|
||||
struct BlockSemaInfo;
|
||||
|
||||
/// Sema - This implements semantic analysis and AST building for C.
|
||||
class Sema : public Action {
|
||||
|
@ -75,6 +76,10 @@ public:
|
|||
/// CurContext - This is the current declaration context of parsing.
|
||||
DeclContext *CurContext;
|
||||
|
||||
/// CurBlock - If inside of a block definition, this contains a pointer to
|
||||
/// the active block object that represents it.
|
||||
BlockSemaInfo *CurBlock;
|
||||
|
||||
/// LabelMap - This is a mapping from label identifiers to the LabelStmt for
|
||||
/// it (which acts like the label decl in some ways). Forward referenced
|
||||
/// labels have a LabelStmt created for them with a null location & SubStmt.
|
||||
|
@ -408,6 +413,7 @@ public:
|
|||
|
||||
virtual StmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
|
||||
ExprTy *RetValExp);
|
||||
StmtResult ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp);
|
||||
|
||||
virtual StmtResult ActOnAsmStmt(SourceLocation AsmLoc,
|
||||
bool IsSimple,
|
||||
|
@ -536,6 +542,27 @@ public:
|
|||
virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc,
|
||||
ExprTy *expr, TypeTy *type,
|
||||
SourceLocation RPLoc);
|
||||
|
||||
//===------------------------- "Block" Extension ------------------------===//
|
||||
|
||||
/// ActOnBlockStart - This callback is invoked when a block literal is
|
||||
/// started.
|
||||
virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope,
|
||||
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.
|
||||
virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope);
|
||||
|
||||
/// ActOnBlockStmtExpr - This is called when the body of a block statement
|
||||
/// literal was successfully completed. ^(int x){...}
|
||||
virtual ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, StmtTy *Body,
|
||||
Scope *CurScope);
|
||||
|
||||
/// ActOnBlockExprExpr - This is called when the body of a block
|
||||
/// expression literal was successfully completed. ^(int x)[foo bar: x]
|
||||
virtual ExprResult ActOnBlockExprExpr(SourceLocation CaretLoc, ExprTy *Body,
|
||||
Scope *CurScope);
|
||||
|
||||
// Act on C++ namespaces
|
||||
virtual DeclTy *ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
|
||||
|
@ -960,6 +987,27 @@ public:
|
|||
bool HadError() { return hadError; }
|
||||
};
|
||||
|
||||
/// BlockSemaInfo - When a block is being parsed, this contains information
|
||||
/// about the block. It is pointed to from Sema::CurBlock.
|
||||
struct BlockSemaInfo {
|
||||
llvm::SmallVector<ParmVarDecl*, 8> Params;
|
||||
llvm::SmallPtrSet<Decl*, 4> ByRefVars;
|
||||
bool hasPrototype;
|
||||
bool isVariadic;
|
||||
|
||||
/// TheScope - This is the scope for the block itself, which contains
|
||||
/// arguments etc.
|
||||
Scope *TheScope;
|
||||
|
||||
/// ReturnType - This will get set to block result type, by looking at
|
||||
/// return types, if any, in the block body.
|
||||
Type *ReturnType;
|
||||
|
||||
/// PrevBlockInfo - If this is nested inside another block, this points
|
||||
/// to the outer block.
|
||||
BlockSemaInfo *PrevBlockInfo;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Parse/DeclSpec.h"
|
||||
#include "clang/Parse/Scope.h"
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -2607,6 +2609,124 @@ Sema::ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond,
|
|||
return new ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, RPLoc);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Clang Extensions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// ActOnBlockStart - This callback is invoked when a block literal is started.
|
||||
void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope,
|
||||
Declarator &ParamInfo) {
|
||||
// Analyze block parameters.
|
||||
BlockSemaInfo *BSI = new BlockSemaInfo();
|
||||
|
||||
// Add BSI to CurBlock.
|
||||
BSI->PrevBlockInfo = CurBlock;
|
||||
CurBlock = BSI;
|
||||
|
||||
BSI->ReturnType = 0;
|
||||
BSI->TheScope = BlockScope;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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.
|
||||
if (FTI.hasPrototype &&
|
||||
FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
|
||||
(!((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;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// ActOnBlockError - If there is an error parsing a block, this callback
|
||||
/// is invoked to pop the information about the block from the action impl.
|
||||
void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
|
||||
// Ensure that CurBlock is deleted.
|
||||
llvm::OwningPtr<BlockSemaInfo> CC(CurBlock);
|
||||
|
||||
// Pop off CurBlock, handle nested blocks.
|
||||
CurBlock = CurBlock->PrevBlockInfo;
|
||||
|
||||
// FIXME: Delete the ParmVarDecl objects as well???
|
||||
|
||||
}
|
||||
|
||||
/// ActOnBlockStmtExpr - This is called when the body of a block statement
|
||||
/// literal was successfully completed. ^(int x){...}
|
||||
Sema::ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, StmtTy *body,
|
||||
Scope *CurScope) {
|
||||
// Ensure that CurBlock is deleted.
|
||||
llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock);
|
||||
llvm::OwningPtr<CompoundStmt> Body(static_cast<CompoundStmt*>(body));
|
||||
|
||||
// Pop off CurBlock, handle nested blocks.
|
||||
CurBlock = CurBlock->PrevBlockInfo;
|
||||
|
||||
QualType RetTy = Context.VoidTy;
|
||||
if (BSI->ReturnType)
|
||||
RetTy = QualType(BSI->ReturnType, 0);
|
||||
|
||||
llvm::SmallVector<QualType, 8> ArgTypes;
|
||||
for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
|
||||
ArgTypes.push_back(BSI->Params[i]->getType());
|
||||
|
||||
QualType BlockTy;
|
||||
if (!BSI->hasPrototype)
|
||||
BlockTy = Context.getFunctionTypeNoProto(RetTy);
|
||||
else
|
||||
BlockTy = Context.getFunctionType(RetTy, &ArgTypes[0], ArgTypes.size(),
|
||||
BSI->isVariadic);
|
||||
|
||||
BlockTy = Context.getBlockPointerType(BlockTy);
|
||||
return new BlockStmtExpr(CaretLoc, BlockTy,
|
||||
&BSI->Params[0], BSI->Params.size(), Body.take());
|
||||
}
|
||||
|
||||
/// ActOnBlockExprExpr - This is called when the body of a block
|
||||
/// expression literal was successfully completed. ^(int x)[foo bar: x]
|
||||
Sema::ExprResult Sema::ActOnBlockExprExpr(SourceLocation CaretLoc, ExprTy *body,
|
||||
Scope *CurScope) {
|
||||
// Ensure that CurBlock is deleted.
|
||||
llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock);
|
||||
llvm::OwningPtr<Expr> Body(static_cast<Expr*>(body));
|
||||
|
||||
// Pop off CurBlock, handle nested blocks.
|
||||
CurBlock = CurBlock->PrevBlockInfo;
|
||||
|
||||
if (BSI->ReturnType) {
|
||||
Diag(CaretLoc, diag::err_return_in_block_expression);
|
||||
return true;
|
||||
}
|
||||
|
||||
QualType RetTy = Body->getType();
|
||||
|
||||
llvm::SmallVector<QualType, 8> ArgTypes;
|
||||
for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
|
||||
ArgTypes.push_back(BSI->Params[i]->getType());
|
||||
|
||||
QualType BlockTy;
|
||||
if (!BSI->hasPrototype)
|
||||
BlockTy = Context.getFunctionTypeNoProto(RetTy);
|
||||
else
|
||||
BlockTy = Context.getFunctionType(RetTy, &ArgTypes[0], ArgTypes.size(),
|
||||
BSI->isVariadic);
|
||||
|
||||
BlockTy = Context.getBlockPointerType(BlockTy);
|
||||
return new BlockExprExpr(CaretLoc, BlockTy,
|
||||
&BSI->Params[0], BSI->Params.size(), Body.take());
|
||||
}
|
||||
|
||||
/// ExprsMatchFnType - return true if the Exprs in array Args have
|
||||
/// QualTypes that match the QualTypes of the arguments of the FnType.
|
||||
/// The number of arguments has already been validated to match the number of
|
||||
|
|
|
@ -588,6 +588,10 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
|
|||
Action::StmtResult
|
||||
Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
|
||||
IdentifierInfo *LabelII) {
|
||||
// If we are in a block, reject all gotos for now.
|
||||
if (CurBlock)
|
||||
return Diag(GotoLoc, diag::err_goto_in_block);
|
||||
|
||||
// Look up the record for this label identifier.
|
||||
LabelStmt *&LabelDecl = LabelMap[LabelII];
|
||||
|
||||
|
@ -630,10 +634,61 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
|
|||
return new BreakStmt(BreakLoc);
|
||||
}
|
||||
|
||||
/// ActOnBlockReturnStmt - Utilty routine to figure out block's return type.
|
||||
///
|
||||
Action::StmtResult
|
||||
Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
|
||||
|
||||
// If this is the first return we've seen in the block, infer the type of
|
||||
// the block from it.
|
||||
if (CurBlock->ReturnType == 0) {
|
||||
if (RetValExp)
|
||||
CurBlock->ReturnType = RetValExp->getType().getTypePtr();
|
||||
else
|
||||
CurBlock->ReturnType = Context.VoidTy.getTypePtr();
|
||||
return new ReturnStmt(ReturnLoc, RetValExp);
|
||||
}
|
||||
|
||||
// Otherwise, verify that this result type matches the previous one. We are
|
||||
// pickier with blocks than for normal functions because we don't have GCC
|
||||
// compatibility to worry about here.
|
||||
if (CurBlock->ReturnType->isVoidType()) {
|
||||
if (RetValExp) {
|
||||
Diag(ReturnLoc, diag::err_return_block_has_expr);
|
||||
delete RetValExp;
|
||||
RetValExp = 0;
|
||||
}
|
||||
return new ReturnStmt(ReturnLoc, RetValExp);
|
||||
}
|
||||
|
||||
if (!RetValExp) {
|
||||
Diag(ReturnLoc, diag::err_block_return_missing_expr);
|
||||
return true;
|
||||
}
|
||||
|
||||
// we have a non-void block with an expression, continue checking
|
||||
QualType RetValType = RetValExp->getType();
|
||||
|
||||
// For now, restrict multiple return statements in a block to have
|
||||
// strict compatible types only.
|
||||
QualType BlockQT = QualType(CurBlock->ReturnType, 0);
|
||||
if (Context.getCanonicalType(BlockQT).getTypePtr()
|
||||
!= Context.getCanonicalType(RetValType).getTypePtr()) {
|
||||
DiagnoseAssignmentResult(Incompatible, ReturnLoc, BlockQT,
|
||||
RetValType, RetValExp, "returning");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (RetValExp) CheckReturnStackAddr(RetValExp, BlockQT, ReturnLoc);
|
||||
|
||||
return new ReturnStmt(ReturnLoc, (Expr*)RetValExp);
|
||||
}
|
||||
|
||||
Action::StmtResult
|
||||
Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprTy *rex) {
|
||||
Expr *RetValExp = static_cast<Expr *>(rex);
|
||||
if (CurBlock)
|
||||
return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
|
||||
QualType FnRetType =
|
||||
getCurFunctionDecl() ? getCurFunctionDecl()->getResultType() :
|
||||
getCurMethodDecl()->getResultType();
|
||||
|
|
Loading…
Reference in New Issue