[cfe-commits] r71145 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaExpr.cpp test/Sema/block-misc.c test/SemaObjC/conditional-expr-2.m

Mike Stump mrs at apple.com
Wed May 6 20:14:17 PDT 2009


Author: mrs
Date: Wed May  6 22:14:14 2009
New Revision: 71145

URL: http://llvm.org/viewvc/llvm-project?rev=71145&view=rev
Log:
Improve semantic checking for blocks.  Radar 6441502

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/Sema/block-misc.c
    cfe/trunk/test/SemaObjC/conditional-expr-2.m

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=71145&r1=71144&r2=71145&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed May  6 22:14:14 2009
@@ -1039,6 +1039,8 @@
   "comparison between pointer and integer (%0 and %1)">;
 def ext_typecheck_comparison_of_distinct_pointers : Warning<
   "comparison of distinct pointer types (%0 and %1)">;
+def ext_typecheck_cond_incompatible_operands : Warning<
+  "incompatible operand types (%0 and %1)">;
 def err_typecheck_comparison_of_distinct_pointers : Error<
   "comparison of distinct pointer types (%0 and %1)">;
 def err_typecheck_vector_comparison : Error<

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=71145&r1=71144&r2=71145&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed May  6 22:14:14 2009
@@ -2786,99 +2786,113 @@
     return RHSTy;
   }
 
+  const PointerType *LHSPT = LHSTy->getAsPointerType();
+  const PointerType *RHSPT = RHSTy->getAsPointerType();
+  const BlockPointerType *LHSBPT = LHSTy->getAsBlockPointerType();
+  const BlockPointerType *RHSBPT = RHSTy->getAsBlockPointerType();
+
   // 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 = LHSTy->getAsPointerType()) { // C99 6.5.15p3,6
