diff options
| author | Jordan Rose <jordan_rose@apple.com> | 2012-06-21 05:54:55 +0000 |
|---|---|---|
| committer | Jordan Rose <jordan_rose@apple.com> | 2012-06-21 05:54:55 +0000 |
| commit | 422080f547c0841d18a44d6395dc28e10c8ab467 (patch) | |
| tree | 567eceea8eaec0bfa705cbaa5f2bf0160a98d272 /clang/test | |
| parent | 815fe26ed35a0ff22b176c2c76bb0c0b2d9c16d9 (diff) | |
| download | bcm5719-llvm-422080f547c0841d18a44d6395dc28e10c8ab467.tar.gz bcm5719-llvm-422080f547c0841d18a44d6395dc28e10c8ab467.zip | |
Pretend that enum constants have enum type when inferring a block return type.
In C, enum constants have the type of the enum's underlying integer type,
rather than the type of the enum. (This is not true in C++.) This leads to
odd warnings when returning enum constants directly in blocks with inferred
return types. The easiest way out of this is to pretend that, like C++, enum
constants have enum type when being returned from a block.
<rdar://problem/11662489>
llvm-svn: 158899
Diffstat (limited to 'clang/test')
| -rw-r--r-- | clang/test/SemaObjC/blocks.m | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/clang/test/SemaObjC/blocks.m b/clang/test/SemaObjC/blocks.m index 7beec19ea78..a6a6a3b3684 100644 --- a/clang/test/SemaObjC/blocks.m +++ b/clang/test/SemaObjC/blocks.m @@ -73,3 +73,130 @@ void foo10() { NSLog(@"%@", myBlock); } + +// In C, enum constants have the type of the underlying integer type, not the +// enumeration they are part of. We pretend the constants have enum type when +// inferring block return types, so that they can be mixed-and-matched with +// other expressions of enum type. +enum CStyleEnum { + CSE_Value = 1 +}; +enum CStyleEnum getCSE(); +typedef enum CStyleEnum (^cse_block_t)(); + +void testCStyleEnumInference(bool arg) { + cse_block_t a; + + // No warnings here. + a = ^{ return CSE_Value; }; + a = ^{ return getCSE(); }; + + a = ^{ // expected-error {{incompatible block pointer types assigning to 'cse_block_t' (aka 'enum CStyleEnum (^)()') from 'int (^)(void)'}} + return 1; + }; + + // No warnings here. + a = ^{ if (arg) return CSE_Value; else return CSE_Value; }; + a = ^{ if (arg) return getCSE(); else return getCSE(); }; + a = ^{ if (arg) return CSE_Value; else return getCSE(); }; + a = ^{ if (arg) return getCSE(); else return CSE_Value; }; + + // Technically these two blocks should return 'int'. + // The first case is easy to handle -- just don't cast the enum constant + // to the enum type. However, the second guess would require going back + // and REMOVING the cast from the first return statement, which isn't really + // feasible (there may be more than one previous return statement with enum + // type). For symmetry, we just treat them the same way. + a = ^{ // expected-error {{incompatible block pointer types assigning to 'cse_block_t' (aka 'enum CStyleEnum (^)()') from 'int (^)(void)'}} + if (arg) + return 1; + else + return CSE_Value; // expected-error {{return type 'enum CStyleEnum' must match previous return type 'int'}} + }; + + a = ^{ + if (arg) + return CSE_Value; + else + return 1; // expected-error {{return type 'int' must match previous return type 'enum CStyleEnum'}} + }; +} + + +enum FixedTypeEnum : unsigned { + FTE_Value = 1U +}; +enum FixedTypeEnum getFTE(); +typedef enum FixedTypeEnum (^fte_block_t)(); + +void testFixedTypeEnumInference(bool arg) { + fte_block_t a; + + // No warnings here. + a = ^{ return FTE_Value; }; + a = ^{ return getFTE(); }; + + // Since we fixed the underlying type of the enum, this is considered a + // compatible block type. + a = ^{ + return 1U; + }; + + // No warnings here. + a = ^{ if (arg) return FTE_Value; else return FTE_Value; }; + a = ^{ if (arg) return getFTE(); else return getFTE(); }; + a = ^{ if (arg) return FTE_Value; else return getFTE(); }; + a = ^{ if (arg) return getFTE(); else return FTE_Value; }; + + // Technically these two blocks should return 'unsigned'. + // The first case is easy to handle -- just don't cast the enum constant + // to the enum type. However, the second guess would require going back + // and REMOVING the cast from the first return statement, which isn't really + // feasible (there may be more than one previous return statement with enum + // type). For symmetry, we just treat them the same way. + a = ^{ + if (arg) + return 1U; + else + return FTE_Value; // expected-error{{return type 'enum FixedTypeEnum' must match previous return type 'unsigned int'}} + }; + + a = ^{ + if (arg) + return FTE_Value; + else + return 1U; // expected-error{{return type 'unsigned int' must match previous return type 'enum FixedTypeEnum'}} + }; +} + + +enum { + AnonymousValue = 1 +}; + +enum : short { + FixedAnonymousValue = 1 +}; + +typedef enum { + TDE_Value +} TypeDefEnum; + +typedef enum : short { + TDFTE_Value +} TypeDefFixedTypeEnum; + + +typedef int (^int_block_t)(); +typedef short (^short_block_t)(); +void testAnonymousEnumTypes() { + int_block_t IB; + IB = ^{ return AnonymousValue; }; + IB = ^{ return TDE_Value; }; // expected-error {{incompatible block pointer types assigning to 'int_block_t' (aka 'int (^)()') from 'TypeDefEnum (^)(void)'}} + IB = ^{ return CSE_Value; }; // expected-error {{incompatible block pointer types assigning to 'int_block_t' (aka 'int (^)()') from 'enum CStyleEnum (^)(void)'}} + + short_block_t SB; + SB = ^{ return FixedAnonymousValue; }; + // This is not an error anyway since the enum has a fixed underlying type. + SB = ^{ return TDFTE_Value; }; +} |

