manmanren created this revision.
manmanren added reviewers: rjmccall, Anastasia.
manmanren added a subscriber: cfe-commits.

A simple example will crash at IRGen:
void (^simpleBlock)() = ^ _Nonnull {
  return;
};

The Return type for the block will be AttributedType of a DependentTy and it 
will not be resolved. We will get a crash at IRGen.
The fix is to warn when we have type attributes or qualifiers with omitted 
return type. The type attributes and qualifiers will be ignored.
This breaks test/SemaOpenCL/invalid-block.cl where it uses "^const(){}".
"int (^const bl3)() = ^const(){};" should emit error since we are converting 
between incompatible block pointer types, the block literal's return type 
should be void. 

http://reviews.llvm.org/D18567

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaType.cpp
  test/SemaObjC/block-omitted-return-type.m
  test/SemaOpenCL/invalid-block.cl

Index: test/SemaObjC/block-omitted-return-type.m
===================================================================
--- /dev/null
+++ test/SemaObjC/block-omitted-return-type.m
@@ -0,0 +1,33 @@
+// 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 '<dependent 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 '<dependent type>' has no effect}}
+    return;
+  };
+}
+@end
Index: test/SemaOpenCL/invalid-block.cl
===================================================================
--- test/SemaOpenCL/invalid-block.cl
+++ test/SemaOpenCL/invalid-block.cl
@@ -6,14 +6,14 @@
 void f1() {
   int (^bl1)() = ^() {}; // 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)() = ^(){ // expected-error{{incompatible block pointer types initializing 'int (^const)()' with an expression of type 'void (^)(void)'}}
   };
 }
 
 // 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)() = ^(){}; // 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)() = ^(){}; // expected-error{{invalid block variable declaration - using 'extern' storage class is disallowed}}
 }
 
 // A block cannot be the return value of a function.
@@ -36,15 +36,15 @@
 // 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}}
 }
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -1552,6 +1552,25 @@
     break;
   }
 
+  // Warn if we see type attributes for omitted return type on a block literal.
+  if (isOmittedBlockReturnType(declarator)) {
+    if (auto *attrs = DS.getAttributes().getList()) {
+      while (attrs) {
+        AttributeList &attr = *attrs;
+        attrs = attr.getNext();
+        // Skip attributes that were marked to be invalid or non-type
+        // attributes.
+        if (attr.isInvalid() || !attr.isTypeAttr())
+          continue;
+        S.Diag(attr.getLoc(),
+               diag::warn_block_literal_attributes_on_omitted_return_type)
+            << attr.getName();
+        // Mark them as invalid.
+        attr.setInvalid();
+      }
+    }
+  }
+
   // Handle complex types.
   if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) {
     if (S.getLangOpts().Freestanding)
@@ -1586,6 +1605,13 @@
 
   // Apply const/volatile/restrict qualifiers to T.
   if (unsigned TypeQuals = DS.getTypeQualifiers()) {
+    // Warn if we see type qualifiers for omitted return type on a block literal.
+    if (TypeQuals && isOmittedBlockReturnType(declarator)) {
+      diagnoseAndRemoveTypeQualifiers(S, DS, TypeQuals, Result,
+          DeclSpec::TQ_const | DeclSpec::TQ_volatile | DeclSpec::TQ_atomic,
+          diag::warn_block_literal_qualifiers_on_omitted_return_type);
+    }
+
     // Warn about CV qualifiers on function types.
     // C99 6.7.3p8:
     //   If the specification of a function type includes any type qualifiers,
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<ObjCProtocolQualifiers>;
 
+def warn_block_literal_attributes_on_omitted_return_type : Warning<
+  "attribute %0 ignored, because it cannot be applied to omitted return type">,
+  InGroup<IgnoredAttributes>;
+
+def warn_block_literal_qualifiers_on_omitted_return_type : Warning<
+  "'%0' qualifier on omitted return type %1 has no effect">,
+  InGroup<IgnoredQualifiers>;
+
 } // end of sema component.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to