[cfe-commits] r92823 - in /cfe/trunk: lib/Sema/SemaChecking.cpp test/Sema/compare.c test/Sema/conversion.c

John McCall rjmccall at apple.com
Tue Jan 5 21:25:05 PST 2010


Author: rjmccall
Date: Tue Jan  5 23:24:50 2010
New Revision: 92823

URL: http://llvm.org/viewvc/llvm-project?rev=92823&view=rev
Log:
Significantly rework the calculation of effective integer-expression ranges
for -Wsign-compare and -Wconversion, and use that coordinated logic to drive
both diagnostics.  The new logic works more transparently with implicit
conversions, conditional operators, etc., as well as bringing -Wconversion's
ability to deal with pseudo-closed operations (e.g. arithmetic on shorts) to
-Wsign-compare.

Fixes PRs 5887, 5937, 5938, and 5939.


Modified:
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/Sema/compare.c
    cfe/trunk/test/Sema/conversion.c

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Tue Jan  5 23:24:50 2010
@@ -1557,170 +1557,153 @@
       << lex->getSourceRange() << rex->getSourceRange();
 }
 
-//===--- CHECK: Comparison of signed and unsigned int (-Wsign-compare) ----===//
+//===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===//
+//===--- CHECK: Lossy implicit conversions (-Wconversion) --------------===//
 
-/// Returns true if we can prove that the result of the given
-/// integral expression will not have its sign bit set.
-static bool IsSignBitProvablyZero(ASTContext &Context, Expr *E) {
-  E = E->IgnoreParens();
+namespace {
 
-  llvm::APSInt value;
-  if (E->isIntegerConstantExpr(value, Context))
-    return value.isNonNegative();
-
-  if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E))
-    return IsSignBitProvablyZero(Context, CO->getLHS()) &&
-           IsSignBitProvablyZero(Context, CO->getRHS());
+/// Structure recording the 'active' range of an integer-valued
+/// expression.
+struct IntRange {
+  /// The number of bits active in the int.
+  unsigned Width;
 
-  return false;
-}
+  /// True if the int is known not to have negative values.
+  bool NonNegative;
 
-/// Retrieves the width and signedness of the given integer type,
-/// or returns false if it is not an integer type.
-///
-/// \param T must be canonical
-static bool getIntProperties(ASTContext &C, const Type *T,
-                             unsigned &BitWidth, bool &Signed) {
-  assert(T->isCanonicalUnqualified());
-
-  if (const VectorType *VT = dyn_cast<VectorType>(T))
-    T = VT->getElementType().getTypePtr();
-  if (const ComplexType *CT = dyn_cast<ComplexType>(T))
-    T = CT->getElementType().getTypePtr();
+  IntRange() {}
+  IntRange(unsigned Width, bool NonNegative)
+    : Width(Width), NonNegative(NonNegative)
+  {}
 
-  if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) {
-    if (!BT->isInteger()) return false;
+  // Returns the range of the bool type.
+  static IntRange forBoolType() {
+    return IntRange(1, true);
+  }
 
-    BitWidth = C.getIntWidth(QualType(T, 0));
-    Signed = BT->isSignedInteger();
-    return true;
+  // Returns the range of an integral type.
+  static IntRange forType(ASTContext &C, QualType T) {
+    return forCanonicalType(C, T->getCanonicalTypeInternal().getTypePtr());
   }
 
-  return false;
-}
+  // Returns the range of an integeral type based on its canonical
+  // representation.
+  static IntRange forCanonicalType(ASTContext &C, const Type *T) {
+    assert(T->isCanonicalUnqualified());
 
-/// Checks whether the given value will have the same value if it it
-/// is truncated to the given width, then extended back to the
-/// original width.
-static bool IsSameIntAfterCast(const llvm::APSInt &value,
-                               unsigned TargetWidth) {
-  unsigned SourceWidth = value.getBitWidth();
-  llvm::APSInt truncated = value;
-  truncated.trunc(TargetWidth);
-  truncated.extend(SourceWidth);
-  return (truncated == value);
-}
+    if (const VectorType *VT = dyn_cast<VectorType>(T))
+      T = VT->getElementType().getTypePtr();
+    if (const ComplexType *CT = dyn_cast<ComplexType>(T))
+      T = CT->getElementType().getTypePtr();
+    if (const EnumType *ET = dyn_cast<EnumType>(T))
+      T = ET->getDecl()->getIntegerType().getTypePtr();
 
-/// Checks whether the given value will have the same value if it
-/// is truncated to the given width, then extended back to the original
-/// width.
-///
-/// The value might be a vector or a complex.
-static bool IsSameIntAfterCast(const APValue &value, unsigned TargetWidth) {
-  if (value.isInt())
-    return IsSameIntAfterCast(value.getInt(), TargetWidth);
+    const BuiltinType *BT = cast<BuiltinType>(T);
+    assert(BT->isInteger());
 
-  if (value.isVector()) {
-    for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i)
-      if (!IsSameIntAfterCast(value.getVectorElt(i), TargetWidth))
-        return false;
-    return true;
+    return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger());
   }
 
