Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -8386,4 +8386,12 @@ "parameterized class %0 already conforms to the protocols listed; did you " "forget a '*'?">, InGroup; +def warn_block_literal_attributes_on_omitted_return_type : Warning< + "attribute %0 ignored, because it cannot be applied to omitted return type">, + InGroup; + +def warn_block_literal_qualifiers_on_omitted_return_type : Warning< + "'%0' qualifier on omitted return type %1 has no effect">, + InGroup; + } // end of sema component. Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -734,6 +734,7 @@ // it; they probably didn't mean to specify a redundant qualifier. typedef std::pair QualLoc; for (QualLoc Qual : {QualLoc(DeclSpec::TQ_const, DS.getConstSpecLoc()), + QualLoc(DeclSpec::TQ_restrict, DS.getRestrictSpecLoc()), QualLoc(DeclSpec::TQ_volatile, DS.getVolatileSpecLoc()), QualLoc(DeclSpec::TQ_atomic, DS.getAtomicSpecLoc())}) { if (!(RemoveTQs & Qual.first)) @@ -750,6 +751,47 @@ } } +/// Return true if this is omitted block return type. Also check type +/// attributes and type qualifiers when returning true. +static bool checkOmittedBlockReturnType(Sema &S, Declarator &declarator, + QualType Result) { + if (!isOmittedBlockReturnType(declarator)) + return false; + + // Warn if we see type attributes for omitted return type on a block literal. + AttributeList *&attrs = + declarator.getMutableDeclSpec().getAttributes().getListRef(); + AttributeList *prev = nullptr; + for (AttributeList *cur = attrs; cur; cur = cur->getNext()) { + AttributeList &attr = *cur; + // Skip attributes that were marked to be invalid or non-type + // attributes. + if (attr.isInvalid() || !attr.isTypeAttr()) { + prev = cur; + continue; + } + S.Diag(attr.getLoc(), + diag::warn_block_literal_attributes_on_omitted_return_type) + << attr.getName(); + // Remove cur from the list. + if (prev) { + prev->setNext(cur->getNext()); + prev = cur; + } else { + attrs = cur->getNext(); + } + } + + // Warn if we see type qualifiers for omitted return type on a block literal. + const DeclSpec &DS = declarator.getDeclSpec(); + unsigned TypeQuals = DS.getTypeQualifiers(); + diagnoseAndRemoveTypeQualifiers(S, DS, TypeQuals, Result, (unsigned)-1, + diag::warn_block_literal_qualifiers_on_omitted_return_type); + declarator.getMutableDeclSpec().ClearTypeQualifiers(); + + return true; +} + /// Apply Objective-C type arguments to the given type. static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, ArrayRef typeArgs, @@ -1251,7 +1293,8 @@ Result = Context.getAutoDeductType(); break; } else if (declarator.getContext() == Declarator::LambdaExprContext || - isOmittedBlockReturnType(declarator)) { + checkOmittedBlockReturnType(S, declarator, + Context.DependentTy)) { Result = Context.DependentTy; break; } Index: test/SemaObjC/block-omitted-return-type.m =================================================================== --- /dev/null +++ test/SemaObjC/block-omitted-return-type.m @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 %s -fblocks -verify -fsyntax-only + +@interface NSObject +@end + +@interface Test : NSObject +- (void)test; +@end + +@implementation Test +- (void)test +{ + void (^simpleBlock)() = ^ _Nonnull { //expected-warning {{attribute '_Nonnull' ignored, because it cannot be applied to omitted return type}} + return; + }; + void (^simpleBlock2)() = ^ _Nonnull void { //expected-error {{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'void'}} + return; + }; + void (^simpleBlock3)() = ^ _Nonnull (void) { //expected-warning {{attribute '_Nonnull' ignored, because it cannot be applied to omitted return type}} + return; + }; + + void (^simpleBlock4)() = ^ const { //expected-warning {{'const' qualifier on omitted return type '' has no effect}} + return; + }; + void (^simpleBlock5)() = ^ const void { //expected-error {{incompatible block pointer types initializing 'void (^)()' with an expression of type 'const void (^)(void)'}} + return; + }; + void (^simpleBlock6)() = ^ const (void) { //expected-warning {{'const' qualifier on omitted return type '' has no effect}} + return; + }; + void (^simpleBlock7)() = ^ _Nonnull __attribute__((align_value(128))) _Nullable const (void) { // expected-warning {{attribute '_Nullable' ignored, because it cannot be applied to omitted return type}} \ + // expected-warning {{attribute '_Nonnull' ignored, because it cannot be applied to omitted return type}} \ + // expected-warning {{'const' qualifier on omitted return type '' has no effect}} \ + // expected-warning {{'align_value' attribute only applies to variables and typedefs}} + return; + }; + void (^simpleBlock9)() = ^ __attribute__ ((align_value(128))) _Nonnull const (void) { // expected-warning {{attribute '_Nonnull' ignored, because it cannot be applied to omitted return type}} \ + // expected-warning {{'const' qualifier on omitted return type '' has no effect}} \ + // expected-warning {{'align_value' attribute only applies to variables and typedefs}} + return; + }; +} +@end Index: test/SemaOpenCL/invalid-block.cl =================================================================== --- test/SemaOpenCL/invalid-block.cl +++ test/SemaOpenCL/invalid-block.cl @@ -4,16 +4,15 @@ // All blocks declarations must be const qualified and initialized. void f1() { - int (^bl1)() = ^() {}; // expected-error{{invalid block variable declaration - must be const qualified}} + int (^bl1)() = ^() {return 1;}; // expected-error{{invalid block variable declaration - must be const qualified}} int (^const bl2)(); // expected-error{{invalid block variable declaration - must be initialized}} - int (^const bl3)() = ^const(){ - }; + int (^const bl3)() = ^(){return 1;}; } // A block with extern storage class is not allowed. -extern int (^const bl)() = ^const(){}; // expected-error{{invalid block variable declaration - using 'extern' storage class is disallowed}} +extern int (^const bl)() = ^(){return 1;}; // expected-error{{invalid block variable declaration - using 'extern' storage class is disallowed}} void f2() { - extern int (^const bl)() = ^const(){}; // expected-error{{invalid block variable declaration - using 'extern' storage class is disallowed}} + extern int (^const bl)() = ^(){return 1;}; // expected-error{{invalid block variable declaration - using 'extern' storage class is disallowed}} } // A block cannot be the return value of a function. @@ -29,22 +28,22 @@ } // A block with variadic argument is not allowed. -int (^const bl)(int, ...) = ^const int(int I, ...) { // expected-error {{invalid block prototype, variadic arguments are not allowed in OpenCL}} +int (^const bl)(int, ...) = ^int(int I, ...) { // expected-error {{invalid block prototype, variadic arguments are not allowed in OpenCL}} return 0; }; // A block can't be used to declare an array typedef int (^const bl1_t)(int); void f5(int i) { - bl1_t bl1 = ^const(int i) {return 1;}; - bl1_t bl2 = ^const(int i) {return 2;}; + bl1_t bl1 = ^(int i) {return 1;}; + bl1_t bl2 = ^(int i) {return 2;}; bl1_t arr[] = {bl1, bl2}; // expected-error {{array of 'bl1_t' (aka 'int (^const)(int)') type is invalid in OpenCL}} int tmp = i ? bl1(i) // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}} : bl2(i); // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}} } void f6(bl1_t * bl_ptr) { - bl1_t bl = ^const(int i) {return 1;}; + bl1_t bl = ^(int i) {return 1;}; bl1_t *p = &bl; // expected-error {{invalid argument type 'bl1_t' (aka 'int (^const)(int)') to unary expression}} bl = *bl_ptr; // expected-error {{dereferencing pointer of type '__generic bl1_t *' (aka 'int (^const __generic *)(int)') is not allowed in OpenCL}} }