-    if (const PointerType *RHSPT = RHSTy->getAsPointerType()) {
-      // get the "pointed to" types
-      QualType lhptee = LHSPT->getPointeeType();
-      QualType rhptee = RHSPT->getPointeeType();
-
-      // ignore qualifiers on void (C99 6.5.15p3, clause 6)
-      if (lhptee->isVoidType() &&
-          rhptee->isIncompleteOrObjectType()) {
-        // Figure out necessary qualifiers (C99 6.5.15p6)
-        QualType destPointee=lhptee.getQualifiedType(rhptee.getCVRQualifiers());
-        QualType destType = Context.getPointerType(destPointee);
-        ImpCastExprToType(LHS, destType); // add qualifiers if necessary
-        ImpCastExprToType(RHS, destType); // promote to void*
-        return destType;
-      }
-      if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) {
-        QualType destPointee=rhptee.getQualifiedType(lhptee.getCVRQualifiers());
-        QualType destType = Context.getPointerType(destPointee);
-        ImpCastExprToType(LHS, destType); // add qualifiers if necessary
-        ImpCastExprToType(RHS, destType); // promote to void*
-        return destType;
-      }
-
-      if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
-        // Two identical pointer types are always compatible.
-        return LHSTy;
-      }
-
-      QualType compositeType = LHSTy;
-
-      // If either type is an Objective-C object type then check
-      // compatibility according to Objective-C.
-      if (Context.isObjCObjectPointerType(LHSTy) ||
-          Context.isObjCObjectPointerType(RHSTy)) {
-        // If both operands are interfaces and either operand can be
-        // assigned to the other, use that type as the composite
-        // type. This allows
-        //   xxx ? (A*) a : (B*) b
-        // where B is a subclass of A.
-        //
-        // Additionally, as for assignment, if either type is 'id'
-        // allow silent coercion. Finally, if the types are
-        // incompatible then make sure to use 'id' as the composite
-        // type so the result is acceptable for sending messages to.
-
-        // FIXME: Consider unifying with 'areComparableObjCPointerTypes'.
-        // It could return the composite type.
-        const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType();
-        const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType();
-        if (LHSIface && RHSIface &&
-            Context.canAssignObjCInterfaces(LHSIface, RHSIface)) {
-          compositeType = LHSTy;
-        } else if (LHSIface && RHSIface &&
-                   Context.canAssignObjCInterfaces(RHSIface, LHSIface)) {
-          compositeType = RHSTy;
-        } else if (Context.isObjCIdStructType(lhptee) ||
-                   Context.isObjCIdStructType(rhptee)) {
-          compositeType = Context.getObjCIdType();
-        } else {
-          Diag(QuestionLoc, diag::ext_typecheck_comparison_of_distinct_pointers)
-               << LHSTy << RHSTy
-               << LHS->getSourceRange() << RHS->getSourceRange();
-          QualType incompatTy = Context.getObjCIdType();
-          ImpCastExprToType(LHS, incompatTy);
-          ImpCastExprToType(RHS, incompatTy);
-          return incompatTy;
-        }
-      } else if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
-                                             rhptee.getUnqualifiedType())) {
-        Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
-          << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
-        // In this situation, we assume void* type. No especially good
-        // reason, but this is what gcc does, and we do have to pick
-        // to get a consistent AST.
-        QualType incompatTy = Context.getPointerType(Context.VoidTy);
+  if ((LHSPT || LHSBPT) && (RHSPT || RHSBPT)) { // C99 6.5.15p3,6
+    // get the "pointed to" types
+    QualType lhptee = LHSPT ? LHSPT->getPointeeType() : LHSBPT->getPointeeType();
+    QualType rhptee = RHSPT ? RHSPT->getPointeeType() : RHSBPT->getPointeeType();
+
+    // ignore qualifiers on void (C99 6.5.15p3, clause 6)
+    if (lhptee->isVoidType()
+        && (RHSBPT || rhptee->isIncompleteOrObjectType())) {
+      // Figure out necessary qualifiers (C99 6.5.15p6)
+      QualType destPointee=lhptee.getQualifiedType(rhptee.getCVRQualifiers());
+      QualType destType = Context.getPointerType(destPointee);
+      ImpCastExprToType(LHS, destType); // add qualifiers if necessary
+      ImpCastExprToType(RHS, destType); // promote to void*
+      return destType;
+    }
+    if (rhptee->isVoidType()
+        && (LHSBPT || lhptee->isIncompleteOrObjectType())) {
+      QualType destPointee=rhptee.getQualifiedType(lhptee.getCVRQualifiers());
+      QualType destType = Context.getPointerType(destPointee);
+      ImpCastExprToType(LHS, destType); // add qualifiers if necessary
+      ImpCastExprToType(RHS, destType); // promote to void*
+      return destType;
+    }
+
+    bool sameKind = (LHSPT && RHSPT) || (LHSBPT && RHSBPT);
+    if (sameKind
+        && Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
+      // Two identical pointer types are always compatible.
+      return LHSTy;
+    }
+
+    QualType compositeType = LHSTy;
+
+    // If either type is an Objective-C object type then check
+    // compatibility according to Objective-C.
+    if (Context.isObjCObjectPointerType(LHSTy) ||
+        Context.isObjCObjectPointerType(RHSTy)) {
+      // If both operands are interfaces and either operand can be
+      // assigned to the other, use that type as the composite
+      // type. This allows
+      //   xxx ? (A*) a : (B*) b
+      // where B is a subclass of A.
+      //
+      // Additionally, as for assignment, if either type is 'id'
+      // allow silent coercion. Finally, if the types are
+      // incompatible then make sure to use 'id' as the composite
+      // type so the result is acceptable for sending messages to.
+
+      // FIXME: Consider unifying with 'areComparableObjCPointerTypes'.
+      // It could return the composite type.
+      const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType();
+      const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType();
+      if (LHSIface && RHSIface &&
+          Context.canAssignObjCInterfaces(LHSIface, RHSIface)) {
+        compositeType = LHSTy;
+      } else if (LHSIface && RHSIface &&
+                 Context.canAssignObjCInterfaces(RHSIface, LHSIface)) {
+        compositeType = RHSTy;
+      } else if (Context.isObjCIdStructType(lhptee) ||
+                 Context.isObjCIdStructType(rhptee)) {
+        compositeType = Context.getObjCIdType();
+      } else if (LHSBPT || RHSBPT) {
+        if (!sameKind
+            || !Context.typesAreBlockCompatible(lhptee.getUnqualifiedType(),
+                                                rhptee.getUnqualifiedType()))
+          Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
+            << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
+        return QualType();
+      } else {
+        Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands)
+          << LHSTy << RHSTy
+          << LHS->getSourceRange() << RHS->getSourceRange();
+        QualType incompatTy = Context.getObjCIdType();
         ImpCastExprToType(LHS, incompatTy);
         ImpCastExprToType(RHS, incompatTy);
         return incompatTy;
       }
-      // The pointer types are compatible.
-      // C99 6.5.15p6: If both operands are pointers to compatible types *or* to
-      // differently qualified versions of compatible types, the result type is
-      // a pointer to an appropriately qualified version of the *composite*
-      // type.
-      // FIXME: Need to calculate the composite type.
-      // FIXME: Need to add qualifiers
-      ImpCastExprToType(LHS, compositeType);
-      ImpCastExprToType(RHS, compositeType);
-      return compositeType;
-    }
+    } else if (!sameKind
+               || !Context.typesAreCompatible(lhptee.getUnqualifiedType(),
+                                              rhptee.getUnqualifiedType())) {
+      Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
+        << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
+      // In this situation, we assume void* type. No especially good
+      // reason, but this is what gcc does, and we do have to pick
+      // to get a consistent AST.
+      QualType incompatTy = Context.getPointerType(Context.VoidTy);
+      ImpCastExprToType(LHS, incompatTy);
+      ImpCastExprToType(RHS, incompatTy);
+      return incompatTy;
+    }
+    // The pointer types are compatible.
+    // C99 6.5.15p6: If both operands are pointers to compatible types *or* to
+    // differently qualified versions of compatible types, the result type is
+    // a pointer to an appropriately qualified version of the *composite*
+    // type.
+    // FIXME: Need to calculate the composite type.
+    // FIXME: Need to add qualifiers
+    ImpCastExprToType(LHS, compositeType);
+    ImpCastExprToType(RHS, compositeType);
+    return compositeType;
   }
 
   // GCC compatibility: soften pointer/integer mismatch.