-  if (value.isComplexInt()) {
-    return IsSameIntAfterCast(value.getComplexIntReal(), TargetWidth) &&
-           IsSameIntAfterCast(value.getComplexIntImag(), TargetWidth);
+  // Returns the supremum of two ranges: i.e. their conservative merge.
+  static IntRange join(const IntRange &L, const IntRange &R) {
+    return IntRange(std::max(L.Width, R.Width),
+                        L.NonNegative && R.NonNegative);
   }
+};
 
-  // This can happen with lossless casts to intptr_t of "based" lvalues.
-  // Assume it might use arbitrary bits.
-  assert(value.isLValue());
-  return false;
-}
-                               
-
-/// Checks whether the given value, which currently has the given
-/// source semantics, has the same value when coerced through the
-/// target semantics.
-static bool IsSameFloatAfterCast(const llvm::APFloat &value,
-                                 const llvm::fltSemantics &Src,
-                                 const llvm::fltSemantics &Tgt) {
-  llvm::APFloat truncated = value;
+IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) {
+  if (value.isSigned() && value.isNegative())
+    return IntRange(value.getMinSignedBits(), false);
 
-  bool ignored;
-  truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored);
-  truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored);
+  if (value.getBitWidth() > MaxWidth)
+    value.trunc(MaxWidth);
 
-  return truncated.bitwiseIsEqual(value);
+  // isNonNegative() just checks the sign bit without considering
+  // signedness.
+  return IntRange(value.getActiveBits(), true);
 }
 
-/// Checks whether the given value, which currently has the given
-/// source semantics, has the same value when coerced through the
-/// target semantics.
-///
-/// The value might be a vector of floats (or a complex number).
-static bool IsSameFloatAfterCast(const APValue &value,
-                                 const llvm::fltSemantics &Src,
-                                 const llvm::fltSemantics &Tgt) {
-  if (value.isFloat())
-    return IsSameFloatAfterCast(value.getFloat(), Src, Tgt);
+IntRange GetValueRange(ASTContext &C, APValue &result,
+                       unsigned MaxWidth) {
+  if (result.isInt())
+    return GetValueRange(C, result.getInt(), MaxWidth);
 
-  if (value.isVector()) {
-    for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i)
-      if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt))
-        return false;
-    return true;
+  if (result.isVector()) {
+    IntRange R = GetValueRange(C, result.getVectorElt(0), MaxWidth);
+    for (unsigned i = 1, e = result.getVectorLength(); i != e; ++i)
+      R = IntRange::join(R, GetValueRange(C, result.getVectorElt(i), MaxWidth));
+    return R;
   }
 
