[cfe-commits] r55158 - in /cfe/trunk: include/clang/AST/ASTContext.h lib/AST/ASTContext.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp

Daniel Dunbar daniel at zuster.org
Fri Aug 22 11:47:37 PDT 2008


I believe this or a related commit is causing regressions in the LLVM test
suite. My nightly tester (http://llvm.org/nightlytest/test.php?machine=308&night=7260)
is showing errors in
Benchmarks/Dhrystone/dry
Benchmarks/Dhrystone/fldry
Benchmarks/MallocBench/cfrac/cfrac
Benchmarks/McCat/18-imp/imp

and I minimized the cfrac failure to the following test case:
--
typedef unsigned short posit;

extern void palloc();

void palloc(posit size) {
}
--
ddunbar at ddunbar2:cfrac$ clang Output/pops.E
Output/pops.E:5:6: error: conflicting types for 'palloc'
void palloc(posit size) {
     ^
Output/pops.E:3:13: error: previous declaration is here
extern void palloc();
            ^
2 diagnostics generated.
--

Can you investigate?

 - Daniel




----- Original Message ----
From: Eli Friedman <eli.friedman at gmail.com>
To: cfe-commits at cs.uiuc.edu
Sent: Thursday, August 21, 2008 5:56:43 PM
Subject:
[cfe-commits] r55158 - in /cfe/trunk: include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp

Author: efriedma
Date: Thu Aug 21 19:56:42 2008
New Revision: 55158

URL: http://llvm.org/viewvc/llvm-project?rev=55158&view=rev
Log:
Rewrite type compatibility testing to do type merging rather than just 
testing compatibility.  This is necessary for some constructs, like merging
redeclarations.

Also, there are some ObjC changes to make sure that 
typesAreCompatible(a,b) == typesAreCompatible(b,a).  I don't have any 
ObjC code beyond the testsuite, so please tell me if there are any cases 
where this doesn't behave as expected.


Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=55158&r1=55157&r2=55158&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Thu Aug 21 19:56:42 2008
@@ -397,9 +397,6 @@
                                              
   /// Compatibility predicates used to check assignment expressions.
   bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
-  bool pointerTypesAreCompatible(QualType, QualType);  // C99 6.7.5.1p2
-  bool referenceTypesAreCompatible(QualType, QualType); // C++ 5.17p6
-  bool functionTypesAreCompatible(QualType, QualType); // C99 6.7.5.3p15
  
   bool isObjCIdType(QualType T) const {
     if (!IdStructType) // ObjC isn't enabled
@@ -416,6 +413,14 @@
     return T->getAsStructureType() == SelStructType;
   }

+  // Check the safety of assignment from LHS to RHS
+  bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS, 
+                               const ObjCInterfaceType *RHS);
+
+  // Functions for calculating composite types
+  QualType mergeTypes(QualType, QualType);
+  QualType mergeFunctionTypes(QualType, QualType);
+
   //===--------------------------------------------------------------------===//
   //                    Integer Predicates
   //===--------------------------------------------------------------------===//

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=55158&r1=55157&r2=55158&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Thu Aug 21 19:56:42 2008
@@ -1623,92 +1623,6 @@
//                        Type Compatibility Testing
//===----------------------------------------------------------------------===//

-/// C99 6.2.7p1: If both are complete types, then the following additional
-/// requirements apply.
-/// FIXME (handle compatibility across source files).
-static bool areCompatTagTypes(TagType *LHS, TagType *RHS,
-                              const ASTContext &C) {
-  // "Class" and "id" are compatible built-in structure types.
-  if (C.isObjCIdType(QualType(LHS, 0)) && C.isObjCClassType(QualType(RHS, 0)) ||
-      C.isObjCClassType(QualType(LHS, 0)) && C.isObjCIdType(QualType(RHS, 0)))
-    return true;
-
-  // Within a translation unit a tag type is only compatible with itself.  Self
-  // equality is already handled by the time we get here.
-  assert(LHS != RHS && "Self equality not handled!");
-  return false;
-}
-
-bool ASTContext::pointerTypesAreCompatible(QualType lhs, QualType rhs) {
-  // C99 6.7.5.1p2: For two pointer types to be compatible, both shall be 
-  // identically qualified and both shall be pointers to compatible types.
-  if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers() ||
-      lhs.getAddressSpace() != rhs.getAddressSpace())
-    return false;
-    
-  QualType ltype = lhs->getAsPointerType()->getPointeeType();
-  QualType rtype = rhs->getAsPointerType()->getPointeeType();
-  
-  return typesAreCompatible(ltype, rtype);
-}
-
-bool ASTContext::functionTypesAreCompatible(QualType lhs, QualType rhs) {
-  const FunctionType *lbase = lhs->getAsFunctionType();
-  const FunctionType *rbase = rhs->getAsFunctionType();
-  const FunctionTypeProto *lproto = dyn_cast<FunctionTypeProto>(lbase);
-  const FunctionTypeProto *rproto = dyn_cast<FunctionTypeProto>(rbase);
-
-  // first check the return types (common between C99 and K&R).
-  if (!typesAreCompatible(lbase->getResultType(), rbase->getResultType()))
-    return false;
-
-  if (lproto && rproto) { // two C99 style function prototypes
-    unsigned lproto_nargs = lproto->getNumArgs();
-    unsigned rproto_nargs = rproto->getNumArgs();
-    
-    if (lproto_nargs != rproto_nargs)
-      return false;
-      
-    // both prototypes have the same number of arguments.
-    if ((lproto->isVariadic() && !rproto->isVariadic()) ||
-        (rproto->isVariadic() && !lproto->isVariadic()))
-      return false;
-      
-    // The use of ellipsis agree...now check the argument types.
-    for (unsigned i = 0; i < lproto_nargs; i++)
-      // C99 6.7.5.3p15: ...and each parameter declared with qualified type
-      // is taken as having the unqualified version of it's declared type.
-      if (!typesAreCompatible(lproto->getArgType(i).getUnqualifiedType(), 
-                              rproto->getArgType(i).getUnqualifiedType()))
-        return false;
-    return true;
-  }
-  
-  if (!lproto && !rproto) // two K&R style function decls, nothing to do.
-    return true;
-
-  // we have a mixture of K&R style with C99 prototypes
-  const FunctionTypeProto *proto = lproto ? lproto : rproto;
-  if (proto->isVariadic())
-    return false;
-    
-  // FIXME: Each parameter type T in the prototype must be compatible with the
-  // type resulting from applying the usual argument conversions to T.
-  return true;
-}
-
-// C99 6.7.5.2p6
-static bool areCompatArrayTypes(ArrayType *LHS, ArrayType *RHS, ASTContext &C) {
-  // Constant arrays must be the same size to be compatible.
-  if (const ConstantArrayType* LCAT = dyn_cast<ConstantArrayType>(LHS))
-    if (const ConstantArrayType* RCAT = dyn_cast<ConstantArrayType>(RHS))
-      if (RCAT->getSize() != LCAT->getSize())
-        return false;
-
-  // Compatible arrays must have compatible element types
-  return C.typesAreCompatible(LHS->getElementType(), RHS->getElementType());
-}
-
/// areCompatVectorTypes - Return true if the two specified vector types are 
/// compatible.
static bool areCompatVectorTypes(const VectorType *LHS,
@@ -1718,12 +1632,12 @@
   LHS->getNumElements() == RHS->getNumElements();
}

