From: John McCall Date: Fri, 4 Jun 2010 19:02:56 +0000 (+0000) Subject: Preserve more information from a block's original function declarator, if one X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c71a4915ca216847599d03cab4ed1c5086b0eb43;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@105478 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index a3f1b4455e..43bf21313f 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3147,7 +3147,7 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, QualType BlockTy = Expr->getType()->getAs()->getPointeeType(); // Encode result type. - getObjCEncodingForType(cast(BlockTy)->getResultType(), S); + getObjCEncodingForType(BlockTy->getAs()->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/lib/Sema/Sema.h b/lib/Sema/Sema.h index 32cd6dcc5c..09d813c7db 100644 --- a/lib/Sema/Sema.h +++ b/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 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/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 4f3f41b715..d47f2ce8ed 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/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/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 1640a61a22..e1a6a04bfd 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/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()) { + CurBlock->FunctionType = T; RetTy = Fn->getResultType(); - CurBlock->hasPrototype = isa(Fn); - CurBlock->isVariadic = + isVariadic = !isa(Fn) || cast(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 Params; if (isa(T)) { FunctionProtoTypeLoc TL = cast(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()) { + if (!isVariadic && CurBlock->TheDecl->getAttr()) { 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 ArgTypes; - for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i) - ArgTypes.push_back(BSI->Params[i]->getType()); - bool NoReturn = BSI->TheDecl->getAttr(); 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::ExtInfo Ext = FTy->getExtInfo(); + if (NoReturn && !Ext.getNoReturn()) Ext = Ext.withNoReturn(true); + + // Turn protoless block types into nullary block types. + if (isa(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(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/test/CodeGen/blocks.c b/test/CodeGen/blocks.c index a0f5dae6f4..6888356a5a 100644 --- a/test/CodeGen/blocks.c +++ b/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; +};