-  assert(value.isComplexFloat());
-  return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) &&
-          IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
-}
-
-/// Determines if it's reasonable for the given expression to be truncated
-/// down to the given integer width.
-/// * Boolean expressions are automatically white-listed.
-/// * Arithmetic operations on implicitly-promoted operands of the
-///   target width or less are okay --- not because the results are
-///   actually guaranteed to fit within the width, but because the
-///   user is effectively pretending that the operations are closed
-///   within the implicitly-promoted type.
-static bool IsExprValueWithinWidth(ASTContext &C, Expr *E, unsigned Width) {
-  E = E->IgnoreParens();
-
-#ifndef NDEBUG
-  {
-    const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr();
-    unsigned EWidth;
-    bool ESigned;
-
-    if (!getIntProperties(C, ETy, EWidth, ESigned))
-      assert(0 && "expression not of integer type");
-
-    // The caller should never let this happen.
-    assert(EWidth > Width && "called on expr whose type is too small");
+  if (result.isComplexInt()) {
+    IntRange R = GetValueRange(C, result.getComplexIntReal(), MaxWidth);
+    IntRange I = GetValueRange(C, result.getComplexIntImag(), MaxWidth);
+    return IntRange::join(R, I);
   }
-#endif
 
-  // Strip implicit casts off.
-  while (isa<ImplicitCastExpr>(E)) {
-    E = cast<ImplicitCastExpr>(E)->getSubExpr();
+  // This can happen with lossless casts to intptr_t of "based" lvalues.
+  // Assume it might use arbitrary bits.
+  assert(result.isLValue());
+  return IntRange(MaxWidth, false);
+}
 
-    const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr();
+/// Pseudo-evaluate the given integer expression, estimating the
+/// range of values it might take.
+///
+/// \param MaxWidth - the width to which the value will be truncated
+IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
+  E = E->IgnoreParens();
 
-    unsigned EWidth;
-    bool ESigned;
-    if (!getIntProperties(C, ETy, EWidth, ESigned))
-      return false;
+  // Try a full evaluation first.
+  Expr::EvalResult result;
+  if (E->Evaluate(result, C))
+    return GetValueRange(C, result.Val, MaxWidth);
 
-    if (EWidth <= Width)
-      return true;
+  // I think we only want to look through implicit casts here; if the
+  // user has an explicit widening cast, we should treat the value as
+  // being of the new, wider type.
+  if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) {
+    if (CE->getCastKind() == CastExpr::CK_NoOp)
+      return GetExprRange(C, CE->getSubExpr(), MaxWidth);
+
+    IntRange OutputTypeRange = IntRange::forType(C, CE->getType());
+
+    // Assume that non-integer casts can span the full range of the type.
+    if (CE->getCastKind() != CastExpr::CK_IntegralCast)
+      return OutputTypeRange;
+
+    IntRange SubRange
+      = GetExprRange(C, CE->getSubExpr(),
+                     std::min(MaxWidth, OutputTypeRange.Width));
+
+    // Bail out if the subexpr's range is as wide as the cast type.
+    if (SubRange.Width >= OutputTypeRange.Width)
+      return OutputTypeRange;
+
+    // Otherwise, we take the smaller width, and we're non-negative if
+    // either the output type or the subexpr is.
+    return IntRange(SubRange.Width,
+                    SubRange.NonNegative || OutputTypeRange.NonNegative);
+  }
+
+  if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+    // If we can fold the condition, just take that operand.
+    bool CondResult;
+    if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C))
+      return GetExprRange(C, CondResult ? CO->getTrueExpr()
+                                        : CO->getFalseExpr(),
+                          MaxWidth);
+
+    // Otherwise, conservatively merge.
+    IntRange L = GetExprRange(C, CO->getTrueExpr(), MaxWidth);
+    IntRange R = GetExprRange(C, CO->getFalseExpr(), MaxWidth);
+    return IntRange::join(L, R);
   }
 
   if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
     switch (BO->getOpcode()) {
 
-    // Boolean-valued operations are white-listed.
+    // Boolean-valued operations are single-bit and positive.
     case BinaryOperator::LAnd:
     case BinaryOperator::LOr:
     case BinaryOperator::LT:
@@ -1729,65 +1712,108 @@
     case BinaryOperator::GE:
     case BinaryOperator::EQ:
     case BinaryOperator::NE:
-      return true;
+      return IntRange::forBoolType();
 
     // Operations with opaque sources are black-listed.
     case BinaryOperator::PtrMemD:
     case BinaryOperator::PtrMemI:
-      return false;
+      return IntRange::forType(C, E->getType());
 
     // Left shift gets black-listed based on a judgement call.
     case BinaryOperator::Shl:
-      return false;
+      return IntRange::forType(C, E->getType());
 
     // Various special cases.
     case BinaryOperator::Shr:
-      return IsExprValueWithinWidth(C, BO->getLHS(), Width);
+      // TODO: if the RHS is constant, change the width as appropriate.
+      return GetExprRange(C, BO->getLHS(), MaxWidth);
     case BinaryOperator::Comma:
-      return IsExprValueWithinWidth(C, BO->getRHS(), Width);
+      return GetExprRange(C, BO->getRHS(), MaxWidth);
+
     case BinaryOperator::Sub:
       if (BO->getLHS()->getType()->isPointerType())
-        return false;
+        return IntRange::forType(C, E->getType());
       // fallthrough
       
-    // Any other operator is okay if the operands are
-    // promoted from expressions of appropriate size.
     default:
-      return IsExprValueWithinWidth(C, BO->getLHS(), Width) &&
-             IsExprValueWithinWidth(C, BO->getRHS(), Width);
+      break;
     }