-/// areCompatObjCInterfaces - Return true if the two interface types are
+/// canAssignObjCInterfaces - Return true if the two interface types are
/// compatible for assignment from RHS to LHS.  This handles validation of any
/// protocol qualifiers on the LHS or RHS.
///
-static bool areCompatObjCInterfaces(const ObjCInterfaceType *LHS, 
-                                    const ObjCInterfaceType *RHS) {
+bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
+                                         const ObjCInterfaceType *RHS) {
   // Verify that the base decls are compatible: the RHS must be a subclass of
   // the LHS.
   if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
@@ -1771,42 +1685,114 @@
   return false;
}

-
/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible, 
/// both shall have the identically qualified version of a compatible type.
/// C99 6.2.7p1: Two types have compatible types if their types are the 
/// same. See 6.7.[2,3,5] for additional rules.
-bool ASTContext::typesAreCompatible(QualType LHS_NC, QualType RHS_NC) {
-  QualType LHS = getCanonicalType(LHS_NC);
-  QualType RHS = getCanonicalType(RHS_NC);
-  
+bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) {
+  return !mergeTypes(LHS, RHS).isNull();
+}
+
+QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
+  const FunctionType *lbase = lhs->getAsFunctionType();
+  const FunctionType *rbase = rhs->getAsFunctionType();
+  const FunctionTypeProto *lproto = dyn_cast<FunctionTypeProto>(lbase);
+  const FunctionTypeProto *rproto = dyn_cast<FunctionTypeProto>(rbase);
+  bool allLTypes = true;
+  bool allRTypes = true;
+
+  // Check return type
+  QualType retType = mergeTypes(lbase->getResultType(), rbase->getResultType());
+  if (retType.isNull()) return QualType();
+  if (getCanonicalType(retType) != getCanonicalType(lbase->getResultType())) allLTypes = false;
+  if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType())) allRTypes = false;
+
+  if (lproto && rproto) { // two C99 style function prototypes
+    unsigned lproto_nargs = lproto->getNumArgs();
+    unsigned rproto_nargs = rproto->getNumArgs();
+
+    // Compatible functions must have the same number of arguments
+    if (lproto_nargs != rproto_nargs)
+      return QualType();
+
+    // Variadic and non-variadic functions aren't compatible
+    if (lproto->isVariadic() != rproto->isVariadic())
+      return QualType();
+
+    // Check argument compatibility
+    llvm::SmallVector<QualType, 10> types;
+    for (unsigned i = 0; i < lproto_nargs; i++) {
+      QualType largtype = lproto->getArgType(i).getUnqualifiedType();
+      QualType rargtype = rproto->getArgType(i).getUnqualifiedType();
+      QualType argtype = mergeTypes(largtype, rargtype);
+      if (argtype.isNull()) return QualType();
+      types.push_back(argtype);
+      if (getCanonicalType(argtype) != getCanonicalType(largtype)) allLTypes = false;
+      if (getCanonicalType(argtype) != getCanonicalType(rargtype)) allRTypes = false;
+    }
+    if (allLTypes) return lhs;
+    if (allRTypes) return rhs;
+    return getFunctionType(retType, types.begin(), types.size(),
+                           lproto->isVariadic());
+  }
+
+  if (lproto) allRTypes = false;
+  if (rproto) allLTypes = false;
+
+  const FunctionTypeProto *proto = lproto ? lproto : rproto;
+  if (proto) {
+    if (proto->isVariadic()) return QualType();
+    // Check that the types are compatible with the types that
+    // would result from default argument promotions (C99 6.7.5.3p15).
+    // The only types actually affected are promotable integer
+    // types and floats, which would be passed as a different
+    // type depending on whether the prototype is visible.
+    unsigned proto_nargs = proto->getNumArgs();
+    for (unsigned i = 0; i < proto_nargs; ++i) {
+      QualType argTy = proto->getArgType(i);
+      if (argTy->isPromotableIntegerType() ||
+          getCanonicalType(argTy).getUnqualifiedType() == FloatTy)
+        return QualType();
+    }
+
+    if (allLTypes) return lhs;
+    if (allRTypes) return rhs;
+    return getFunctionType(retType, proto->arg_type_begin(),
+                           proto->getNumArgs(), lproto->isVariadic());
+  }
+
+  if (allLTypes) return lhs;
+  if (allRTypes) return rhs;
+  return getFunctionTypeNoProto(retType);
+}
+
+QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
   // C++ [expr]: If an expression initially has the type "reference to T", the
   // type is adjusted to "T" prior to any further analysis, the expression
   // designates the object or function denoted by the reference, and the
   // expression is an lvalue.
