comex created this revision. comex added a subscriber: cfe-commits. Herald added a subscriber: aemerson.
This mostly "just works" by adding Block to the subject list, but there is an issue with warnings in attribute handlers tied to the return type, which for blocks can be inferred. My solution to this is a bit ugly but seems to do the right thing. The list: always_inline, noinline, cold, hot, minsize, malloc, disable_tail_calls, noalias, noduplicate, nonnull, returns_nonnull, optnone. nonnull already partially worked on blocks, but fix applying it to parameters on them; also, improve the error message and add additional tests. Most of these attributes only make sense when the target of a function call is known; since blocks are always called indirectly via pointers, these will only work if the optimizer is able to replace the indirect calls with direct calls (ergo not at all at -O0). However, this can still be useful in practice. For now, all of them only apply to the block implementation function itself, as opposed to the copy and dispose helpers. For those it might make sense to propagate always_inline in particular, or perhaps to just add some explicit syntax for putting attributes on them, but it's not essential. Incidentally, for some of these attributes and some not included, such as returns_nonnull, printf, warn_unused_result, etc., it would be somewhat useful and more principled to allow them as part of function types rather than just functions themselves, for the sake of both standard function pointer calls and blocks. Currently only a handful of attributes can be used on types: noreturn, ns_returns_retained, regparm, and calling convention. However, that would be a larger change and orthogonal to this patch. http://reviews.llvm.org/D15907 Files: include/clang/Basic/Attr.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Parser.h include/clang/Sema/AttributeList.h include/clang/Sema/Sema.h lib/Parse/ParseExpr.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaExpr.cpp lib/Sema/TreeTransform.h test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p1.cpp test/CodeGen/always-inline.c test/CodeGen/attr-disable-tail-calls.c test/CodeGen/attr-noinline.c test/CodeGen/attr-optnone.c test/CodeGen/nonnull.c test/Parser/cxx0x-attributes.cpp test/Sema/attr-capabilities.c test/Sema/attr-coldhot.c test/Sema/attr-disable-tail-calls.c test/Sema/attr-malloc.c test/Sema/attr-minsize.c test/Sema/attr-noinline.c test/Sema/nonnull.c test/SemaObjC/attr-cf_returns.m test/SemaObjC/objcbridge-attribute-arc.m test/SemaObjC/objcbridge-attribute.m utils/TableGen/ClangAttrEmitter.cpp
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"; 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: 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/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/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/Sema/attr-noinline.c =================================================================== --- test/Sema/attr-noinline.c +++ test/Sema/attr-noinline.c @@ -1,8 +1,9 @@ -// 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}} void t1() __attribute__((noinline)); void t2() __attribute__((noinline(2))); // expected-error {{'noinline' attribute takes no arguments}} +void (^t3)() = ^ __attribute__((noinline)) {}; 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-malloc.c =================================================================== --- test/Sema/attr-malloc.c +++ test/Sema/attr-malloc.c @@ -1,21 +1,25 @@ -// 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 <stddef.h> // 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}} int * returns_intptr(void) __attribute((malloc)); // no-warning 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-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-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-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/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/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/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/attr-noinline.c =================================================================== --- test/CodeGen/attr-noinline.c +++ test/CodeGen/attr-noinline.c @@ -1,9 +1,10 @@ -// 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)); void t1() { } +void (^t2)() = ^ __attribute__((noinline)) {}; 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/always-inline.c =================================================================== --- test/CodeGen/always-inline.c +++ test/CodeGen/always-inline.c @@ -1,15 +1,23 @@ // 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(); } 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/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: 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<typename Derived> 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<NoReturnAttr>(); QualType BlockTy; Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -111,6 +111,10 @@ return cast<ObjCMethodDecl>(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<FunctionDecl>(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<MayAliasAttr>(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,22 +5650,26 @@ /// 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: // int *__attr__(x)** D; // 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/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: 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: 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/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/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2425,16 +2425,18 @@ 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|" "types and namespaces|Objective-C interfaces|methods and properties|" "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<IgnoredAttributes>; def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>; 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]; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits