Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -403,7 +403,7 @@ def AlwaysInline : InheritableAttr { let Spellings = [GCC<"always_inline">, Keyword<"__forceinline">]; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, Block]>; let Documentation = [Undocumented]; } @@ -539,7 +539,7 @@ def Cold : InheritableAttr { let Spellings = [GCC<"cold">]; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, Block]>; let Documentation = [Undocumented]; } @@ -747,7 +747,7 @@ def MinSize : InheritableAttr { let Spellings = [GNU<"minsize">]; - let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>; + let Subjects = SubjectList<[Function, ObjCMethod, Block], ErrorDiag>; let Documentation = [Undocumented]; } @@ -789,7 +789,7 @@ def Hot : InheritableAttr { let Spellings = [GCC<"hot">]; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, Block]>; // An AST node is created for this attribute, but not actually used beyond // semantic checking for mutual exclusion with the Cold attribute. let Documentation = [Undocumented]; @@ -820,7 +820,7 @@ def Restrict : InheritableAttr { let Spellings = [Declspec<"restrict">, GCC<"malloc">]; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, Block]>; let Documentation = [Undocumented]; } @@ -909,13 +909,13 @@ def DisableTailCalls : InheritableAttr { let Spellings = [GNU<"disable_tail_calls">, CXX11<"clang", "disable_tail_calls">]; - let Subjects = SubjectList<[Function, ObjCMethod]>; + let Subjects = SubjectList<[Function, ObjCMethod, Block]>; let Documentation = [DisableTailCallsDocs]; } def NoAlias : InheritableAttr { let Spellings = [Declspec<"noalias">]; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, Block]>; let Documentation = [NoAliasDocs]; } @@ -932,13 +932,13 @@ def NoDuplicate : InheritableAttr { let Spellings = [GNU<"noduplicate">, CXX11<"clang", "noduplicate">]; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, Block]>; let Documentation = [NoDuplicateDocs]; } def NoInline : InheritableAttr { let Spellings = [GCC<"noinline">, Declspec<"noinline">]; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, Block]>; let Documentation = [Undocumented]; } @@ -988,8 +988,8 @@ def NonNull : InheritableAttr { let Spellings = [GCC<"nonnull">]; - let Subjects = SubjectList<[ObjCMethod, HasFunctionProto, ParmVar], WarnDiag, - "ExpectedFunctionMethodOrParameter">; + let Subjects = SubjectList<[ObjCMethod, HasFunctionProto, ParmVar], + WarnDiag, "ExpectedFunctionMethodParameterOrBlock">; let Args = [VariadicUnsignedArgument<"Args">]; let AdditionalMembers = [{bool isNonNull(unsigned idx) const { @@ -1007,8 +1007,7 @@ def ReturnsNonNull : InheritableAttr { let Spellings = [GCC<"returns_nonnull">]; - let Subjects = SubjectList<[ObjCMethod, Function], WarnDiag, - "ExpectedFunctionOrMethod">; + let Subjects = SubjectList<[Function, ObjCMethod, Block], WarnDiag>; let Documentation = [ReturnsNonNullDocs]; } @@ -1210,7 +1209,7 @@ def OptimizeNone : InheritableAttr { let Spellings = [GNU<"optnone">, CXX11<"clang", "optnone">]; - let Subjects = SubjectList<[Function, ObjCMethod]>; + let Subjects = SubjectList<[Function, ObjCMethod, Block]>; let Documentation = [OptnoneDocs]; } Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2425,8 +2425,10 @@ def warn_attribute_wrong_decl_type : Warning< "%0 attribute only applies to %select{functions|unions|" "variables and functions|functions and methods|parameters|" - "functions, methods and blocks|functions, methods, and classes|" - "functions, methods, and parameters|classes|enums|variables|methods|" + "functions and blocks|functions, methods and blocks|" + "functions, methods and classes|functions, methods and parameters|" + "functions, methods, parameters and blocks|" + "classes|enums|variables|methods|" "variables, functions and labels|fields and global variables|structs|" "variables and typedefs|thread-local variables|" "variables and fields|variables, data members and tag types|" @@ -2434,7 +2436,7 @@ "struct or union|struct, union or class|types|" "Objective-C instance methods|init methods of interface or class extension declarations|" "variables, functions and classes|Objective-C protocols|" - "functions and global variables|structs, unions, and typedefs|structs and typedefs|" + "functions and global variables|structs, unions and typedefs|structs and typedefs|" "interface or protocol declarations|kernel functions|non-K&R-style functions}1">, InGroup; def err_attribute_wrong_decl_type : Error; Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -2035,8 +2035,6 @@ ParsedAttributes *Attrs = nullptr); private: - void ParseBlockId(SourceLocation CaretLoc); - // Check for the start of a C++11 attribute-specifier-seq in a context where // an attribute is not allowed. bool CheckProhibitedCXX11Attribute() { Index: include/clang/Sema/AttributeList.h =================================================================== --- include/clang/Sema/AttributeList.h +++ include/clang/Sema/AttributeList.h @@ -826,9 +826,11 @@ ExpectedVariableOrFunction, ExpectedFunctionOrMethod, ExpectedParameter, + ExpectedFunctionOrBlock, ExpectedFunctionMethodOrBlock, ExpectedFunctionMethodOrClass, ExpectedFunctionMethodOrParameter, + ExpectedFunctionMethodParameterOrBlock, ExpectedClass, ExpectedEnum, ExpectedVariable, Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -2922,9 +2922,11 @@ void ProcessPragmaWeak(Scope *S, Decl *D); // Decl attributes - this routine is the top level dispatcher. - void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); + void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD, + QualType *OverrideRetType = nullptr); void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL, - bool IncludeCXX11Attributes = true); + bool IncludeCXX11Attributes = true, + QualType *OverrideRetType = nullptr); bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, const AttributeList *AttrList); @@ -4072,7 +4074,7 @@ /// ActOnBlockStmtExpr - This is called when the body of a block statement /// literal was successfully completed. ^(int x){...} ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, - Scope *CurScope); + Scope *CurScope, Declarator *ParamInfo); //===---------------------------- Clang Extensions ----------------------===// Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -2676,32 +2676,6 @@ } } -/// ParseBlockId - Parse a block-id, which roughly looks like int (int x). -/// -/// \verbatim -/// [clang] block-id: -/// [clang] specifier-qualifier-list block-declarator -/// \endverbatim -void Parser::ParseBlockId(SourceLocation CaretLoc) { - if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); - return cutOffParsing(); - } - - // Parse the specifier-qualifier-list piece. - DeclSpec DS(AttrFactory); - ParseSpecifierQualifierList(DS); - - // Parse the block-declarator. - Declarator DeclaratorInfo(DS, Declarator::BlockLiteralContext); - ParseDeclarator(DeclaratorInfo); - - MaybeParseGNUAttributes(DeclaratorInfo); - - // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(CaretLoc, DeclaratorInfo, getCurScope()); -} - /// ParseBlockLiteralExpression - Parse a block literal, which roughly looks /// like ^(int x){ return x+1; } /// @@ -2711,6 +2685,8 @@ /// [clang] '^' block-id compound-statement /// [clang] block-args: /// [clang] '(' parameter-list ')' +/// [clang] block-id: +/// [clang] specifier-qualifier-list block-declarator /// \endverbatim ExprResult Parser::ParseBlockLiteralExpression() { assert(Tok.is(tok::caret) && "block literal starts with ^"); @@ -2753,13 +2729,14 @@ Actions.ActOnBlockError(CaretLoc, getCurScope()); return ExprError(); } - - MaybeParseGNUAttributes(ParamInfo); - - // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); } else if (!Tok.is(tok::l_brace)) { - ParseBlockId(CaretLoc); + // This is a block-id. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); + cutOffParsing(); + } + ParseSpecifierQualifierList(DS); + ParseDeclarator(ParamInfo); } else { // Otherwise, pretend we saw (void). ParsedAttributes attrs(AttrFactory); @@ -2788,12 +2765,12 @@ CaretLoc, CaretLoc, ParamInfo), attrs, CaretLoc); + } - MaybeParseGNUAttributes(ParamInfo); + MaybeParseGNUAttributes(ParamInfo); - // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); - } + // Inform sema that we are starting a block. + Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); ExprResult Result(true); @@ -2807,7 +2784,8 @@ StmtResult Stmt(ParseCompoundStatementBody()); BlockScope.Exit(); if (!Stmt.isInvalid()) - Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.get(), getCurScope()); + Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.get(), getCurScope(), + &ParamInfo); else Actions.ActOnBlockError(CaretLoc, getCurScope()); return Result; Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -111,6 +111,10 @@ return cast(D)->getReturnType(); } +static QualType getPossiblyOverriddenResultType(const Decl *D, QualType *OverrideRetType) { + return OverrideRetType ? *OverrideRetType : getFunctionOrMethodResultType(D); +} + static SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) { if (const auto *FD = dyn_cast(D)) return FD->getReturnTypeSourceRange(); @@ -1254,7 +1258,7 @@ static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D, const AttributeList &Attr) { if (Attr.getNumArgs() > 0) { - if (D->getFunctionType()) { + if (D->getFunctionType(/*BlocksToo=*/true)) { handleNonNullAttr(S, D, Attr); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_parm_no_args) @@ -1274,8 +1278,8 @@ } static void handleReturnsNonNullAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - QualType ResultType = getFunctionOrMethodResultType(D); + const AttributeList &Attr, + QualType ResultType) { SourceRange SR = getFunctionOrMethodResultSourceRange(D); if (!attrNonNullArgCheck(S, ResultType, Attr, SourceRange(), SR, /* isReturnValue */ true)) @@ -1595,8 +1599,8 @@ Attr.getAttributeSpellingListIndex())); } -static void handleRestrictAttr(Sema &S, Decl *D, const AttributeList &Attr) { - QualType ResultType = getFunctionOrMethodResultType(D); +static void handleRestrictAttr(Sema &S, Decl *D, const AttributeList &Attr, + QualType ResultType) { if (ResultType->isAnyPointerType() || ResultType->isBlockPointerType()) { D->addAttr(::new (S.Context) RestrictAttr( Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); @@ -4915,7 +4919,8 @@ /// silently ignore it if a GNU attribute. static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const AttributeList &Attr, - bool IncludeCXX11Attributes) { + bool IncludeCXX11Attributes, + QualType *OverrideRetType) { if (Attr.isInvalid() || Attr.getKind() == AttributeList::IgnoredAttribute) return; @@ -5063,7 +5068,8 @@ handleLaunchBoundsAttr(S, D, Attr); break; case AttributeList::AT_Restrict: - handleRestrictAttr(S, D, Attr); + handleRestrictAttr(S, D, Attr, + getPossiblyOverriddenResultType(D, OverrideRetType)); break; case AttributeList::AT_MayAlias: handleSimpleAttribute(S, D, Attr); @@ -5087,7 +5093,8 @@ handleNonNullAttr(S, D, Attr); break; case AttributeList::AT_ReturnsNonNull: - handleReturnsNonNullAttr(S, D, Attr); + handleReturnsNonNullAttr(S, D, Attr, + getPossiblyOverriddenResultType(D, OverrideRetType)); break; case AttributeList::AT_AssumeAligned: handleAssumeAlignedAttr(S, D, Attr); @@ -5451,9 +5458,11 @@ /// attribute list to the specified decl, ignoring any type attributes. void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList, - bool IncludeCXX11Attributes) { + bool IncludeCXX11Attributes, + QualType *OverrideRetType) { for (const AttributeList* l = AttrList; l; l = l->getNext()) - ProcessDeclAttribute(*this, S, D, *l, IncludeCXX11Attributes); + ProcessDeclAttribute(*this, S, D, *l, IncludeCXX11Attributes, + OverrideRetType); // FIXME: We should be able to handle these cases in TableGen. // GCC accepts @@ -5501,7 +5510,8 @@ const AttributeList *AttrList) { for (const AttributeList* l = AttrList; l; l = l->getNext()) { if (l->getKind() == AttributeList::AT_Annotate) { - ProcessDeclAttribute(*this, nullptr, ASDecl, *l, l->isCXX11Attribute()); + ProcessDeclAttribute(*this, nullptr, ASDecl, *l, l->isCXX11Attribute(), + nullptr); } else { Diag(l->getLoc(), diag::err_only_annotate_after_access_spec); return true; @@ -5640,10 +5650,12 @@ /// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in /// it, apply them to D. This is a bit tricky because PD can have attributes /// specified in many different places, and we need to find and apply them all. -void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { +void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD, + QualType *OverrideRetType) { // Apply decl attributes from the DeclSpec if present. if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes().getList()) - ProcessDeclAttributeList(S, D, Attrs); + ProcessDeclAttributeList(S, D, Attrs, /*IncludeCXX11Attributes=*/true, + OverrideRetType); // Walk the declarator structure, applying decl attributes that were in a type // position to the decl itself. This handles cases like: @@ -5651,11 +5663,13 @@ // when X is a decl attribute. for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs()) - ProcessDeclAttributeList(S, D, Attrs, /*IncludeCXX11Attributes=*/false); + ProcessDeclAttributeList(S, D, Attrs, /*IncludeCXX11Attributes=*/false, + OverrideRetType); // Finally, apply any attributes on the decl itself. if (const AttributeList *Attrs = PD.getAttributes()) - ProcessDeclAttributeList(S, D, Attrs); + ProcessDeclAttributeList(S, D, Attrs, /*IncludeCXX11Attributes=*/true, + OverrideRetType); } /// Is the given declaration allowed to use a forbidden type? Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -11517,9 +11517,6 @@ CurBlock->TheDecl->param_end(), /*CheckParameterNames=*/false); } - - // Finally we can process decl attributes. - ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); // Put the parameter variables in scope. for (auto AI : CurBlock->TheDecl->params()) { @@ -11549,7 +11546,8 @@ /// ActOnBlockStmtExpr - This is called when the body of a block statement /// literal was successfully completed. ^(int x){...} ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, - Stmt *Body, Scope *CurScope) { + Stmt *Body, Scope *CurScope, + Declarator *ParamInfo) { // If blocks are disabled, emit an error. if (!LangOpts.Blocks) Diag(CaretLoc, diag::err_blocks_disable); @@ -11571,6 +11569,12 @@ if (!BSI->ReturnType.isNull()) RetTy = BSI->ReturnType; + // We have to process attributes super late, because some of them warn on + // unsupported return types, but the return type here can be inferred. + // ParamInfo could be null if called from TransformBlockExpr. + if (ParamInfo) + ProcessDeclAttributes(CurScope, BSI->TheDecl, *ParamInfo, &RetTy); + bool NoReturn = BSI->TheDecl->hasAttr(); QualType BlockTy; Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -11070,7 +11070,7 @@ #endif return SemaRef.ActOnBlockStmtExpr(E->getCaretLocation(), body.get(), - /*Scope=*/nullptr); + /*Scope=*/nullptr, /*ParamInfo=*/nullptr); } template Index: test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p1.cpp =================================================================== --- test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p1.cpp +++ test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p1.cpp @@ -7,8 +7,8 @@ [[carries_dependency]] void f1(); // FIXME: warn here [[carries_dependency]] int f2(); // ok int f3(int param [[carries_dependency]]); // ok -[[carries_dependency]] int (*f4)(); // expected-error {{'carries_dependency' attribute only applies to functions, methods, and parameters}} -int (*f5 [[carries_dependency]])(); // expected-error {{'carries_dependency' attribute only applies to functions, methods, and parameters}} +[[carries_dependency]] int (*f4)(); // expected-error {{'carries_dependency' attribute only applies to functions, methods and parameters}} +int (*f5 [[carries_dependency]])(); // expected-error {{'carries_dependency' attribute only applies to functions, methods and parameters}} int (*f6)() [[carries_dependency]]; // expected-error {{'carries_dependency' attribute cannot be applied to types}} int (*f7)(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}} int (((f8)))(int n [[carries_dependency]]); // ok @@ -21,7 +21,7 @@ }; void f() { [[carries_dependency]] int f(int n [[carries_dependency]]); // ok - [[carries_dependency]] // expected-error {{'carries_dependency' attribute only applies to functions, methods, and parameters}} + [[carries_dependency]] // expected-error {{'carries_dependency' attribute only applies to functions, methods and parameters}} int (*p)(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}} } Index: test/CodeGen/always-inline.c =================================================================== --- test/CodeGen/always-inline.c +++ test/CodeGen/always-inline.c @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -fno-inline -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fno-inline -fno-inline-functions -fblocks -O -DBLOCKS_TOO -emit-llvm %s -o - | FileCheck %s // CHECK-NOT: foo -void bar() { -} +extern void bar(); inline void __attribute__((__always_inline__)) foo() { bar(); @@ -13,3 +13,11 @@ void i_want_bar() { foo(); } + +#ifdef BLOCKS_TOO +void i_want_bar_from_block() { + void (^foo)() = ^ __attribute__((__always_inline__)) { bar(); }; + foo(); + foo(); +} +#endif Index: test/CodeGen/attr-disable-tail-calls.c =================================================================== --- test/CodeGen/attr-disable-tail-calls.c +++ test/CodeGen/attr-disable-tail-calls.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 %s -emit-llvm -mdisable-tail-calls -o - | FileCheck %s -check-prefix=DISABLE -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 %s -emit-llvm -o - | FileCheck %s -check-prefix=ENABLE +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 -fblocks %s -emit-llvm -mdisable-tail-calls -o - | FileCheck %s -check-prefix=DISABLE +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 -fblocks %s -emit-llvm -o - | FileCheck %s -check-prefix=ENABLE // DISABLE: define i32 @f1() [[ATTRTRUE:#[0-9]+]] { // DISABLE: define i32 @f2() [[ATTRTRUE]] { @@ -14,6 +14,14 @@ return 0; } +// ENABLE: define internal i32 @b_block_invoke{{.*}} [[ATTRTRUE2:#[0-9]+]] { + +// (cold avoids ATTRTRUE == ATTRTRUE2) +int (^b)() = ^ __attribute__((disable_tail_calls, cold)) { + return 0; +}; + // DISABLE: attributes [[ATTRTRUE]] = { {{.*}}"disable-tail-calls"="true"{{.*}} } // ENABLE: attributes [[ATTRFALSE]] = { {{.*}}"disable-tail-calls"="false"{{.*}} } // ENABLE: attributes [[ATTRTRUE]] = { {{.*}}"disable-tail-calls"="true"{{.*}} } +// ENABLE: attributes [[ATTRTRUE2]] = { {{.*}}"disable-tail-calls"="true"{{.*}} } Index: test/CodeGen/attr-noinline.c =================================================================== --- test/CodeGen/attr-noinline.c +++ test/CodeGen/attr-noinline.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -debug-info-kind=limited -emit-llvm -o %t %s -// RUN: grep 'noinline' %t +// RUN: %clang_cc1 -debug-info-kind=limited -fblocks -emit-llvm -o %t %s +// RUN: grep 'Function Attrs:.*noinline' %t | count 2 void t1() __attribute__((noinline)); @@ -7,3 +7,4 @@ { } +void (^t2)() = ^ __attribute__((noinline)) {}; Index: test/CodeGen/attr-optnone.c =================================================================== --- test/CodeGen/attr-optnone.c +++ test/CodeGen/attr-optnone.c @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -emit-llvm < %s > %t +// RUN: %clang_cc1 -emit-llvm -fblocks < %s > %t // RUN: FileCheck %s --check-prefix=PRESENT < %t // RUN: FileCheck %s --check-prefix=ABSENT < %t -// RUN: %clang_cc1 -emit-llvm -Os < %s > %t +// RUN: %clang_cc1 -emit-llvm -fblocks -Os < %s > %t // RUN: FileCheck %s --check-prefix=PRESENT < %t // RUN: FileCheck %s --check-prefix=OPTSIZE < %t -// RUN: %clang_cc1 -emit-llvm -Oz < %s > %t +// RUN: %clang_cc1 -emit-llvm -fblocks -Oz < %s > %t // RUN: FileCheck %s --check-prefix=PRESENT < %t // RUN: FileCheck %s --check-prefix=MINSIZE < %t @@ -23,9 +23,13 @@ // Also check that test2 is inlined into test4 (always_inline still works). // PRESENT-NOT: call i32 @test2 +int (^test5)() = ^ __attribute__((optnone)) { return 0; }; +// PRESENT-DAG: @test5_block_invoke{{.*}}[[ATTR5:#[0-9]+]] + // Check for both noinline and optnone on each optnone function. // PRESENT-DAG: attributes [[ATTR3]] = { {{.*}}noinline{{.*}}optnone{{.*}} } // PRESENT-DAG: attributes [[ATTR4]] = { {{.*}}noinline{{.*}}optnone{{.*}} } +// PRESENT-DAG: attributes [[ATTR5]] = { {{.*}}noinline{{.*}}optnone{{.*}} } // Check that no 'optsize' or 'minsize' attributes appear. // ABSENT-NOT: optsize Index: test/CodeGen/nonnull.c =================================================================== --- test/CodeGen/nonnull.c +++ test/CodeGen/nonnull.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm < %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm < %s | FileCheck %s // CHECK: define void @foo(i32* nonnull %x) void foo(int * __attribute__((nonnull)) x) { @@ -49,3 +49,6 @@ // CHECK: define void @bar8(i32* nonnull %a, i32* nonnull %b) void bar8(int *a, int *b) __attribute__((nonnull)) __attribute__((nonnull(1))) {} + +// CHECK: define internal void @blk_block_invoke(i8* %.block_descriptor, i32* nonnull %a) +void (^blk)(int *) = ^(int *a) __attribute__((nonnull)) {}; Index: test/Parser/cxx0x-attributes.cpp =================================================================== --- test/Parser/cxx0x-attributes.cpp +++ test/Parser/cxx0x-attributes.cpp @@ -305,7 +305,7 @@ [[attribute_declaration]]; // expected-warning {{unknown attribute 'attribute_declaration' ignored}} [[noreturn]]; // expected-error {{'noreturn' attribute only applies to functions}} -[[carries_dependency]]; // expected-error {{'carries_dependency' attribute only applies to functions, methods, and parameters}} +[[carries_dependency]]; // expected-error {{'carries_dependency' attribute only applies to functions, methods and parameters}} class A { A([[gnu::unused]] int a); Index: test/Sema/attr-capabilities.c =================================================================== --- test/Sema/attr-capabilities.c +++ test/Sema/attr-capabilities.c @@ -11,8 +11,8 @@ // Test an invalid capability name struct __attribute__((capability("wrong"))) IncorrectName {}; // expected-warning {{invalid capability name 'wrong'; capability name must be 'mutex' or 'role'}} -int Test1 __attribute__((capability("test1"))); // expected-error {{'capability' attribute only applies to structs, unions, and typedefs}} -int Test2 __attribute__((shared_capability("test2"))); // expected-error {{'shared_capability' attribute only applies to structs, unions, and typedefs}} +int Test1 __attribute__((capability("test1"))); // expected-error {{'capability' attribute only applies to structs, unions and typedefs}} +int Test2 __attribute__((shared_capability("test2"))); // expected-error {{'shared_capability' attribute only applies to structs, unions and typedefs}} int Test3 __attribute__((acquire_capability("test3"))); // expected-warning {{'acquire_capability' attribute only applies to functions}} int Test4 __attribute__((try_acquire_capability("test4"))); // expected-error {{'try_acquire_capability' attribute only applies to functions}} int Test5 __attribute__((release_capability("test5"))); // expected-warning {{'release_capability' attribute only applies to functions}} Index: test/Sema/attr-coldhot.c =================================================================== --- test/Sema/attr-coldhot.c +++ test/Sema/attr-coldhot.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fblocks -fsyntax-only -verify %s int foo() __attribute__((__hot__)); int bar() __attribute__((__cold__)); @@ -10,3 +10,6 @@ // expected-note{{conflicting attribute is here}} int baz() __attribute__((__cold__)) __attribute__((__hot__)); // expected-error{{'__cold__' and 'hot' attributes are not compatible}} \ // expected-note{{conflicting attribute is here}} + +enum { s = sizeof(^() __attribute__((__cold__)) __attribute__((__hot__)) {}) }; // expected-error{{'__cold__' and 'hot' attributes are not compatible}} \ +// expected-note{{conflicting attribute is here}} Index: test/Sema/attr-disable-tail-calls.c =================================================================== --- test/Sema/attr-disable-tail-calls.c +++ test/Sema/attr-disable-tail-calls.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s void __attribute__((disable_tail_calls,naked)) foo1(int a) { // expected-error {{'disable_tail_calls' and 'naked' attributes are not compatible}} expected-note {{conflicting attribute is here}} __asm__(""); @@ -8,6 +8,6 @@ __asm__(""); } -int g0 __attribute__((disable_tail_calls)); // expected-warning {{'disable_tail_calls' attribute only applies to functions and methods}} +int g0 __attribute__((disable_tail_calls)); // expected-warning {{'disable_tail_calls' attribute only applies to functions, methods and blocks}} int foo3(int a) __attribute__((disable_tail_calls("abc"))); // expected-error {{'disable_tail_calls' attribute takes no arguments}} Index: test/Sema/attr-malloc.c =================================================================== --- test/Sema/attr-malloc.c +++ test/Sema/attr-malloc.c @@ -1,12 +1,12 @@ -// RUN: %clang_cc1 -verify -fsyntax-only %s -// RUN: %clang_cc1 -emit-llvm -o %t %s +// RUN: %clang_cc1 -fblocks -verify -fsyntax-only %s +// RUN: %clang_cc1 -fblocks -emit-llvm -o %t %s #include // Declare malloc here explicitly so we don't depend on system headers. void * malloc(size_t) __attribute((malloc)); -int no_vars __attribute((malloc)); // expected-warning {{attribute only applies to functions}} +int no_vars __attribute((malloc)); // expected-warning {{attribute only applies to functions and blocks}} void returns_void (void) __attribute((malloc)); // expected-warning {{attribute only applies to return values that are pointers}} int returns_int (void) __attribute((malloc)); // expected-warning {{attribute only applies to return values that are pointers}} @@ -14,8 +14,12 @@ typedef int * iptr; iptr returns_iptr (void) __attribute((malloc)); // no-warning -__attribute((malloc)) void *(*f)(); // expected-warning{{attribute only applies to functions}} -__attribute((malloc)) int (*g)(); // expected-warning{{attribute only applies to functions}} +__attribute((malloc)) void *(*f)(); // expected-warning{{attribute only applies to functions and blocks}} +__attribute((malloc)) int (*g)(); // expected-warning{{attribute only applies to functions and blocks}} + +enum { s1 = sizeof(^ __attribute((malloc)) {}) }; // expected-warning {{attribute only applies to return values that are pointers}} +enum { s2 = sizeof(^() __attribute((malloc)) {}) }; // expected-warning {{attribute only applies to return values that are pointers}} +enum { s3 = sizeof(^void *() __attribute((malloc)) { return 0; }) }; // no-warning __attribute((malloc)) void * xalloc(unsigned n) { return malloc(n); } // no-warning Index: test/Sema/attr-minsize.c =================================================================== --- test/Sema/attr-minsize.c +++ test/Sema/attr-minsize.c @@ -1,5 +1,7 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s int foo() __attribute__((__minsize__)); -int var1 __attribute__((__minsize__)); // expected-error{{'__minsize__' attribute only applies to functions and methods}} +int var1 __attribute__((__minsize__)); // expected-error{{'__minsize__' attribute only applies to functions, methods and blocks}} + +void (^bar)() = ^ __attribute__((__minsize__)) {}; Index: test/Sema/attr-noinline.c =================================================================== --- test/Sema/attr-noinline.c +++ test/Sema/attr-noinline.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -verify -fsyntax-only +// RUN: %clang_cc1 %s -verify -fblocks -fsyntax-only int a __attribute__((noinline)); // expected-warning {{'noinline' attribute only applies to functions}} @@ -6,3 +6,4 @@ void t2() __attribute__((noinline(2))); // expected-error {{'noinline' attribute takes no arguments}} +void (^t3)() = ^ __attribute__((noinline)) {}; Index: test/Sema/nonnull.c =================================================================== --- test/Sema/nonnull.c +++ test/Sema/nonnull.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fblocks -fsyntax-only -verify %s // rdar://9584012 typedef struct { @@ -36,8 +36,8 @@ int test_int_returns_nonnull(void) __attribute__((returns_nonnull)); // expected-warning {{'returns_nonnull' attribute only applies to return values that are pointers}} void *test_ptr_returns_nonnull(void) __attribute__((returns_nonnull)); // no-warning -int i __attribute__((nonnull)); // expected-warning {{'nonnull' attribute only applies to functions, methods, and parameters}} -int j __attribute__((returns_nonnull)); // expected-warning {{'returns_nonnull' attribute only applies to functions and methods}} +int i __attribute__((nonnull)); // expected-warning {{'nonnull' attribute only applies to functions, methods, parameters and blocks}} +int j __attribute__((returns_nonnull)); // expected-warning {{'returns_nonnull' attribute only applies to functions, methods and blocks}} void *test_no_fn_proto() __attribute__((returns_nonnull)); // no-warning void *test_with_fn_proto(void) __attribute__((returns_nonnull)); // no-warning @@ -154,6 +154,12 @@ ; } +void (^block1)() = ^(int a) __attribute__((nonnull(2))) {}; // expected-error {{'nonnull' attribute parameter 1 is out of bounds}} +void (^block2)() = ^(int a) __attribute__((nonnull)) {}; // expected-warning {{'nonnull' attribute applied to function with no pointer arguments}} +void (^block3)() = ^() __attribute__((returns_nonnull)) {}; // expected-warning {{'returns_nonnull' attribute only applies to return values that are pointers}} +int (^block4)() = ^int() __attribute__((returns_nonnull)) { return 0; }; // expected-warning {{'returns_nonnull' attribute only applies to return values that are pointers}} +void *(^block5)() = ^() __attribute__((returns_nonnull)) { return (void *) 0; }; + __attribute__((returns_nonnull)) void *returns_nonnull_whee(); void returns_nonnull_warning_tests() { Index: test/SemaObjC/attr-cf_returns.m =================================================================== --- test/SemaObjC/attr-cf_returns.m +++ test/SemaObjC/attr-cf_returns.m @@ -10,8 +10,8 @@ #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) -int x CF_RETURNS_RETAINED; // expected-warning{{'cf_returns_retained' attribute only applies to functions, methods, and parameters}} -int y CF_RETURNS_NOT_RETAINED; // expected-warning{{'cf_returns_not_retained' attribute only applies to functions, methods, and parameters}} +int x CF_RETURNS_RETAINED; // expected-warning{{'cf_returns_retained' attribute only applies to functions, methods and parameters}} +int y CF_RETURNS_NOT_RETAINED; // expected-warning{{'cf_returns_not_retained' attribute only applies to functions, methods and parameters}} typedef struct __CFFoo *CFFooRef; Index: test/SemaObjC/objcbridge-attribute-arc.m =================================================================== --- test/SemaObjC/objcbridge-attribute-arc.m +++ test/SemaObjC/objcbridge-attribute-arc.m @@ -32,7 +32,7 @@ @interface I { - __attribute__((objc_bridge(NSError))) void * color; // expected-error {{'objc_bridge' attribute only applies to structs, unions, and typedefs}}; + __attribute__((objc_bridge(NSError))) void * color; // expected-error {{'objc_bridge' attribute only applies to structs, unions and typedefs}}; } @end Index: test/SemaObjC/objcbridge-attribute.m =================================================================== --- test/SemaObjC/objcbridge-attribute.m +++ test/SemaObjC/objcbridge-attribute.m @@ -38,7 +38,7 @@ @interface I { - __attribute__((objc_bridge(NSError))) void * color; // expected-error {{'objc_bridge' attribute only applies to structs, unions, and typedefs}}; + __attribute__((objc_bridge(NSError))) void * color; // expected-error {{'objc_bridge' attribute only applies to structs, unions and typedefs}}; } @end Index: utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2363,10 +2363,12 @@ case GenericRecord: return "(S.getLangOpts().CPlusPlus ? ExpectedStructOrUnionOrClass : " "ExpectedStructOrUnion)"; + case Func | Block: return "ExpectedFunctionOrBlock"; case Func | ObjCMethod | Block: return "ExpectedFunctionMethodOrBlock"; case Func | ObjCMethod | Class: return "ExpectedFunctionMethodOrClass"; case Func | Param: case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter"; + case Func | ObjCMethod | Block | Param: return "ExpectedFunctionMethodBlockOrParameter"; case Func | ObjCMethod: return "ExpectedFunctionOrMethod"; case Func | Var: return "ExpectedVariableOrFunction";