-  if (ReferenceType *RT = dyn_cast<ReferenceType>(LHS))
+  // FIXME: C++ shouldn't be going through here!  The rules are different
+  // enough that they should be handled separately.
+  if (const ReferenceType *RT = LHS->getAsReferenceType())
     LHS = RT->getPointeeType();
-  if (ReferenceType *RT = dyn_cast<ReferenceType>(RHS))
+  if (const ReferenceType *RT = RHS->getAsReferenceType())
     RHS = RT->getPointeeType();
-  
+
+  QualType LHSCan = getCanonicalType(LHS),
+           RHSCan = getCanonicalType(RHS);
+
   // If two types are identical, they are compatible.
-  if (LHS == RHS)
-    return true;
-  
-  // If qualifiers differ, the types are different.
-  unsigned LHSAS = LHS.getAddressSpace(), RHSAS = RHS.getAddressSpace();
-  if (LHS.getCVRQualifiers() != RHS.getCVRQualifiers() || LHSAS != RHSAS)
-    return false;
-  
-  // Strip off ASQual's if present.
-  if (LHSAS) {
-    LHS = LHS.getUnqualifiedType();
-    RHS = RHS.getUnqualifiedType();
-  }
+  if (LHSCan == RHSCan)
+    return LHS;
+
+  // If the qualifiers are different, the types aren't compatible
+  if (LHSCan.getCVRQualifiers() != RHSCan.getCVRQualifiers() ||
+      LHSCan.getAddressSpace() != RHSCan.getAddressSpace())
+    return QualType();
+
+  Type::TypeClass LHSClass = LHSCan->getTypeClass();
+  Type::TypeClass RHSClass = RHSCan->getTypeClass();