@@ -2895,11 +2909,6 @@
     return LHSTy;
   }
 
-  // Selection between block pointer types is ok as long as they are the same.
-  if (LHSTy->isBlockPointerType() && RHSTy->isBlockPointerType() &&
-      Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy))
-    return LHSTy;
-
   // Need to handle "id<xx>" explicitly. Unlike "id", whose canonical type
   // evaluates to "struct objc_object *" (and is handled above when comparing
   // id with statically typed objects).
@@ -3671,7 +3680,7 @@
   QualType lType = lex->getType();
   QualType rType = rex->getType();
 
-  if (!lType->isFloatingType()) {
+  if (!lType->isFloatingType() && !(lType->isBlockPointerType() && isRelational)) {
     // For non-floating point types, check for self-comparisons of the form
     // x == x, x != x, x < x, etc.  These always evaluate to a constant, and
     // often indicate logic errors in the program.
@@ -3795,7 +3804,7 @@
     return ResultTy;
   }
   // Handle block pointer types.
-  if (lType->isBlockPointerType() && rType->isBlockPointerType()) {
+  if (!isRelational && lType->isBlockPointerType() && rType->isBlockPointerType()) {
     QualType lpointee = lType->getAsBlockPointerType()->getPointeeType();
     QualType rpointee = rType->getAsBlockPointerType()->getPointeeType();
 
@@ -3808,11 +3817,16 @@
     return ResultTy;
   }
   // Allow block pointers to be compared with null pointer constants.
-  if ((lType->isBlockPointerType() && rType->isPointerType()) ||
-      (lType->isPointerType() && rType->isBlockPointerType())) {
+  if (!isRelational
+      && ((lType->isBlockPointerType() && rType->isPointerType())
+          || (lType->isPointerType() && rType->isBlockPointerType()))) {
     if (!LHSIsNull && !RHSIsNull) {
-      Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
-        << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+      if (!((rType->isPointerType() && rType->getAsPointerType()
+             ->getPointeeType()->isVoidType())
+            || (lType->isPointerType() && lType->getAsPointerType()
+                ->getPointeeType()->isVoidType())))
+        Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
+          << lType << rType << lex->getSourceRange() << rex->getSourceRange();
     }
     ImpCastExprToType(rex, lType); // promote the pointer to pointer
     return ResultTy;
@@ -3867,14 +3881,20 @@
   }
   // Handle block pointers.
   if (lType->isBlockPointerType() && rType->isIntegerType()) {
-    if (!RHSIsNull)
+    if (isRelational)
+      Diag(Loc, diag::err_typecheck_invalid_operands)
+        << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+    else if (!RHSIsNull)
       Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
         << lType << rType << lex->getSourceRange() << rex->getSourceRange();
     ImpCastExprToType(rex, lType); // promote the integer to pointer
     return ResultTy;
   }
   if (lType->isIntegerType() && rType->isBlockPointerType()) {
-    if (!LHSIsNull)
+    if (isRelational)
+      Diag(Loc, diag::err_typecheck_invalid_operands)
+        << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+    else if (!LHSIsNull)
       Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
         << lType << rType << lex->getSourceRange() << rex->getSourceRange();
     ImpCastExprToType(lex, rType); // promote the integer to pointer

Modified: cfe/trunk/test/Sema/block-misc.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/block-misc.c?rev=71145&r1=71144&r2=71145&view=diff

==============================================================================
--- cfe/trunk/test/Sema/block-misc.c (original)
+++ cfe/trunk/test/Sema/block-misc.c Wed May  6 22:14:14 2009
@@ -156,3 +156,19 @@
   __block int a[size]; // expected-error {{__block attribute not allowed on declaration with a variably modified type}}
   __block int (*ap)[size]; // expected-error {{__block attribute not allowed on declaration with a variably modified type}}
 }
+
+void test17() {
+  void (^bp)(int);
+  void (*rp)(int);
+  void (^bp1)();
+  void *vp = bp;
+
+  f(1 ? bp : vp);
+  f(1 ? vp : bp);
+  f(1 ? bp : bp1); // expected-error {{incompatible operand types ('void (^)(int)' and 'void (^)()')}}
+  (void)(bp > rp); // expected-error {{invalid operands}}
+  (void)(bp > 0); // expected-error {{invalid operands}}
+  (void)(bp > bp); // expected-error {{invalid operands}}
+  (void)(bp > vp); // expected-error {{invalid operands}}
+  f(1 ? bp : rp); // expected-error {{incompatible operand types ('void (^)(int)' and 'void (*)(int)')}}
+}

Modified: cfe/trunk/test/SemaObjC/conditional-expr-2.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/conditional-expr-2.m?rev=71145&r1=71144&r2=71145&view=diff

==============================================================================
--- cfe/trunk/test/SemaObjC/conditional-expr-2.m (original)
+++ cfe/trunk/test/SemaObjC/conditional-expr-2.m Wed May  6 22:14:14 2009
@@ -8,7 +8,7 @@
 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{{comparison of distinct pointer types ('A *' and 'B *')}} expected-warning {{method '-test' not found}}
+  [ (cond ? a : b) test ]; // expected-warning{{incompatible operand types ('A *' and 'B *')}} expected-warning {{method '-test' not found}}
 }
 
 @interface NSKey @end
@@ -22,8 +22,8 @@
   NSKey *key;
   KeySub *keysub;
 
-  obj = i ? NSKeyValueCoding_NullValue : nukedUpdatesList; // expected-warning{{comparison of distinct pointer types ('NSKey *' and 'UpdatesList *')}}
-  key = i ? NSKeyValueCoding_NullValue : nukedUpdatesList; // expected-warning{{comparison of distinct pointer types ('NSKey *' and 'UpdatesList *')}}
+  obj = i ? NSKeyValueCoding_NullValue : nukedUpdatesList; // expected-warning{{incompatible operand types ('NSKey *' and 'UpdatesList *')}}
+  key = i ? NSKeyValueCoding_NullValue : nukedUpdatesList; // expected-warning{{incompatible operand types ('NSKey *' and 'UpdatesList *')}}
   key = i ? NSKeyValueCoding_NullValue : keysub;
   keysub = i ? NSKeyValueCoding_NullValue : keysub; // expected-warning{{incompatible pointer types assigning 'NSKey *', expected 'KeySub *'}}
 }





More information about the cfe-commits mailing list