Fix for PR2501; this patch makes usual arithmetic conversions for 
integers which have the same width and different signedness work 
correctly. (The testcase in PR2501 uses a comparison between long and 
unsigned int).



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@52853 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 1fd65b1..a910095 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -371,6 +371,19 @@
   }
 
   //===--------------------------------------------------------------------===//
+  //                    Integer Predicates
+  //===--------------------------------------------------------------------===//
+
+  // The width of an integer, as defined in C99 6.2.6.2. This is the number
+  // of bits in an integer type excluding any padding bits.
+  unsigned getIntWidth(QualType T);
+
+  // Per C99 6.2.5p6, for every signed integer type, there is a corresponding
+  // unsigned integer type.  This method takes a signed type, and returns the
+  // corresponding unsigned integer type.
+  QualType getCorrespondingUnsignedType(QualType T);
+
+  //===--------------------------------------------------------------------===//
   //                    Serialization
   //===--------------------------------------------------------------------===//
 
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 2e80f44..beedbfb 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -48,6 +48,7 @@
   class VariableArrayType;
   class IncompleteArrayType;
   class RecordType;
+  class EnumType;
   class ComplexType;
   class TagType;
   class TypedefType;
@@ -352,6 +353,7 @@
   const RecordType *getAsStructureType() const;
   const TypedefType *getAsTypedefType() const;
   const RecordType *getAsUnionType() const;
+  const EnumType *getAsEnumType() const;
   const VectorType *getAsVectorType() const; // GCC vector type.
   const ComplexType *getAsComplexType() const;
   const ComplexType *getAsComplexIntegerType() const; // GCC complex int type.
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 11ca78a..08a2bb1 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1757,6 +1757,41 @@
 }
 
 //===----------------------------------------------------------------------===//
+//                         Integer Predicates
+//===----------------------------------------------------------------------===//
+unsigned ASTContext::getIntWidth(QualType T) {
+  if (T == BoolTy)
+    return 1;
+  // At the moment, only bool has padding bits
+  return (unsigned)getTypeSize(T);
+}
+
+QualType ASTContext::getCorrespondingUnsignedType(QualType T) {
+  assert(T->isSignedIntegerType() && "Unexpected type");
+  if (const EnumType* ETy = T->getAsEnumType())
+    T = ETy->getDecl()->getIntegerType();
+  const BuiltinType* BTy = T->getAsBuiltinType();
+  assert (BTy && "Unexpected signed integer type");
+  switch (BTy->getKind()) {
+  case BuiltinType::Char_S:
+  case BuiltinType::SChar:
+    return UnsignedCharTy;
+  case BuiltinType::Short:
+    return UnsignedShortTy;
+  case BuiltinType::Int:
+    return UnsignedIntTy;
+  case BuiltinType::Long:
+    return UnsignedLongTy;
+  case BuiltinType::LongLong:
+    return UnsignedLongLongTy;
+  default:
+    assert(0 && "Unexpected signed integer type");
+    return QualType();
+  }
+}
+
+
+//===----------------------------------------------------------------------===//
 //                         Serialization Support
 //===----------------------------------------------------------------------===//
 
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 7e09bb1..bf32c53 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -390,6 +390,13 @@
   return 0;
 }
 
+const EnumType *Type::getAsEnumType() const {
+  // Check the canonicalized unqualified type directly; the more complex
+  // version is unnecessary because there isn't any typedef information
+  // to preserve.
+  return dyn_cast<EnumType>(CanonicalType.getUnqualifiedType());
+}
+
 const ComplexType *Type::getAsComplexType() const {
   // Are we directly a complex type?
   if (const ComplexType *CTy = dyn_cast<ComplexType>(this))
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9751392..8ef9486 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1221,12 +1221,35 @@
     }
   }
   // Finally, we have two differing integer types.
-  if (Context.getIntegerTypeOrder(lhs, rhs) >= 0) { // convert the rhs
-    if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs);
-    return lhs;
+  // The rules for this case are in C99 6.3.1.8
+  int compare = Context.getIntegerTypeOrder(lhs, rhs);
+  bool lhsSigned = lhs->isSignedIntegerType(),
+       rhsSigned = rhs->isSignedIntegerType();
+  QualType destType;
+  if (lhsSigned == rhsSigned) {
+    // Same signedness; use the higher-ranked type
+    destType = compare >= 0 ? lhs : rhs;
+  } else if (compare != (lhsSigned ? 1 : -1)) {
+    // The unsigned type has greater than or equal rank to the
+    // signed type, so use the unsigned type
+    destType = lhsSigned ? rhs : lhs;
+  } else if (Context.getIntWidth(lhs) != Context.getIntWidth(rhs)) {
+    // The two types are different widths; if we are here, that
+    // means the signed type is larger than the unsigned type, so
+    // use the signed type.
+    destType = lhsSigned ? lhs : rhs;
+  } else {
+    // The signed type is higher-ranked than the unsigned type,
+    // but isn't actually any bigger (like unsigned int and long
+    // on most 32-bit systems).  Use the unsigned type corresponding
+    // to the signed type.
+    destType = Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs);
   }
-  if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); // convert the lhs
-  return rhs;
+  if (!isCompAssign) {
+    ImpCastExprToType(lhsExpr, destType);
+    ImpCastExprToType(rhsExpr, destType);
+  }
+  return destType;
 }
 
 // CheckPointerTypesForAssignment - This is a very tricky routine (despite
diff --git a/test/Sema/int-arith-convert.c b/test/Sema/int-arith-convert.c
new file mode 100644
index 0000000..254c6c0
--- /dev/null
+++ b/test/Sema/int-arith-convert.c
@@ -0,0 +1,12 @@
+// RUN: clang -fsyntax-only -verify %s
+
+// Check types are the same through redeclaration
+unsigned long x;
+__typeof(1u+1l) x;
+
+unsigned y;
+__typeof(1+1u) y;
+__typeof(1u+1) y;
+
+long long z;
+__typeof(1ll+1u) z;