-  Type::TypeClass LHSClass = LHS->getTypeClass();
-  Type::TypeClass RHSClass = RHS->getTypeClass();
-  
   // We want to consider the two function types to be the same for these
   // comparisons, just force one to the other.
   if (LHSClass == Type::FunctionProto) LHSClass = Type::FunctionNoProto;
@@ -1825,68 +1811,106 @@
   // Consider qualified interfaces and interfaces the same.
   if (LHSClass == Type::ObjCQualifiedInterface) LHSClass = Type::ObjCInterface;
   if (RHSClass == Type::ObjCQualifiedInterface) RHSClass = Type::ObjCInterface;
-  
+
   // If the canonical type classes don't match.
   if (LHSClass != RHSClass) {
-    // ID is compatible with all interface types.
-    if (isa<ObjCInterfaceType>(LHS))
-      return isObjCIdType(RHS);
-    if (isa<ObjCInterfaceType>(RHS))
-      return isObjCIdType(LHS);
-
     // ID is compatible with all qualified id types.
-    if (isa<ObjCQualifiedIdType>(LHS)) {
+    if (LHS->isObjCQualifiedIdType()) {
       if (const PointerType *PT = RHS->getAsPointerType())
-        return isObjCIdType(PT->getPointeeType());
+        if (isObjCIdType(PT->getPointeeType()))
+          return LHS;
     }
-    if (isa<ObjCQualifiedIdType>(RHS)) {
+    if (RHS->isObjCQualifiedIdType()) {
       if (const PointerType *PT = LHS->getAsPointerType())
-        return isObjCIdType(PT->getPointeeType());
-    }    
+        if (isObjCIdType(PT->getPointeeType()))
+          return RHS;
+    }
+
     // C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
     // a signed integer type, or an unsigned integer type. 
-    if (LHS->isEnumeralType() && RHS->isIntegralType()) {
-      EnumDecl* EDecl = cast<EnumType>(LHS)->getDecl();
-      return EDecl->getIntegerType() == RHS;
+    if (const EnumType* ETy = LHS->getAsEnumType()) {
+      if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType())
+        return RHS;
     }
-    if (RHS->isEnumeralType() && LHS->isIntegralType()) {
-      EnumDecl* EDecl = cast<EnumType>(RHS)->getDecl();
-      return EDecl->getIntegerType() == LHS;
+    if (const EnumType* ETy = RHS->getAsEnumType()) {
+      if (ETy->getDecl()->getIntegerType() == LHSCan.getUnqualifiedType())
+        return LHS;
     }

-    return false;
+    return QualType();
   }
-  
+
   // The canonical type classes match.
   switch (LHSClass) {
-  case Type::ASQual:
-  case Type::FunctionProto:
-  case Type::VariableArray:
-  case Type::IncompleteArray:
-  case Type::Reference:
-  case Type::ObjCQualifiedInterface:
-    assert(0 && "Canonicalized away above");
   case Type::Pointer:
-    return pointerTypesAreCompatible(LHS, RHS);
+  {
+    // Merge two pointer types, while trying to preserve typedef info
+    QualType LHSPointee = LHS->getAsPointerType()->getPointeeType();
+    QualType RHSPointee = RHS->getAsPointerType()->getPointeeType();
+    QualType ResultType = mergeTypes(LHSPointee, RHSPointee);
+    if (ResultType.isNull()) return QualType();
+    if (getCanonicalType(LHSPointee) != getCanonicalType(ResultType)) return LHS;
+    if (getCanonicalType(RHSPointee) != getCanonicalType(ResultType)) return RHS;
+    return getPointerType(ResultType);
+  }
   case Type::ConstantArray:
-    return areCompatArrayTypes(cast<ArrayType>(LHS), cast<ArrayType>(RHS),
-                               *this);
+  {
+    const ConstantArrayType* LCAT = getAsConstantArrayType(LHS);
+    const ConstantArrayType* RCAT = getAsConstantArrayType(RHS);
+    if (LCAT && RCAT && RCAT->getSize() != LCAT->getSize())
+      return QualType();
+
+    QualType LHSElem = getAsArrayType(LHS)->getElementType();
+    QualType RHSElem = getAsArrayType(RHS)->getElementType();
+    QualType ResultType = mergeTypes(LHSElem, RHSElem);
+    if (ResultType.isNull()) return QualType();
+    if (LCAT && getCanonicalType(LHSElem) != getCanonicalType(ResultType)) return LHS;
+    if (RCAT && getCanonicalType(RHSElem) != getCanonicalType(ResultType)) return RHS;
+    const VariableArrayType* LVAT = getAsVariableArrayType(LHS);
+    const VariableArrayType* RVAT = getAsVariableArrayType(RHS);
+    if (LVAT && getCanonicalType(LHSElem) != getCanonicalType(ResultType)) return LHS;
+    if (RVAT && getCanonicalType(RHSElem) != getCanonicalType(ResultType)) return RHS;
+    if (LVAT) {
+      // FIXME: This isn't correct! But tricky to implement because
+      // the array's size has to be the size of LHS, but the type
+      // has to be different.
+      return LHS;
+    }
+    if (RVAT) {
+      // FIXME: This isn't correct! But tricky to implement because
+      // the array's size has to be the size of RHS, but the type
+      // has to be different.
+      return RHS;
+    }
+    if (getCanonicalType(LHSElem) != getCanonicalType(ResultType)) return LHS;
+    if (getCanonicalType(RHSElem) != getCanonicalType(ResultType)) return RHS;
+    return getIncompleteArrayType(ResultType, ArrayType::ArraySizeModifier(), 0);
+  }
   case Type::FunctionNoProto:
-    return functionTypesAreCompatible(LHS, RHS);
-  case Type::Tagged: // handle structures, unions
-    return areCompatTagTypes(cast<TagType>(LHS), cast<TagType>(RHS), *this);
+    return mergeFunctionTypes(LHS, RHS);
+  case Type::Tagged:
+  {
+    // FIXME: Why are these compatible?
+    if (isObjCIdType(LHS) && isObjCClassType(RHS)) return LHS;
+    if (isObjCClassType(LHS) && isObjCIdType(RHS)) return LHS;
+    return QualType();
+  }
   case Type::Builtin:
     // Only exactly equal builtin types are compatible, which is tested above.
-    return false;
+    return QualType();
   case Type::Vector:
-    return areCompatVectorTypes(cast<VectorType>(LHS), cast<VectorType>(RHS));
+    if (areCompatVectorTypes(LHS->getAsVectorType(), RHS->getAsVectorType()))
+      return LHS;
   case Type::ObjCInterface:
-    return areCompatObjCInterfaces(cast<ObjCInterfaceType>(LHS),
-                                   cast<ObjCInterfaceType>(RHS));
+  {
+    // Distinct ObjC interfaces are not compatible; see canAssignObjCInterfaces
+    // for checking assignment/comparison safety
+    return QualType();
+  }
   default:
     assert(0 && "unexpected type");
+    return QualType();
   }
-  return true; // should never get here...
}

//===----------------------------------------------------------------------===//

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Aug 21 19:56:42 2008
@@ -346,7 +346,7 @@
   // C: Function types need to be compatible, not identical. This handles
   // duplicate function decls like "void f(int); void f(enum X);" properly.
   if (!getLangOptions().CPlusPlus &&
-      Context.functionTypesAreCompatible(OldQType, NewQType)) {
+      Context.typesAreCompatible(OldQType, NewQType)) {
     MergeAttributes(New, Old);
     Redeclaration = true;
     return New;

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Aug 21 19:56:42 2008
@@ -1354,7 +1354,20 @@
     assert(lhptee->isFunctionType());
     return FunctionVoidPointer;
   }
-  
+
+  // Check for ObjC interfaces
+  const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType();
+  const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType();
+  if (LHSIface && RHSIface &&
+      Context.canAssignObjCInterfaces(LHSIface, RHSIface))
+    return ConvTy;
+
+  // ID acts sort of like void* for ObjC interfaces
+  if (LHSIface && Context.isObjCIdType(rhptee))
+    return ConvTy;
+  if (RHSIface && Context.isObjCIdType(lhptee))
+    return ConvTy;
+
   // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or 
   // unqualified versions of compatible types, ...
   if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), 
