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/Sema | |
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/Sema')
-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 |
4 files changed, 75 insertions, 24 deletions
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) { |