aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2013-03-21 00:10:07 +0000
committerJohn McCall <rjmccall@apple.com>2013-03-21 00:10:07 +0000
commitb9da713efb4277753211590953f433723908aade (patch)
treec5f4fcdca4ff986302d7e505340bce3f67d9d69b
parentb79f589f51da22c13ed5e1d00258236e7e8f555f (diff)
Further weaken block conversion rules to permit blocks with
enum return type to be converted to blocks with any integer type of the same size. rdar://13463504 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177613 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/AST/ASTContext.cpp35
-rw-r--r--test/Sema/block-return.c11
-rw-r--r--test/SemaObjC/blocks.m4
3 files changed, 38 insertions, 12 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index b55a926e32..eee7ed2fb8 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -6844,6 +6844,27 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
return getFunctionNoProtoType(retType, einfo);
}
+/// Given that we have an enum type and a non-enum type, try to merge them.
+static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET,
+ QualType other, bool isBlockReturnType) {
+ // C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
+ // a signed integer type, or an unsigned integer type.
+ // Compatibility is based on the underlying type, not the promotion
+ // type.
+ QualType underlyingType = ET->getDecl()->getIntegerType();
+ if (underlyingType.isNull()) return QualType();
+ if (Context.hasSameType(underlyingType, other))
+ return other;
+
+ // In block return types, we're more permissive and accept any
+ // integral type of the same size.
+ if (isBlockReturnType && other->isIntegerType() &&
+ Context.getTypeSize(underlyingType) == Context.getTypeSize(other))
+ return other;
+
+ return QualType();
+}
+
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
bool OfBlockPointer,
bool Unqualified, bool BlockReturnType) {
@@ -6925,19 +6946,13 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
// If the canonical type classes don't match.
if (LHSClass != RHSClass) {
- // C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
- // a signed integer type, or an unsigned integer type.
- // Compatibility is based on the underlying type, not the promotion
- // type.
+ // Note that we only have special rules for turning block enum
+ // returns into block int returns, not vice-versa.
if (const EnumType* ETy = LHS->getAs<EnumType>()) {
- QualType TINT = ETy->getDecl()->getIntegerType();
- if (!TINT.isNull() && hasSameType(TINT, RHSCan.getUnqualifiedType()))
- return RHS;
+ return mergeEnumWithInteger(*this, ETy, RHS, false);
}
if (const EnumType* ETy = RHS->getAs<EnumType>()) {
- QualType TINT = ETy->getDecl()->getIntegerType();
- if (!TINT.isNull() && hasSameType(TINT, LHSCan.getUnqualifiedType()))
- return LHS;
+ return mergeEnumWithInteger(*this, ETy, LHS, BlockReturnType);
}
// allow block pointer type to match an 'id' type.
if (OfBlockPointer && !BlockReturnType) {
diff --git a/test/Sema/block-return.c b/test/Sema/block-return.c
index 2ea4d813ab..6b4d99830c 100644
--- a/test/Sema/block-return.c
+++ b/test/Sema/block-return.c
@@ -134,3 +134,14 @@ void foo7()
void (^blk)(void) = ^{
return (void)0; // expected-warning {{void block literal should not return void expression}}
};
+
+// rdar://13463504
+enum Test8 { T8_a, T8_b, T8_c };
+void test8(void) {
+ extern void test8_helper(int (^)(int));
+ test8_helper(^(int flag) { if (flag) return T8_a; return T8_b; });
+}
+void test8b(void) {
+ extern void test8_helper2(char (^)(int)); // expected-note {{here}}
+ test8_helper2(^(int flag) { if (flag) return T8_a; return T8_b; }); // expected-error {{passing 'enum Test8 (^)(int)' to parameter of type 'char (^)(int)'}}
+}
diff --git a/test/SemaObjC/blocks.m b/test/SemaObjC/blocks.m
index dd659addef..b523e4c916 100644
--- a/test/SemaObjC/blocks.m
+++ b/test/SemaObjC/blocks.m
@@ -196,8 +196,8 @@ typedef short (^short_block_t)();
void testAnonymousEnumTypes(int arg) {
int_block_t IB;
IB = ^{ return AnonymousValue; };
- IB = ^{ if (arg) return TDE_Value; else return getTDE(); }; // expected-error {{incompatible block pointer}}
- IB = ^{ if (arg) return getTDE(); else return TDE_Value; }; // expected-error {{incompatible block pointer}}
+ IB = ^{ if (arg) return TDE_Value; else return getTDE(); };
+ IB = ^{ if (arg) return getTDE(); else return TDE_Value; };
// Since we fixed the underlying type of the enum, these are considered
// compatible block types anyway.