diff options
author | Mike Stump <mrs@apple.com> | 2009-02-04 22:31:32 +0000 |
---|---|---|
committer | Mike Stump <mrs@apple.com> | 2009-02-04 22:31:32 +0000 |
commit | 98eb8a7a702b95183ed015706b1f1c66f5cb27a4 (patch) | |
tree | c8447654c9c0f9e1bb7655e0d01a6edf33fc347c /lib | |
parent | 90350b6f815eecd9441119b1412695d33fb2b98f (diff) |
Add support for blocks with explicit return types.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63784 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 34 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 35 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 31 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 31 |
5 files changed, 103 insertions, 30 deletions
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 64c4c31fc4..d20f294bc6 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1211,11 +1211,29 @@ bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs) { } } +/// ParseBlockId - Parse a block-id, which roughly looks like int (int x). +/// +/// [clang] block-id: +/// [clang] specifier-qualifier-list block-declarator +/// +void Parser::ParseBlockId() { + // Parse the specifier-qualifier-list piece. + DeclSpec DS; + ParseSpecifierQualifierList(DS); + + // Parse the block-declarator. + Declarator DeclaratorInfo(DS, Declarator::BlockLiteralContext); + ParseDeclarator(DeclaratorInfo); + // Inform sema that we are starting a block. + Actions.ActOnBlockArguments(DeclaratorInfo, CurScope); +} + /// ParseBlockLiteralExpression - Parse a block literal, which roughly looks /// like ^(int x){ return x+1; } /// /// block-literal: /// [clang] '^' block-args[opt] compound-statement +/// [clang] '^' block-id compound-statement /// [clang] block-args: /// [clang] '(' parameter-list ')' /// @@ -1235,7 +1253,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { // Parse the return type if present. DeclSpec DS; - Declarator ParamInfo(DS, Declarator::PrototypeContext); + Declarator ParamInfo(DS, Declarator::BlockLiteralContext); // If this block has arguments, parse them. There is no ambiguity here with // the expression case, because the expression case requires a parameter list. @@ -1244,20 +1262,24 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { // Parse the pieces after the identifier as if we had "int(...)". ParamInfo.SetIdentifier(0, CaretLoc); if (ParamInfo.getInvalidType()) { - // If there was an error parsing the arguments, they may have tried to use - // ^(x+y) which requires an argument list. Just skip the whole block - // literal. + // If there was an error parsing the arguments, they may have + // tried to use ^(x+y) which requires an argument list. Just + // skip the whole block literal. return ExprError(); } + // Inform sema that we are starting a block. + Actions.ActOnBlockArguments(ParamInfo, CurScope); + } else if (! Tok.is(tok::l_brace)) { + ParseBlockId(); } else { // Otherwise, pretend we saw (void). ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, 0, 0, 0, CaretLoc, ParamInfo)); + // Inform sema that we are starting a block. + Actions.ActOnBlockArguments(ParamInfo, CurScope); } - // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(ParamInfo); OwningExprResult Result(Actions, true); if (Tok.is(tok::l_brace)) { diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4879ac8458..975c5e1c59 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1209,7 +1209,7 @@ public: /// ActOnBlockArguments - This callback allows processing of block arguments. /// If there are no arguments, this is still invoked. - virtual void ActOnBlockArguments(Declarator &ParamInfo); + virtual void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope); /// 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 66710370af..3ee6e52e2e 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4179,12 +4179,36 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) { PushDeclContext(BlockScope, BSI->TheDecl); } -void Sema::ActOnBlockArguments(Declarator &ParamInfo) { +void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { + assert(ParamInfo.getIdentifier() == 0 && "block-id should have no identifier!"); + + if (ParamInfo.getNumTypeObjects() == 0 + || ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) { + QualType T = GetTypeForDeclarator(ParamInfo, CurScope); + + // The type is entirely optional as well, if none, use DependentTy. + if (T.isNull()) + T = Context.DependentTy; + + // The parameter list is optional, if there was none, assume (). + if (!T->isFunctionType()) + T = Context.getFunctionType(T, NULL, 0, 0, 0); + + CurBlock->hasPrototype = true; + CurBlock->isVariadic = false; + Type *RetTy = T.getTypePtr()->getAsFunctionType()->getResultType() + .getTypePtr(); + + if (!RetTy->isDependentType()) + CurBlock->ReturnType = RetTy; + return; + } + // Analyze arguments to block. assert(ParamInfo.getTypeObject(0).Kind == DeclaratorChunk::Function && "Not a function declarator!"); DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getTypeObject(0).Fun; - + CurBlock->hasPrototype = FTI.hasPrototype; CurBlock->isVariadic = true; @@ -4200,6 +4224,13 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo) { for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) CurBlock->Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param); CurBlock->isVariadic = FTI.isVariadic; + QualType T = GetTypeForDeclarator (ParamInfo, CurScope); + + Type* RetTy = T.getTypePtr()->getAsFunctionType()->getResultType() + .getTypePtr(); + + if (!RetTy->isDependentType()) + CurBlock->ReturnType = RetTy; } CurBlock->TheDecl->setArgs(&CurBlock->Params[0], CurBlock->Params.size()); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index cf26b90bc4..7697dbda00 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -731,8 +731,8 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { CurBlock->ReturnType = RetValExp->getType().getTypePtr(); } else CurBlock->ReturnType = Context.VoidTy.getTypePtr(); - return Owned(new ReturnStmt(ReturnLoc, RetValExp)); } + QualType FnRetType = QualType(CurBlock->ReturnType, 0); // 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 @@ -749,21 +749,22 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (!RetValExp) return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); - // 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()) { - // FIXME: non-localizable string in diagnostic - DiagnoseAssignmentResult(Incompatible, ReturnLoc, BlockQT, - RetValType, RetValExp, "returning"); - return StmtError(); - } + if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { + // we have a non-void block with an expression, continue checking + QualType RetValType = RetValExp->getType(); + + // C99 6.8.6.4p3(136): The return statement is not an assignment. The + // overlap restriction of subclause 6.5.16.1 does not apply to the case of + // function return. - if (RetValExp) CheckReturnStackAddr(RetValExp, BlockQT, ReturnLoc); + // In C++ the return statement is handled via a copy initialization. + // the C version of which boils down to CheckSingleAssignmentConstraints. + // FIXME: Leaks RetValExp. + if (PerformCopyInitialization(RetValExp, FnRetType, "returning")) + return StmtError(); + + if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + } return Owned(new ReturnStmt(ReturnLoc, RetValExp)); } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 9d78d0adbf..e6d18338a4 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -251,9 +251,20 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS) { return Result; } -/// GetTypeForDeclarator - Convert the type for the specified declarator to Type -/// instances. Skip the outermost Skip type objects. +/// GetTypeForDeclarator - Convert the type for the specified +/// declarator to Type instances. Skip the outermost Skip type +/// objects. QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { + bool OmittedReturnType = false; + + if (D.getContext() == Declarator::BlockLiteralContext + && Skip == 0 + && !D.getDeclSpec().hasTypeSpecifier() + && (D.getNumTypeObjects() == 0 + || (D.getNumTypeObjects() == 1 + && D.getTypeObject(0).Kind == DeclaratorChunk::Function))) + OmittedReturnType = true; + // long long is a C99 feature. if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x && D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong) @@ -265,9 +276,16 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { switch (D.getKind()) { case Declarator::DK_Abstract: case Declarator::DK_Normal: - case Declarator::DK_Operator: - T = ConvertDeclSpecToType(D.getDeclSpec()); + case Declarator::DK_Operator: { + const DeclSpec& DS = D.getDeclSpec(); + if (OmittedReturnType) + // We default to a dependent type initially. Can be modified by + // the first return statement. + T = Context.DependentTy; + else + T = ConvertDeclSpecToType(DS); break; + } case Declarator::DK_Constructor: case Declarator::DK_Destructor: @@ -279,8 +297,9 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { break; } - // Walk the DeclTypeInfo, building the recursive type as we go. DeclTypeInfos - // are ordered from the identifier out, which is opposite of what we want :). + // Walk the DeclTypeInfo, building the recursive type as we go. + // DeclTypeInfos are ordered from the identifier out, which is + // opposite of what we want :). for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) { DeclaratorChunk &DeclType = D.getTypeObject(e-i-1+Skip); switch (DeclType.Kind) { |