@@ -1701,6 +1714,21 @@
   return lex->getType();
}

+static bool areComparableObjCInterfaces(QualType LHS, QualType RHS,
+                                        ASTContext& Context) {
+  const ObjCInterfaceType* LHSIface = LHS->getAsObjCInterfaceType();
+  const ObjCInterfaceType* RHSIface = RHS->getAsObjCInterfaceType();
+  // ID acts sort of like void* for ObjC interfaces
+  if (LHSIface && Context.isObjCIdType(RHS))
+    return true;
+  if (RHSIface && Context.isObjCIdType(LHS))
+    return true;
+  if (!LHSIface || !RHSIface)
+    return false;
+  return Context.canAssignObjCInterfaces(LHSIface, RHSIface) ||
+         Context.canAssignObjCInterfaces(RHSIface, LHSIface);
+}
+
// C99 6.5.8
QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation loc,
                                     bool isRelational) {
@@ -1756,7 +1784,8 @@
     if (!LHSIsNull && !RHSIsNull &&                       // C99 6.5.9p2
         !LCanPointeeTy->isVoidType() && !RCanPointeeTy->isVoidType() &&
         !Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
-                                    RCanPointeeTy.getUnqualifiedType())) {
+                                    RCanPointeeTy.getUnqualifiedType()) &&
+        !areComparableObjCInterfaces(LCanPointeeTy, RCanPointeeTy, Context)) {
       Diag(loc, diag::ext_typecheck_comparison_of_distinct_pointers,
            lType.getAsString(), rType.getAsString(),
            lex->getSourceRange(), rex->getSourceRange());


_______________________________________________
cfe-commits mailing list
cfe-commits at cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits




More information about the cfe-commits mailing list