+
+    // Treat every other operator as if it were closed on the
+    // narrowest type that encompasses both operands.
+    IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth);
+    IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth);
+    return IntRange::join(L, R);
   }
 
   if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
     switch (UO->getOpcode()) {
     // Boolean-valued operations are white-listed.
     case UnaryOperator::LNot:
-      return true;
+      return IntRange::forBoolType();
 
     // Operations with opaque sources are black-listed.
     case UnaryOperator::Deref:
     case UnaryOperator::AddrOf: // should be impossible
-      return false;
-
     case UnaryOperator::OffsetOf:
-      return false;
+      return IntRange::forType(C, E->getType());
 
     default:
-      return IsExprValueWithinWidth(C, UO->getSubExpr(), Width);
+      return GetExprRange(C, UO->getSubExpr(), MaxWidth);
     }
   }
 
-  // Don't diagnose if the expression is an integer constant
-  // whose value in the target type is the same as it was
-  // in the original type.
-  Expr::EvalResult result;
-  if (E->Evaluate(result, C))
-    if (IsSameIntAfterCast(result.Val, Width))
-      return true;
+  FieldDecl *BitField = E->getBitField();
+  if (BitField) {
+    llvm::APSInt BitWidthAP = BitField->getBitWidth()->EvaluateAsInt(C);
+    unsigned BitWidth = BitWidthAP.getZExtValue();
+
+    return IntRange(BitWidth, BitField->getType()->isUnsignedIntegerType());
+  }
+
+  return IntRange::forType(C, E->getType());
+}
+
+/// Checks whether the given value, which currently has the given
+/// source semantics, has the same value when coerced through the
+/// target semantics.
+bool IsSameFloatAfterCast(const llvm::APFloat &value,
+                          const llvm::fltSemantics &Src,
+                          const llvm::fltSemantics &Tgt) {
+  llvm::APFloat truncated = value;
+
+  bool ignored;
+  truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored);
+  truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored);
 
-  return false;
+  return truncated.bitwiseIsEqual(value);
 }
 
