From: Steve Naroff Date: Wed, 3 Sep 2008 18:15:37 +0000 (+0000) Subject: Add semantic analysis for "blocks". X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4eb206bebcdab28ababe8df55c6185cec2cdc071;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55710 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index b84ca020a1..5acf4dea3c 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -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 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::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 diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 9a60898428..3acf4e6aee 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -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 diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 9c90306177..473f517681 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -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, diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 1410f7e05c..1ab2220387 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -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(&Body); +} +Stmt::child_iterator BlockStmtExpr::child_end() { + return reinterpret_cast(&Body)+1; +} + +Stmt::child_iterator BlockExprExpr::child_begin() { + return reinterpret_cast(&BodyExpr); +} +Stmt::child_iterator BlockExprExpr::child_end() { + return reinterpret_cast(&BodyExpr)+1; +} + diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index a76506007d..f5806ea5dd 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -874,6 +874,46 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { OS << "]"; } +void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { + OS << "^"; + + const FunctionType *AFT = Node->getFunctionType(); + + if (isa(AFT)) { + OS << "()"; + } else if (!Node->arg_empty() || cast(AFT)->isVariadic()) { + const FunctionTypeProto *FT = cast(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 //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp index 23879ee63b..5dbd3cd541 100644 --- a/lib/AST/StmtSerialization.cpp +++ b/lib/AST/StmtSerialization.cpp @@ -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(*/D.ReadOwnedPtr(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 //===----------------------------------------------------------------------===// diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 30ada28d8b..65f1d6812b 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -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. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 1ce4d804c0..faa16ca5e4 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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 Params; + llvm::SmallPtrSet 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 diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 7886976aaf..14fec20c9f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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 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 BSI(CurBlock); + llvm::OwningPtr Body(static_cast(body)); + + // Pop off CurBlock, handle nested blocks. + CurBlock = CurBlock->PrevBlockInfo; + + QualType RetTy = Context.VoidTy; + if (BSI->ReturnType) + RetTy = QualType(BSI->ReturnType, 0); + + llvm::SmallVector 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 BSI(CurBlock); + llvm::OwningPtr Body(static_cast(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 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 diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 629ab3465d..98efc8a907 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -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(rex); + if (CurBlock) + return ActOnBlockReturnStmt(ReturnLoc, RetValExp); QualType FnRetType = getCurFunctionDecl() ? getCurFunctionDecl()->getResultType() : getCurMethodDecl()->getResultType();