diff options
author | John McCall <rjmccall@apple.com> | 2010-06-04 19:02:56 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-06-04 19:02:56 +0000 |
commit | 8e346702b6f7d628ad1bf5fc3e8cdc697b08a9b7 (patch) | |
tree | 1ccc3b8eecb54ecb9db1daf2f2f6c544d618e8a0 | |
parent | 7f3d95054b492fbf6ebc22f7db32fb1574f25e6c (diff) | |
download | bcm5719-llvm-8e346702b6f7d628ad1bf5fc3e8cdc697b08a9b7.tar.gz bcm5719-llvm-8e346702b6f7d628ad1bf5fc3e8cdc697b08a9b7.zip |
Preserve more information from a block's original function declarator, if one
was given. Remove some unnecessary accounting from BlockScopeInfo. Handle
typedef'ed function types until such time as we decide not.
llvm-svn: 105478
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 15 | ||||
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 84 | ||||
-rw-r--r-- | clang/test/CodeGen/blocks.c | 6 |
5 files changed, 74 insertions, 35 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a3f1b4455e9..43bf21313f6 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3147,7 +3147,7 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, QualType BlockTy = Expr->getType()->getAs<BlockPointerType>()->getPointeeType(); // Encode result type. - getObjCEncodingForType(cast<FunctionType>(BlockTy)->getResultType(), S); + getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getResultType(), S); // Compute size of all parameters. // Start with computing size of a pointer in number of bytes. // FIXME: There might(should) be a better way of doing this computation! diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 32cd6dcc5cb..09d813c7dbe 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -155,9 +155,6 @@ struct FunctionScopeInfo { /// \brief Retains information about a block that is currently being parsed. struct BlockScopeInfo : FunctionScopeInfo { - llvm::SmallVector<ParmVarDecl*, 8> Params; - bool hasPrototype; - bool isVariadic; bool hasBlockDeclRefExprs; BlockDecl *TheDecl; @@ -166,13 +163,17 @@ struct BlockScopeInfo : FunctionScopeInfo { /// arguments etc. Scope *TheScope; - /// ReturnType - This will get set to block result type, by looking at - /// return types, if any, in the block body. + /// ReturnType - The return type of the block, or null if the block + /// signature didn't provide an explicit return type. QualType ReturnType; + /// BlockType - The function type of the block, if one was given. + /// Its return type may be BuiltinType::Dependent. + QualType FunctionType; + BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block) - : FunctionScopeInfo(NumErrors), hasPrototype(false), isVariadic(false), - hasBlockDeclRefExprs(false), TheDecl(Block), TheScope(BlockScope) + : FunctionScopeInfo(NumErrors), hasBlockDeclRefExprs(false), + TheDecl(Block), TheScope(BlockScope) { IsBlockInfo = true; } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 4f3f41b715f..d47f2ce8edc 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -511,7 +511,7 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { BlockScopeInfo *CurBlock = getCurBlock(); bool isVariadic; if (CurBlock) - isVariadic = CurBlock->isVariadic; + isVariadic = CurBlock->TheDecl->isVariadic(); else if (FunctionDecl *FD = getCurFunctionDecl()) isVariadic = FD->isVariadic(); else diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 1640a61a22d..e1a6a04bfd4 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6980,19 +6980,19 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { QualType T = GetTypeForDeclarator(ParamInfo, CurScope, &Sig); CurBlock->TheDecl->setSignatureAsWritten(Sig); + bool isVariadic; QualType RetTy; if (const FunctionType *Fn = T->getAs<FunctionType>()) { + CurBlock->FunctionType = T; RetTy = Fn->getResultType(); - CurBlock->hasPrototype = isa<FunctionProtoType>(Fn); - CurBlock->isVariadic = + isVariadic = !isa<FunctionProtoType>(Fn) || cast<FunctionProtoType>(Fn)->isVariadic(); } else { RetTy = T; - CurBlock->hasPrototype = true; - CurBlock->isVariadic = false; + isVariadic = false; } - CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic); + CurBlock->TheDecl->setIsVariadic(isVariadic); // Don't allow returning an array by value. if (RetTy->isArrayType()) { @@ -7008,11 +7008,14 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { } // Context.DependentTy is used as a placeholder for a missing block - // return type. + // return type. TODO: what should we do with declarators like: + // ^ * { ... } + // If the answer is "apply template argument deduction".... if (RetTy != Context.DependentTy) CurBlock->ReturnType = RetTy; // Push block parameters from the declarator if we had them. + llvm::SmallVector<ParmVarDecl*, 8> Params; if (isa<FunctionProtoType>(T)) { FunctionProtoTypeLoc TL = cast<FunctionProtoTypeLoc>(Sig->getTypeLoc()); for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { @@ -7022,7 +7025,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { !Param->isInvalidDecl() && !getLangOptions().CPlusPlus) Diag(Param->getLocation(), diag::err_parameter_name_omitted); - CurBlock->Params.push_back(Param); + Params.push_back(Param); } // Fake up parameter variables if we have a typedef, like @@ -7034,19 +7037,18 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { BuildParmVarDeclForTypedef(CurBlock->TheDecl, ParamInfo.getSourceRange().getBegin(), *I); - CurBlock->Params.push_back(Param); + Params.push_back(Param); } } - // Set the parmaeters on the block decl. - if (!CurBlock->Params.empty()) - CurBlock->TheDecl->setParams(CurBlock->Params.data(), - CurBlock->Params.size()); + // Set the parameters on the block decl. + if (!Params.empty()) + CurBlock->TheDecl->setParams(Params.data(), Params.size()); // Finally we can process decl attributes. ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); - if (!CurBlock->isVariadic && CurBlock->TheDecl->getAttr<SentinelAttr>()) { + if (!isVariadic && CurBlock->TheDecl->getAttr<SentinelAttr>()) { Diag(ParamInfo.getAttributes()->getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1; // FIXME: remove the attribute. @@ -7054,7 +7056,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { // Put the parameter variables in scope. We can bail out immediately // if we don't have any. - if (CurBlock->Params.empty()) + if (Params.empty()) return; bool ShouldCheckShadow = @@ -7099,22 +7101,52 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (!BSI->ReturnType.isNull()) RetTy = BSI->ReturnType; - llvm::SmallVector<QualType, 8> ArgTypes; - for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i) - ArgTypes.push_back(BSI->Params[i]->getType()); - bool NoReturn = BSI->TheDecl->getAttr<NoReturnAttr>(); QualType BlockTy; - if (!BSI->hasPrototype) - BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0, - FunctionType::ExtInfo(NoReturn, 0, CC_Default)); - else - BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(), - BSI->isVariadic, 0, false, false, 0, 0, - FunctionType::ExtInfo(NoReturn, 0, CC_Default)); + + // If the user wrote a function type in some form, try to use that. + if (!BSI->FunctionType.isNull()) { + const FunctionType *FTy = BSI->FunctionType->getAs<FunctionType>(); + + FunctionType::ExtInfo Ext = FTy->getExtInfo(); + if (NoReturn && !Ext.getNoReturn()) Ext = Ext.withNoReturn(true); + + // Turn protoless block types into nullary block types. + if (isa<FunctionNoProtoType>(FTy)) { + BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, + false, false, 0, 0, Ext); + + // Otherwise, if we don't need to change anything about the function type, + // preserve its sugar structure. + } else if (FTy->getResultType() == RetTy && + (!NoReturn || FTy->getNoReturnAttr())) { + BlockTy = BSI->FunctionType; + + // Otherwise, make the minimal modifications to the function type. + } else { + const FunctionProtoType *FPT = cast<FunctionProtoType>(FTy); + BlockTy = Context.getFunctionType(RetTy, + FPT->arg_type_begin(), + FPT->getNumArgs(), + FPT->isVariadic(), + /*quals*/ 0, + FPT->hasExceptionSpec(), + FPT->hasAnyExceptionSpec(), + FPT->getNumExceptions(), + FPT->exception_begin(), + Ext); + } + + // If we don't have a function type, just build one from nothing. + } else { + BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, + false, false, 0, 0, + FunctionType::ExtInfo(NoReturn, 0, CC_Default)); + } // FIXME: Check that return/parameter types are complete/non-abstract - DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end()); + DiagnoseUnusedParameters(BSI->TheDecl->param_begin(), + BSI->TheDecl->param_end()); BlockTy = Context.getBlockPointerType(BlockTy); // If needed, diagnose invalid gotos and switches in the block. diff --git a/clang/test/CodeGen/blocks.c b/clang/test/CodeGen/blocks.c index a0f5dae6f44..6888356a5a1 100644 --- a/clang/test/CodeGen/blocks.c +++ b/clang/test/CodeGen/blocks.c @@ -27,3 +27,9 @@ void (^test1)(void) = ^(void) { ^ { i = 1; }(); }; +typedef double ftype(double); +// It's not clear that we *should* support this syntax, but until that decision +// is made, we should support it properly and not crash. +ftype ^test2 = ^ftype { + return 0; +}; |