+/// Checks whether the given value, which currently has the given
+/// source semantics, has the same value when coerced through the
+/// target semantics.
+///
+/// The value might be a vector of floats (or a complex number).
+bool IsSameFloatAfterCast(const APValue &value,
+                          const llvm::fltSemantics &Src,
+                          const llvm::fltSemantics &Tgt) {
+  if (value.isFloat())
+    return IsSameFloatAfterCast(value.getFloat(), Src, Tgt);
+
+  if (value.isVector()) {
+    for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i)
+      if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt))
+        return false;
+    return true;
+  }
+
+  assert(value.isComplexFloat());
+  return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) &&
+          IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
+}
+
+} // end anonymous namespace
+
 /// \brief Implements -Wsign-compare.
 ///
 /// \param lex the left-hand expression
@@ -1801,53 +1827,74 @@
   if (ExprEvalContexts.back().Context == Unevaluated)
     return;
 
+  // If either expression is value-dependent, don't warn. We'll get another
+  // chance at instantiation time.
+  if (lex->isValueDependent() || rex->isValueDependent())
+    return;
+
   QualType lt = lex->getType(), rt = rex->getType();
 
   // Only warn if both operands are integral.
   if (!lt->isIntegerType() || !rt->isIntegerType())
     return;
 
-  // If either expression is value-dependent, don't warn. We'll get another
-  // chance at instantiation time.
-  if (lex->isValueDependent() || rex->isValueDependent())
-    return;
+  // In C, the width of a bitfield determines its type, and the
+  // declared type only contributes the signedness.  This duplicates
+  // the work that will later be done by UsualUnaryConversions.
+  // Eventually, this check will be reorganized in a way that avoids
+  // this duplication.
+  if (!getLangOptions().CPlusPlus) {
+    QualType tmp;
+    tmp = Context.isPromotableBitField(lex);
+    if (!tmp.isNull()) lt = tmp;
+    tmp = Context.isPromotableBitField(rex);
+    if (!tmp.isNull()) rt = tmp;
+  }
 
   // The rule is that the signed operand becomes unsigned, so isolate the
   // signed operand.
-  Expr *signedOperand, *unsignedOperand;
+  Expr *signedOperand = lex, *unsignedOperand = rex;
+  QualType signedType = lt, unsignedType = rt;
   if (lt->isSignedIntegerType()) {
     if (rt->isSignedIntegerType()) return;
-    signedOperand = lex;
-    unsignedOperand = rex;
   } else {
     if (!rt->isSignedIntegerType()) return;
-    signedOperand = rex;
-    unsignedOperand = lex;
+    std::swap(signedOperand, unsignedOperand);
+    std::swap(signedType, unsignedType);
   }
 
+  unsigned unsignedWidth = Context.getIntWidth(unsignedType);
+  unsigned signedWidth = Context.getIntWidth(signedType);
+
   // If the unsigned type is strictly smaller than the signed type,
   // then (1) the result type will be signed and (2) the unsigned
   // value will fit fully within the signed type, and thus the result
   // of the comparison will be exact.
-  if (Context.getIntWidth(signedOperand->getType()) >
-      Context.getIntWidth(unsignedOperand->getType()))
+  if (signedWidth > unsignedWidth)
     return;
 
-  // If the value is a non-negative integer constant, then the
-  // signed->unsigned conversion won't change it.
-  if (IsSignBitProvablyZero(Context, signedOperand))
+  // Otherwise, calculate the effective ranges.
+  IntRange signedRange = GetExprRange(Context, signedOperand, signedWidth);
+  IntRange unsignedRange = GetExprRange(Context, unsignedOperand, unsignedWidth);
+
+  // We should never be unable to prove that the unsigned operand is
+  // non-negative.
+  assert(unsignedRange.NonNegative && "unsigned range includes negative?");
+
+  // If the signed operand is non-negative, then the signed->unsigned
+  // conversion won't change it.
+  if (signedRange.NonNegative)
     return;
 
   // For (in)equality comparisons, if the unsigned operand is a
   // constant which cannot collide with a overflowed signed operand,
   // then reinterpreting the signed operand as unsigned will not
   // change the result of the comparison.
-  if (Equality && IsSignBitProvablyZero(Context, unsignedOperand))
+  if (Equality && unsignedRange.Width < unsignedWidth)
     return;
 
   Diag(OpLoc, PD)
