From 40727a4b43d827319553620fa1183f4bcb346d2d Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 3 Sep 2008 17:53:25 +0000 Subject: [PATCH] Improve type-checking of ?: for Objective-C types. - Allow any Objective-C object types to devolve to type id in a ?: expression. This matches gcc behavior more closely. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55705 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaExpr.cpp | 29 +++++---- ...nditional-expr2.m => conditional-expr-2.m} | 2 +- test/SemaObjC/conditional-expr-3.m | 63 +++++++++++++++++++ test/SemaObjC/conditional-expr.m | 4 +- 4 files changed, 83 insertions(+), 15 deletions(-) rename test/SemaObjC/{conditional-expr2.m => conditional-expr-2.m} (63%) create mode 100644 test/SemaObjC/conditional-expr-3.m diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 479c8412fd..7886976aaf 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1252,6 +1252,23 @@ inline QualType Sema::CheckConditionalOperands( // C99 6.5.15 ImpCastExprToType(lex, rexT); // promote the null to a pointer. return rexT; } + // Allow any Objective-C types to devolve to id type. + // FIXME: This seems to match gcc behavior, although that is very + // arguably incorrect. For example, (xxx ? (id

) : (id

)) has + // type id, which seems broken. + if (Context.isObjCObjectPointerType(lexT) && + Context.isObjCObjectPointerType(rexT)) { + // FIXME: This is not the correct composite type. This only + // happens to work because id can more or less be used anywhere, + // however this may change the type of method sends. + // FIXME: gcc adds some type-checking of the arguments and emits + // (confusing) incompatible comparison warnings in some + // cases. Investigate. + QualType compositeType = Context.getObjCIdType(); + ImpCastExprToType(lex, compositeType); + ImpCastExprToType(rex, compositeType); + return compositeType; + } // Handle the case where both operands are pointers before we handle null // pointer constants in case both operands are null pointer constants. if (const PointerType *LHSPT = lexT->getAsPointerType()) { // C99 6.5.15p3,6 @@ -1312,18 +1329,6 @@ inline QualType Sema::CheckConditionalOperands( // C99 6.5.15 return compositeType; } } - // Need to handle "id" explicitly. Unlike "id", whose canonical type - // evaluates to "struct objc_object *" (and is handled above when comparing - // id with statically typed objects). - if (lexT->isObjCQualifiedIdType() || rexT->isObjCQualifiedIdType()) { - if (ObjCQualifiedIdTypesAreCompatible(lexT, rexT, true)) { - // FIXME: This is not the correct composite type. - QualType compositeType = Context.getObjCIdType(); - ImpCastExprToType(lex, compositeType); - ImpCastExprToType(rex, compositeType); - return compositeType; - } - } // Otherwise, the operands are not compatible. Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands, lexT.getAsString(), rexT.getAsString(), diff --git a/test/SemaObjC/conditional-expr2.m b/test/SemaObjC/conditional-expr-2.m similarity index 63% rename from test/SemaObjC/conditional-expr2.m rename to test/SemaObjC/conditional-expr-2.m index 440b72d9a2..d8a2663093 100644 --- a/test/SemaObjC/conditional-expr2.m +++ b/test/SemaObjC/conditional-expr-2.m @@ -8,5 +8,5 @@ void f0(int cond, A *a, B *b) { // Ensure that we can still send a message to result of incompatible // conditional expression. - [ (cond ? a : b) test ]; // expected-warning {{pointer type mismatch}}, expected-warning {{method '-test' not found}} + [ (cond ? a : b) test ]; // expected-warning {{method '-test' not found}} } diff --git a/test/SemaObjC/conditional-expr-3.m b/test/SemaObjC/conditional-expr-3.m new file mode 100644 index 0000000000..de7b828a98 --- /dev/null +++ b/test/SemaObjC/conditional-expr-3.m @@ -0,0 +1,63 @@ +// RUN: clang -fsyntax-only -verify %s + +@protocol P0 +@end +@protocol P1 +@end +@protocol P2 +@end + +@interface A +@end + +@interface B : A +@end + +void bar(id x); +void barP0(id x); +void barP1(id x); +void barP2(id x); + +void f0(A *a) { + id l = a; +} + +void f1(id x, A *a) { + id l = a; +} + +void f2(id x) { + id l = x; // expected-error {{incompatible type initializing 'id', expected 'id'}} +} + +void f3(A *a) { + id l = a; // expected-error {{incompatible type initializing 'A *', expected 'id'}} +} + +void f4(int cond, id x, A *a) { + bar(cond ? x : a); +} + +void f5(int cond, A *a, B *b) { + bar(cond ? a : b); +} + +void f6(int cond, id x, A *a) { + bar(cond ? (id) x : a); +} + +void f7(int cond, id x, A *a) { + bar(cond ? a : (id) x); +} + +void f8(int cond, id x0, id x1) { + barP0(cond ? x0 : x1); +} + +void f9(int cond, id x0, id x1) { + barP1(cond ? x0 : x1); +} + +void f10(int cond, id x0, id x1) { + barP2(cond ? x0 : x1); +} diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m index e3cd041d3a..2884fb4c98 100644 --- a/test/SemaObjC/conditional-expr.m +++ b/test/SemaObjC/conditional-expr.m @@ -29,7 +29,7 @@ id nextOutputStream = [self nextOutputStream]; // GCC warns about both of these. self = nextOutputStream; // expected-error {{incompatible type assigning 'id', expected 'DTFilterOutputStream2 *'}} - return nextOutputStream ? nextOutputStream : self; // expected-error {{incompatible operand types ('id' and 'DTFilterOutputStream2 *')}} + return nextOutputStream ? nextOutputStream : self; } @end @@ -39,6 +39,6 @@ id nextOutputStream = [self nextOutputStream]; // GCC warns about both of these as well (no errors). self = nextOutputStream; // expected-error {{incompatible type assigning 'id', expected 'DTFilterOutputStream3 *'}} - return nextOutputStream ? nextOutputStream : self; // expected-error {{incompatible operand types ('id' and 'DTFilterOutputStream3 *')}} + return nextOutputStream ? nextOutputStream : self; } @end -- 2.40.0