From 82dc00948fe7116edd31bfa07a728fda98648be1 Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 4 Jun 2010 11:21:44 +0000 Subject: [PATCH] Restructure how we interpret block-literal declarators. Correctly handle the case where we pick up block arguments from a typedef. Save the block signature as it was written, and preserve same through PCH. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@105466 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Decl.h | 7 +- lib/Frontend/PCHReaderDecl.cpp | 1 + lib/Frontend/PCHWriterDecl.cpp | 1 + lib/Sema/Sema.h | 3 + lib/Sema/SemaDecl.cpp | 22 ++++-- lib/Sema/SemaExpr.cpp | 134 ++++++++++++++++----------------- 6 files changed, 88 insertions(+), 80 deletions(-) diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 61447295ce..1e507a5d25 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -2127,11 +2127,13 @@ class BlockDecl : public Decl, public DeclContext { unsigned NumParams; Stmt *Body; + TypeSourceInfo *SignatureAsWritten; protected: BlockDecl(DeclContext *DC, SourceLocation CaretLoc) : Decl(Block, DC, CaretLoc), DeclContext(Block), - IsVariadic(false), ParamInfo(0), NumParams(0), Body(0) {} + IsVariadic(false), ParamInfo(0), NumParams(0), Body(0), + SignatureAsWritten(0) {} virtual ~BlockDecl(); virtual void Destroy(ASTContext& C); @@ -2148,6 +2150,9 @@ public: Stmt *getBody() const { return (Stmt*) Body; } void setBody(CompoundStmt *B) { Body = (Stmt*) B; } + void setSignatureAsWritten(TypeSourceInfo *Sig) { SignatureAsWritten = Sig; } + TypeSourceInfo *getSignatureAsWritten() const { return SignatureAsWritten; } + // Iterator access to formal parameters. unsigned param_size() const { return getNumParams(); } typedef ParmVarDecl **param_iterator; diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 606e852385..8b7b66c2b8 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -462,6 +462,7 @@ void PCHDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) { void PCHDeclReader::VisitBlockDecl(BlockDecl *BD) { VisitDecl(BD); BD->setBody(cast_or_null(Reader.ReadDeclStmt())); + BD->setSignatureAsWritten(Reader.GetTypeSourceInfo(Record, Idx)); unsigned NumParams = Record[Idx++]; llvm::SmallVector Params; Params.reserve(NumParams); diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index d0a01f083f..8eeef7c741 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -471,6 +471,7 @@ void PCHDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { void PCHDeclWriter::VisitBlockDecl(BlockDecl *D) { VisitDecl(D); Writer.AddStmt(D->getBody()); + Writer.AddTypeSourceInfo(D->getSignatureAsWritten(), Record); Record.push_back(D->param_size()); for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); P != PEnd; ++P) diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index e4e63c330b..32cd6dcc5c 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -841,6 +841,9 @@ public: bool &OverloadableAttrRequired); void CheckMain(FunctionDecl *FD); virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D); + ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, + SourceLocation Loc, + QualType T); ParmVarDecl *CheckParameter(DeclContext *DC, TypeSourceInfo *TSInfo, QualType T, IdentifierInfo *Name, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 02a157f1d8..52e4bb9aca 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3272,14 +3272,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Synthesize a parameter for each argument type. for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(), AE = FT->arg_type_end(); AI != AE; ++AI) { - ParmVarDecl *Param = ParmVarDecl::Create(Context, NewFD, - D.getIdentifierLoc(), 0, - *AI, - Context.getTrivialTypeSourceInfo(*AI, - D.getIdentifierLoc()), - VarDecl::None, - VarDecl::None, 0); - Param->setImplicit(); + ParmVarDecl *Param = + BuildParmVarDeclForTypedef(NewFD, D.getIdentifierLoc(), *AI); Params.push_back(Param); } } else { @@ -4331,6 +4325,18 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { return DeclPtrTy::make(New); } +/// \brief Synthesizes a variable for a parameter arising from a +/// typedef. +ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC, + SourceLocation Loc, + QualType T) { + ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, 0, + T, Context.getTrivialTypeSourceInfo(T, Loc), + VarDecl::None, VarDecl::None, 0); + Param->setImplicit(); + return Param; +} + ParmVarDecl *Sema::CheckParameter(DeclContext *DC, TypeSourceInfo *TSInfo, QualType T, IdentifierInfo *Name, diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 906fd08828..1640a61a22 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -6976,62 +6976,47 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!"); BlockScopeInfo *CurBlock = getCurBlock(); - if (ParamInfo.getNumTypeObjects() == 0 - || ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) { - ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); - QualType T = GetTypeForDeclarator(ParamInfo, CurScope); - - if (T->isArrayType()) { - Diag(ParamInfo.getSourceRange().getBegin(), - diag::err_block_returns_array); - return; - } - - // The parameter list is optional, if there was none, assume (). - if (!T->isFunctionType()) - T = Context.getFunctionType(T, 0, 0, false, 0, false, false, 0, 0, - FunctionType::ExtInfo()); - + TypeSourceInfo *Sig = 0; + QualType T = GetTypeForDeclarator(ParamInfo, CurScope, &Sig); + CurBlock->TheDecl->setSignatureAsWritten(Sig); + + QualType RetTy; + if (const FunctionType *Fn = T->getAs()) { + RetTy = Fn->getResultType(); + CurBlock->hasPrototype = isa(Fn); + CurBlock->isVariadic = + !isa(Fn) || cast(Fn)->isVariadic(); + } else { + RetTy = T; CurBlock->hasPrototype = true; CurBlock->isVariadic = false; - // Check for a valid sentinel attribute on this block. - if (CurBlock->TheDecl->getAttr()) { - Diag(ParamInfo.getAttributes()->getLoc(), - diag::warn_attribute_sentinel_not_variadic) << 1; - // FIXME: remove the attribute. - } - QualType RetTy = T.getTypePtr()->getAs()->getResultType(); - - // Do not allow returning a objc interface by-value. - if (RetTy->isObjCObjectType()) { - Diag(ParamInfo.getSourceRange().getBegin(), - diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy; - return; - } + } - CurBlock->ReturnType = RetTy; + CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic); + + // Don't allow returning an array by value. + if (RetTy->isArrayType()) { + Diag(ParamInfo.getSourceRange().getBegin(), diag::err_block_returns_array); return; } - // Analyze arguments to block. - assert(ParamInfo.getTypeObject(0).Kind == DeclaratorChunk::Function && - "Not a function declarator!"); - DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getTypeObject(0).Fun; + // Don't allow returning a objc interface by value. + if (RetTy->isObjCObjectType()) { + Diag(ParamInfo.getSourceRange().getBegin(), + diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy; + return; + } - CurBlock->hasPrototype = FTI.hasPrototype; - CurBlock->isVariadic = true; + // Context.DependentTy is used as a placeholder for a missing block + // return type. + if (RetTy != Context.DependentTy) + CurBlock->ReturnType = RetTy; - // 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 && - (!FTI.ArgInfo[0].Param.getAs()->getType().getCVRQualifiers()&& - FTI.ArgInfo[0].Param.getAs()->getType()->isVoidType())) { - // empty arg list, don't push any params. - CurBlock->isVariadic = false; - } else if (FTI.hasPrototype) { - for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { - ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs(); + // Push block parameters from the declarator if we had them. + if (isa(T)) { + FunctionProtoTypeLoc TL = cast(Sig->getTypeLoc()); + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { + ParmVarDecl *Param = TL.getArg(I); if (Param->getIdentifier() == 0 && !Param->isImplicit() && !Param->isInvalidDecl() && @@ -7039,13 +7024,39 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { Diag(Param->getLocation(), diag::err_parameter_name_omitted); CurBlock->Params.push_back(Param); } - CurBlock->isVariadic = FTI.isVariadic; + + // Fake up parameter variables if we have a typedef, like + // ^ fntype { ... } + } else if (const FunctionProtoType *Fn = T->getAs()) { + for (FunctionProtoType::arg_type_iterator + I = Fn->arg_type_begin(), E = Fn->arg_type_end(); I != E; ++I) { + ParmVarDecl *Param = + BuildParmVarDeclForTypedef(CurBlock->TheDecl, + ParamInfo.getSourceRange().getBegin(), + *I); + CurBlock->Params.push_back(Param); + } } - CurBlock->TheDecl->setParams(CurBlock->Params.data(), - CurBlock->Params.size()); - CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic); + + // Set the parmaeters on the block decl. + if (!CurBlock->Params.empty()) + CurBlock->TheDecl->setParams(CurBlock->Params.data(), + CurBlock->Params.size()); + + // Finally we can process decl attributes. ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); + if (!CurBlock->isVariadic && CurBlock->TheDecl->getAttr()) { + Diag(ParamInfo.getAttributes()->getLoc(), + diag::warn_attribute_sentinel_not_variadic) << 1; + // FIXME: remove the attribute. + } + + // Put the parameter variables in scope. We can bail out immediately + // if we don't have any. + if (CurBlock->Params.empty()) + return; + bool ShouldCheckShadow = Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored; @@ -7061,25 +7072,6 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { PushOnScopeChains(*AI, CurBlock->TheScope); } } - - // Check for a valid sentinel attribute on this block. - if (!CurBlock->isVariadic && - CurBlock->TheDecl->getAttr()) { - Diag(ParamInfo.getAttributes()->getLoc(), - diag::warn_attribute_sentinel_not_variadic) << 1; - // FIXME: remove the attribute. - } - - // Analyze the return type. - QualType T = GetTypeForDeclarator(ParamInfo, CurScope); - QualType RetTy = T->getAs()->getResultType(); - - // Do not allow returning a objc interface by-value. - if (RetTy->isObjCObjectType()) { - Diag(ParamInfo.getSourceRange().getBegin(), - diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy; - } else if (!RetTy->isDependentType()) - CurBlock->ReturnType = RetTy; } /// ActOnBlockError - If there is an error parsing a block, this callback -- 2.49.0