-    << lex->getType() << rex->getType()
-    << lex->getSourceRange() << rex->getSourceRange();
+    << lt << rt << lex->getSourceRange() << rex->getSourceRange();
 }
 
 /// Diagnose an implicit cast;  purely a helper for CheckImplicitConversion.
@@ -1925,20 +1972,18 @@
     return;
   }
 
-  unsigned SourceWidth, TargetWidth;
-  bool SourceSigned, TargetSigned;
-
-  if (!getIntProperties(Context, Source, SourceWidth, SourceSigned) ||
-      !getIntProperties(Context, Target, TargetWidth, TargetSigned))
+  if (!Source->isIntegerType() || !Target->isIntegerType())
     return;
 
-  if (SourceWidth > TargetWidth) {
-    if (IsExprValueWithinWidth(Context, E, TargetWidth))
-      return;
+  IntRange SourceRange = GetExprRange(Context, E, Context.getIntWidth(E->getType()));
+  IntRange TargetRange = IntRange::forCanonicalType(Context, Target);
+
+  // FIXME: also signed<->unsigned?
 
+  if (SourceRange.Width > TargetRange.Width) {
     // People want to build with -Wshorten-64-to-32 and not -Wconversion
     // and by god we'll let them.
-    if (SourceWidth == 64 && TargetWidth == 32)
+    if (SourceRange.Width == 64 && TargetRange.Width == 32)
       return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_64_32);
     return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_precision);
   }

Modified: cfe/trunk/test/Sema/compare.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/compare.c?rev=92823&r1=92822&r2=92823&view=diff

==============================================================================
--- cfe/trunk/test/Sema/compare.c (original)
+++ cfe/trunk/test/Sema/compare.c Tue Jan  5 23:24:50 2010
@@ -233,3 +233,36 @@
   enum en { zero };
   return i > zero;
 }
+
+// PR5937
+int test2(int i32) {
+  struct foo {
+    unsigned int u8 : 8;
+    unsigned long long u31 : 31;
+    unsigned long long u32 : 32;
+    unsigned long long u63 : 63;
+    unsigned long long u64 : 64;
+  } *x;
+  
+  if (x->u8 == i32) { // comparison in int32, exact
+    return 0;
+  } else if (x->u31 == i32) { // comparison in int32, exact
+    return 1;
+  } else if (x->u32 == i32) { // expected-warning {{comparison of integers of different signs}}
+    return 2;
+  } else if (x->u63 == i32) { // comparison in uint64, exact because ==
+    return 3;
+  } else if (x->u64 == i32) { // expected-warning {{comparison of integers of different signs}}
+    return 4;
+  } else {
+    return 5;
+  }
+}
+
+// PR5887
+void test3() {
+  unsigned short x, y;
+  unsigned int z;
+  if ((x > y ? x : y) > z)
+    (void) 0;
+}

Modified: cfe/trunk/test/Sema/conversion.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/conversion.c?rev=92823&r1=92822&r2=92823&view=diff

==============================================================================
--- cfe/trunk/test/Sema/conversion.c (original)
+++ cfe/trunk/test/Sema/conversion.c Tue Jan  5 23:24:50 2010
@@ -235,3 +235,29 @@
 void test16(void) {
   int a = (unsigned long) &test16_external; // expected-warning {{implicit cast loses integer precision}}
 }
+
+// PR 5938
+void test17() {
+  union {
+    unsigned long long a : 8;
+    unsigned long long b : 32;
+    unsigned long long c;
+  } U;
+
+  unsigned int x;
+  x = U.a;
+  x = U.b;
+  x = U.c; // expected-warning {{implicit cast loses integer precision}} 
+}
+
+// PR 5939
+void test18() {
+  union {
+    unsigned long long a : 1;
+    unsigned long long b;
+  } U;
+
+  int x;
+  x = (U.a ? 0 : 1);
+  x = (U.b ? 0 : 1);
+}





More information about the cfe-commits mailing list