]> granicus.if.org Git - clang/commitdiff
Rearchitect -Wconversion and -Wsign-compare. Instead of computing them
authorJohn McCall <rjmccall@apple.com>
Thu, 6 May 2010 08:58:33 +0000 (08:58 +0000)
committerJohn McCall <rjmccall@apple.com>
Thu, 6 May 2010 08:58:33 +0000 (08:58 +0000)
"bottom-up" when implicit casts and comparisons are inserted, compute them
"top-down" when the full expression is finished.  Makes it easier to
coordinate warnings and thus implement -Wconversion for signedness
conversions without double-warning with -Wsign-compare.  Also makes it possible
to realize that a signedness conversion is okay because the context is
performing the inverse conversion.  Also simplifies some logic that was
trying to calculate the ultimate comparison/result type and getting it wrong.
Also fixes a problem with the C++ explicit casts which are often "implemented"
in the AST with a series of implicit cast expressions.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103174 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.cpp
lib/Sema/Sema.h
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
test/Sema/compare.c
test/Sema/conditional-expr.c
test/Sema/conversion.c
test/SemaCXX/compare.cpp
test/SemaCXX/conditional-expr.cpp

index a62408129cc621961982382e7156d1b4de28baa8..89f892cec13609ba4d6372f8b24b5329c65c86c0 100644 (file)
@@ -883,6 +883,12 @@ def warn_impcast_float_precision : Warning<
 def warn_impcast_float_integer : Warning<
   "implicit cast turns floating-point number into integer: %0 to %1">,
   InGroup<DiagGroup<"conversion">>, DefaultIgnore;
+def warn_impcast_integer_sign : Warning<
+  "implicit cast changes signedness: %0 to %1">,
+  InGroup<DiagGroup<"conversion">>, DefaultIgnore;
+def warn_impcast_integer_sign_conditional : Warning<
+  "operand of ? changes signedness: %0 to %1">,
+  InGroup<DiagGroup<"conversion">>, DefaultIgnore;
 def warn_impcast_integer_precision : Warning<
   "implicit cast loses integer precision: %0 to %1">,
   InGroup<DiagGroup<"conversion">>, DefaultIgnore;
index 755af84ca96035f44ecb1061fe075b6331a5d1ed..a4329786048c892d84ab8d5c38d2e19a15aac78a 100644 (file)
@@ -175,8 +175,6 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
     }
   }
 
-  CheckImplicitConversion(Expr, Ty);
-
   if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
     if (ImpCast->getCastKind() == Kind && BasePath.empty()) {
       ImpCast->setType(Ty);
index 45ea09e4f278d29704156242c55b10d7961c8f3e..8656f4883acdbe9c1bd08340860d72b87fac5db4 100644 (file)
@@ -4456,9 +4456,7 @@ private:
   void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
                             SourceLocation ReturnLoc);
   void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
-  void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc,
-                        const BinaryOperator::Opcode* BinOpc = 0);
-  void CheckImplicitConversion(Expr *E, QualType Target);
+  void CheckImplicitConversions(Expr *E);
 };
 
 //===--------------------------------------------------------------------===//
index e60dfd3452c7335c45cca1cfc1e463024b0c009f..8474944f06c01f269e27695f42e13a9b04382367 100644 (file)
@@ -1731,8 +1731,14 @@ struct IntRange {
       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();
+
+    if (const EnumType *ET = dyn_cast<EnumType>(T)) {
+      EnumDecl *Enum = ET->getDecl();
+      unsigned NumPositive = Enum->getNumPositiveBits();
+      unsigned NumNegative = Enum->getNumNegativeBits();
+
+      return IntRange(std::max(NumPositive, NumNegative), NumNegative == 0);
+    }
 
     const BuiltinType *BT = cast<BuiltinType>(T);
     assert(BT->isInteger());
@@ -1974,6 +1980,10 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
   return IntRange::forType(C, E->getType());
 }
 
+IntRange GetExprRange(ASTContext &C, Expr *E) {
+  return GetExprRange(C, E, C.getIntWidth(E->getType()));
+}
+
 /// Checks whether the given value, which currently has the given
 /// source semantics, has the same value when coerced through the
 /// target semantics.
@@ -2012,7 +2022,40 @@ bool IsSameFloatAfterCast(const APValue &value,
           IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
 }
 
-} // end anonymous namespace
+void AnalyzeImplicitConversions(Sema &S, Expr *E);
+
+bool IsZero(Sema &S, Expr *E) {
+  llvm::APSInt Value;
+  return E->isIntegerConstantExpr(Value, S.Context) && Value == 0;
+}
+
+void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
+  BinaryOperator::Opcode op = E->getOpcode();
+  if (op == BinaryOperator::LT && IsZero(S, E->getRHS())) {
+    S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
+      << "< 0" << "false"
+      << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+  } else if (op == BinaryOperator::GE && IsZero(S, E->getRHS())) {
+    S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
+      << ">= 0" << "true"
+      << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+  } else if (op == BinaryOperator::GT && IsZero(S, E->getLHS())) {
+    S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
+      << "0 >" << "false" 
+      << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+  } else if (op == BinaryOperator::LE && IsZero(S, E->getLHS())) {
+    S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
+      << "0 <=" << "true" 
+      << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+  }
+}
+
+/// Analyze the operands of the given comparison.  Implements the
+/// fallback case from AnalyzeComparison.
+void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
+  AnalyzeImplicitConversions(S, E->getLHS());
+  AnalyzeImplicitConversions(S, E->getRHS());
+}
 
 /// \brief Implements -Wsign-compare.
 ///
@@ -2020,138 +2063,85 @@ bool IsSameFloatAfterCast(const APValue &value,
 /// \param rex the right-hand expression
 /// \param OpLoc the location of the joining operator
 /// \param BinOpc binary opcode or 0
-void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
-                            const BinaryOperator::Opcode* BinOpc) {
-  // Don't warn if we're in an unevaluated context.
-  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;
-
-  // 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;
-  }
-
-  if (const EnumType *E = lt->getAs<EnumType>())
-    lt = E->getDecl()->getPromotionType();
-  if (const EnumType *E = rt->getAs<EnumType>())
-    rt = E->getDecl()->getPromotionType();
-
-  // The rule is that the signed operand becomes unsigned, so isolate the
-  // signed operand.
-  Expr *signedOperand = lex, *unsignedOperand = rex;
-  QualType signedType = lt, unsignedType = rt;
-  if (lt->isSignedIntegerType()) {
-    if (rt->isSignedIntegerType()) return;
+void AnalyzeComparison(Sema &S, BinaryOperator *E) {
+  // The type the comparison is being performed in.
+  QualType T = E->getLHS()->getType();
+  assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType())
+         && "comparison with mismatched types");
+
+  // We don't do anything special if this isn't an unsigned integral
+  // comparison:  we're only interested in integral comparisons, and
+  // signed comparisons only happen in cases we don't care to warn about.
+  if (!T->isUnsignedIntegerType())
+    return AnalyzeImpConvsInComparison(S, E);
+
+  Expr *lex = E->getLHS()->IgnoreParenImpCasts();
+  Expr *rex = E->getRHS()->IgnoreParenImpCasts();
+
+  // Check to see if one of the (unmodified) operands is of different
+  // signedness.
+  Expr *signedOperand, *unsignedOperand;
+  if (lex->getType()->isSignedIntegerType()) {
+    assert(!rex->getType()->isSignedIntegerType() &&
+           "unsigned comparison between two signed integer expressions?");
+    signedOperand = lex;
+    unsignedOperand = rex;
+  } else if (rex->getType()->isSignedIntegerType()) {
+    signedOperand = rex;
+    unsignedOperand = lex;
   } else {
-    if (!rt->isSignedIntegerType()) return;
-    std::swap(signedOperand, unsignedOperand);
-    std::swap(signedType, unsignedType);
+    CheckTrivialUnsignedComparison(S, E);
+    return AnalyzeImpConvsInComparison(S, E);
   }
 
-  unsigned unsignedWidth = Context.getIntWidth(unsignedType);
-  unsigned signedWidth = Context.getIntWidth(signedType);
+  // Otherwise, calculate the effective range of the signed operand.
+  IntRange signedRange = GetExprRange(S.Context, signedOperand);
 
-  // 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 (signedWidth > unsignedWidth)
-    return;
+  // Go ahead and analyze implicit conversions in the operands.  Note
+  // that we skip the implicit conversions on both sides.
+  AnalyzeImplicitConversions(S, lex);
+  AnalyzeImplicitConversions(S, rex);
 
-  // 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) {
-    // Emit warnings for comparisons of unsigned to integer constant 0.
-    //   always false: x < 0  (or 0 > x)
-    //   always true:  x >= 0 (or 0 <= x)
-    llvm::APSInt X;
-    if (BinOpc && signedOperand->isIntegerConstantExpr(X, Context) && X == 0) {
-      if (signedOperand != lex) {
-        if (*BinOpc == BinaryOperator::LT) {
-          Diag(OpLoc, diag::warn_lunsigned_always_true_comparison)
-            << "< 0" << "false"
-            << lex->getSourceRange() << rex->getSourceRange();
-        }
-        else if (*BinOpc == BinaryOperator::GE) {
-          Diag(OpLoc, diag::warn_lunsigned_always_true_comparison)
-            << ">= 0" << "true"
-            << lex->getSourceRange() << rex->getSourceRange();
-        }
-      }
-      else {
-        if (*BinOpc == BinaryOperator::GT) {
-          Diag(OpLoc, diag::warn_runsigned_always_true_comparison)
-            << "0 >" << "false" 
-            << lex->getSourceRange() << rex->getSourceRange();
-        } 
-        else if (*BinOpc == BinaryOperator::LE) {
-          Diag(OpLoc, diag::warn_runsigned_always_true_comparison)
-            << "0 <=" << "true" 
-            << lex->getSourceRange() << rex->getSourceRange();
-        }
-      }
-    }
-    return;
-  }
+  // If the signed range is non-negative, -Wsign-compare won't fire,
+  // but we should still check for comparisons which are always true
+  // or false.
+  if (signedRange.NonNegative)
+    return CheckTrivialUnsignedComparison(S, E);
 
   // 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 (BinOpc &&
-      (*BinOpc == BinaryOperator::EQ || *BinOpc == BinaryOperator::NE) &&
-      unsignedRange.Width < unsignedWidth)
-    return;
+  if (E->isEqualityOp()) {
+    unsigned comparisonWidth = S.Context.getIntWidth(T);
+    IntRange unsignedRange = GetExprRange(S.Context, unsignedOperand);
+
+    // We should never be unable to prove that the unsigned operand is
+    // non-negative.
+    assert(unsignedRange.NonNegative && "unsigned range includes negative?");
 
-  Diag(OpLoc, BinOpc ? diag::warn_mixed_sign_comparison
-                     : diag::warn_mixed_sign_conditional)
-    << lt << rt << lex->getSourceRange() << rex->getSourceRange();
+    if (unsignedRange.Width < comparisonWidth)
+      return;
+  }
+
+  S.Diag(E->getOperatorLoc(), diag::warn_mixed_sign_comparison)
+    << lex->getType() << rex->getType()
+    << lex->getSourceRange() << rex->getSourceRange();
 }
 
 /// Diagnose an implicit cast;  purely a helper for CheckImplicitConversion.
-static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) {
+void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) {
   S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange();
 }
 
-/// Implements -Wconversion.
-void Sema::CheckImplicitConversion(Expr *E, QualType T) {
-  // Don't diagnose in unevaluated contexts.
-  if (ExprEvalContexts.back().Context == Sema::Unevaluated)
-    return;
-
-  // Don't diagnose for value-dependent expressions.
-  if (E->isValueDependent())
-    return;
+void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
+                             bool *ICContext = 0) {
+  if (E->isTypeDependent() || E->isValueDependent()) return;
 
-  const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr();
-  const Type *Target = Context.getCanonicalType(T).getTypePtr();
+  const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
+  const Type *Target = S.Context.getCanonicalType(T).getTypePtr();
+  if (Source == Target) return;
+  if (Target->isDependentType()) return;
 
   // Never diagnose implicit casts to bool.
   if (Target->isSpecificBuiltinType(BuiltinType::Bool))
@@ -2160,7 +2150,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
   // Strip vector types.
   if (isa<VectorType>(Source)) {
     if (!isa<VectorType>(Target))
-      return DiagnoseImpCast(*this, E, T, diag::warn_impcast_vector_scalar);
+      return DiagnoseImpCast(S, E, T, diag::warn_impcast_vector_scalar);
 
     Source = cast<VectorType>(Source)->getElementType().getTypePtr();
     Target = cast<VectorType>(Target)->getElementType().getTypePtr();
@@ -2169,7 +2159,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
   // Strip complex types.
   if (isa<ComplexType>(Source)) {
     if (!isa<ComplexType>(Target))
-      return DiagnoseImpCast(*this, E, T, diag::warn_impcast_complex_scalar);
+      return DiagnoseImpCast(S, E, T, diag::warn_impcast_complex_scalar);
 
     Source = cast<ComplexType>(Source)->getElementType().getTypePtr();
     Target = cast<ComplexType>(Target)->getElementType().getTypePtr();
@@ -2189,15 +2179,15 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
         // Don't warn about float constants that are precisely
         // representable in the target type.
         Expr::EvalResult result;
-        if (E->Evaluate(result, Context)) {
+        if (E->Evaluate(result, S.Context)) {
           // Value might be a float, a float vector, or a float complex.
           if (IsSameFloatAfterCast(result.Val,
-                     Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
-                     Context.getFloatTypeSemantics(QualType(SourceBT, 0))))
+                   S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
+                   S.Context.getFloatTypeSemantics(QualType(SourceBT, 0))))
             return;
         }
 
-        DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_precision);
+        DiagnoseImpCast(S, E, T, diag::warn_impcast_float_precision);
       }
       return;
     }
@@ -2205,7 +2195,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
     // If the target is integral, always warn.
     if ((TargetBT && TargetBT->isInteger()))
       // TODO: don't warn for integer values?
-      return DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_integer);
+      DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer);
 
     return;
   }
@@ -2213,22 +2203,158 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
   if (!Source->isIntegerType() || !Target->isIntegerType())
     return;
 
-  IntRange SourceRange = GetExprRange(Context, E, Context.getIntWidth(E->getType()));
-  IntRange TargetRange = IntRange::forCanonicalType(Context, Target);
-
-  // FIXME: also signed<->unsigned?
+  IntRange SourceRange = GetExprRange(S.Context, E);
+  IntRange TargetRange = IntRange::forCanonicalType(S.Context, Target);
 
   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 (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);
+      return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_64_32);
+    return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_precision);
+  }
+
+  if ((TargetRange.NonNegative && !SourceRange.NonNegative) ||
+      (!TargetRange.NonNegative && SourceRange.NonNegative &&
+       SourceRange.Width == TargetRange.Width)) {
+    unsigned DiagID = diag::warn_impcast_integer_sign;
+
+    // Traditionally, gcc has warned about this under -Wsign-compare.
+    // We also want to warn about it in -Wconversion.
+    // So if -Wconversion is off, use a completely identical diagnostic
+    // in the sign-compare group.
+    // The conditional-checking code will 
+    if (ICContext) {
+      DiagID = diag::warn_impcast_integer_sign_conditional;
+      *ICContext = true;
+    }
+
+    return DiagnoseImpCast(S, E, T, DiagID);
   }
 
   return;
 }
 
+void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T);
+
+void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
+                             bool &ICContext) {
+  E = E->IgnoreParenImpCasts();
+
+  if (isa<ConditionalOperator>(E))
+    return CheckConditionalOperator(S, cast<ConditionalOperator>(E), T);
+
+  AnalyzeImplicitConversions(S, E);
+  if (E->getType() != T)
+    return CheckImplicitConversion(S, E, T, &ICContext);
+  return;
+}
+
+void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) {
+  AnalyzeImplicitConversions(S, E->getCond());
+
+  bool Suspicious = false;
+  CheckConditionalOperand(S, E->getTrueExpr(), T, Suspicious);
+  CheckConditionalOperand(S, E->getFalseExpr(), T, Suspicious);
+
+  // If -Wconversion would have warned about either of the candidates
+  // for a signedness conversion to the context type...
+  if (!Suspicious) return;
+
+  // ...but it's currently ignored...
+  if (S.Diags.getDiagnosticLevel(diag::warn_impcast_integer_sign_conditional))
+    return;
+
+  // ...and -Wsign-compare isn't...
+  if (!S.Diags.getDiagnosticLevel(diag::warn_mixed_sign_conditional))
+    return;
+
+  // ...then check whether it would have warned about either of the
+  // candidates for a signedness conversion to the condition type.
+  if (E->getType() != T) {
+    Suspicious = false;
+    CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(),
+                            E->getType(), &Suspicious);
+    if (!Suspicious)
+      CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(),
+                              E->getType(), &Suspicious);
+    if (!Suspicious)
+      return;
+  }
+
+  // If so, emit a diagnostic under -Wsign-compare.
+  Expr *lex = E->getTrueExpr()->IgnoreParenImpCasts();
+  Expr *rex = E->getFalseExpr()->IgnoreParenImpCasts();
+  S.Diag(E->getQuestionLoc(), diag::warn_mixed_sign_conditional)
+    << lex->getType() << rex->getType()
+    << lex->getSourceRange() << rex->getSourceRange();
+}
+
+/// AnalyzeImplicitConversions - Find and report any interesting
+/// implicit conversions in the given expression.  There are a couple
+/// of competing diagnostics here, -Wconversion and -Wsign-compare.
+void AnalyzeImplicitConversions(Sema &S, Expr *OrigE) {
+  QualType T = OrigE->getType();
+  Expr *E = OrigE->IgnoreParenImpCasts();
+
+  // For conditional operators, we analyze the arguments as if they
+  // were being fed directly into the output.
+  if (isa<ConditionalOperator>(E)) {
+    ConditionalOperator *CO = cast<ConditionalOperator>(E);
+    CheckConditionalOperator(S, CO, T);
+    return;
+  }
+
+  // Go ahead and check any implicit conversions we might have skipped.
+  // The non-canonical typecheck is just an optimization;
+  // CheckImplicitConversion will filter out dead implicit conversions.
+  if (E->getType() != T)
+    CheckImplicitConversion(S, E, T);
+
+  // Now continue drilling into this expression.
+
+  // Skip past explicit casts.
+  if (isa<ExplicitCastExpr>(E)) {
+    E = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreParenImpCasts();
+    return AnalyzeImplicitConversions(S, E);
+  }
+
+  // Do a somewhat different check with comparison operators.
+  if (isa<BinaryOperator>(E) && cast<BinaryOperator>(E)->isComparisonOp())
+    return AnalyzeComparison(S, cast<BinaryOperator>(E));
+
+  // These break the otherwise-useful invariant below.  Fortunately,
+  // we don't really need to recurse into them, because any internal
+  // expressions should have been analyzed already when they were
+  // built into statements.
+  if (isa<StmtExpr>(E)) return;
+
+  // Don't descend into unevaluated contexts.
+  if (isa<SizeOfAlignOfExpr>(E)) return;
+
+  // Now just recurse over the expression's children.
+  for (Stmt::child_iterator I = E->child_begin(), IE = E->child_end();
+         I != IE; ++I)
+    AnalyzeImplicitConversions(S, cast<Expr>(*I));
+}
+
+} // end anonymous namespace
+
+/// Diagnoses "dangerous" implicit conversions within the given
+/// expression (which is a full expression).  Implements -Wconversion
+/// and -Wsign-compare.
+void Sema::CheckImplicitConversions(Expr *E) {
+  // Don't diagnose in unevaluated contexts.
+  if (ExprEvalContexts.back().Context == Sema::Unevaluated)
+    return;
+
+  // Don't diagnose for value- or type-dependent expressions.
+  if (E->isTypeDependent() || E->isValueDependent())
+    return;
+
+  AnalyzeImplicitConversions(*this, E);
+}
+
 /// CheckParmsForFunctionDef - Check that the parameters of the given
 /// function are appropriate for the definition of a function. This
 /// takes care of any checks that cannot be performed on the
index 869d6df2f0949b78cd0ac373abddac70a01031c9..8bfb4ca1004262c7322c7716e1563b82e3968d3a 100644 (file)
@@ -4081,8 +4081,6 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
   if (getLangOptions().CPlusPlus)
     return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc);
 
-  CheckSignCompare(LHS, RHS, QuestionLoc);
-
   UsualUnaryConversions(Cond);
   UsualUnaryConversions(LHS);
   UsualUnaryConversions(RHS);
@@ -5274,8 +5272,6 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
   if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
     return CheckVectorCompareOperands(lex, rex, Loc, isRelational);
 
-  CheckSignCompare(lex, rex, Loc, &Opc);
-
   // C99 6.5.8p3 / C99 6.5.9p4
   if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
     UsualArithmeticConversions(lex, rex);
index 425fc2d15aa5331d9cc648055a1e77726c3212c0..217d2307aa06a58163c4619582ef189c506ef8ff 100644 (file)
@@ -2113,8 +2113,6 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
   if (LHS->isTypeDependent() || RHS->isTypeDependent())
     return Context.DependentTy;
 
-  CheckSignCompare(LHS, RHS, QuestionLoc);
-
   // C++0x 5.16p2
   //   If either the second or the third operand has type (cv) void, ...
   QualType LTy = LHS->getType();
@@ -2529,6 +2527,9 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
 Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr) {
   assert(SubExpr && "sub expression can't be null!");
 
+  // Check any implicit conversions within the expression.
+  CheckImplicitConversions(SubExpr);
+
   unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
   assert(ExprTemporaries.size() >= FirstTemporary);
   if (ExprTemporaries.size() == FirstTemporary)
index 631b69420293376aae5126491081087db53601d8..f997dc1a73bf40c483117e2caa24dd852844f98a 100644 (file)
@@ -23,8 +23,8 @@ int ints(long a, unsigned long b) {
          ((signed char) a == b) +  // expected-warning {{comparison of integers of different signs}}
          ((long) a == (unsigned long) b) +  // expected-warning {{comparison of integers of different signs}}
          ((int) a == (unsigned int) b) +  // expected-warning {{comparison of integers of different signs}}
-         ((short) a == (unsigned short) b) +  // expected-warning {{comparison of integers of different signs}}
-         ((signed char) a == (unsigned char) b) +  // expected-warning {{comparison of integers of different signs}}
+         ((short) a == (unsigned short) b) +
+         ((signed char) a == (unsigned char) b) +
          (a < (unsigned long) b) +  // expected-warning {{comparison of integers of different signs}}
          (a < (unsigned int) b) +
          (a < (unsigned short) b) +
@@ -35,8 +35,8 @@ int ints(long a, unsigned long b) {
          ((signed char) a < b) +  // expected-warning {{comparison of integers of different signs}}
          ((long) a < (unsigned long) b) +  // expected-warning {{comparison of integers of different signs}}
          ((int) a < (unsigned int) b) +  // expected-warning {{comparison of integers of different signs}}
-         ((short) a < (unsigned short) b) +  // expected-warning {{comparison of integers of different signs}}
-         ((signed char) a < (unsigned char) b) +  // expected-warning {{comparison of integers of different signs}}
+         ((short) a < (unsigned short) b) +
+         ((signed char) a < (unsigned char) b) +
 
          // (A,b)
          (A == (unsigned long) b) +
@@ -87,8 +87,8 @@ int ints(long a, unsigned long b) {
          ((signed char) a < B) +
          ((long) a < (unsigned long) B) +  // expected-warning {{comparison of integers of different signs}}
          ((int) a < (unsigned int) B) +  // expected-warning {{comparison of integers of different signs}}
-         ((short) a < (unsigned short) B) +  // expected-warning {{comparison of integers of different signs}}
-         ((signed char) a < (unsigned char) B) +  // expected-warning {{comparison of integers of different signs}}
+         ((short) a < (unsigned short) B) +
+         ((signed char) a < (unsigned char) B) +
 
          // (C,b)
          (C == (unsigned long) b) +
@@ -139,8 +139,8 @@ int ints(long a, unsigned long b) {
          ((signed char) a < C) +
          ((long) a < (unsigned long) C) +  // expected-warning {{comparison of integers of different signs}}
          ((int) a < (unsigned int) C) +  // expected-warning {{comparison of integers of different signs}}
-         ((short) a < (unsigned short) C) +  // expected-warning {{comparison of integers of different signs}}
-         ((signed char) a < (unsigned char) C) +  // expected-warning {{comparison of integers of different signs}}
+         ((short) a < (unsigned short) C) +
+         ((signed char) a < (unsigned char) C) +
 
          // (0x80000,b)
          (0x80000 == (unsigned long) b) +
@@ -191,8 +191,8 @@ int ints(long a, unsigned long b) {
          ((signed char) a < 0x80000) +
          ((long) a < (unsigned long) 0x80000) +  // expected-warning {{comparison of integers of different signs}}
          ((int) a < (unsigned int) 0x80000) +  // expected-warning {{comparison of integers of different signs}}
-         ((short) a < (unsigned short) 0x80000) +  // expected-warning {{comparison of integers of different signs}}
-         ((signed char) a < (unsigned char) 0x80000) +  // expected-warning {{comparison of integers of different signs}}
+         ((short) a < (unsigned short) 0x80000) +
+         ((signed char) a < (unsigned char) 0x80000) +
 
          // We should be able to avoid warning about this.
          (b != (a < 4 ? 1 : 2)) +
index 5e2c1a46248a3459804c03b1333ae7641da8f948..6e248bc3cfec143d1a39a04104e0a744c7730612 100644 (file)
@@ -52,7 +52,9 @@ void foo() {
   enum Enum { EVal };
   test0 = test0 ? EVal : test0;
   test0 = test0 ? EVal : (int) test0; // okay: EVal is an int
-  test0 = test0 ? (unsigned) EVal : (int) test0; // expected-warning {{operands of ? are integers of different signs}}
+  test0 = test0 ? // expected-warning {{operands of ? are integers of different signs}}
+                  (unsigned) EVal
+                : (int) test0;
 }
 
 int Postgresql() {
@@ -68,3 +70,8 @@ int f0(int a) {
   // GCC considers this a warning.
   return a ? f1() : nil; // expected-warning {{pointer/integer type mismatch in conditional expression ('int' and 'void *')}} expected-warning {{incompatible pointer to integer conversion returning 'void *' from a function with result type 'int'}}
 }
+
+int f2(int x) {
+  // We can suppress this because the immediate context wants an int.
+  return (x != 0) ? 0U : x;
+}
index addedd91f7e83649db689e339c72379e650cb5a5..5b09ec6d9708a3bfb526b3562cdefca8adf6d645 100644 (file)
@@ -287,3 +287,13 @@ void test_7676608(void) {
   char c = 5;
   f7676608(c *= q);
 }
+
+// <rdar://problem/7904686>
+void test_7904686(void) {
+  const int i = -1;
+  unsigned u1 = i; // expected-warning {{implicit cast changes signedness}}  
+  u1 = i; // expected-warning {{implicit cast changes signedness}}  
+
+  unsigned u2 = -1; // expected-warning {{implicit cast changes signedness}}  
+  u2 = -1; // expected-warning {{implicit cast changes signedness}}  
+}
index cd243e3d6b23f3908b365d4a1f99dc6589d3339b..4790347220d68cc2321d61dcde9a7723a145fecd 100644 (file)
@@ -19,8 +19,8 @@ int test0(long a, unsigned long b) {
          ((signed char) a == b) +  // expected-warning {{comparison of integers of different signs}}
          ((long) a == (unsigned long) b) +  // expected-warning {{comparison of integers of different signs}}
          ((int) a == (unsigned int) b) +  // expected-warning {{comparison of integers of different signs}}
-         ((short) a == (unsigned short) b) +  // expected-warning {{comparison of integers of different signs}}
-         ((signed char) a == (unsigned char) b) +  // expected-warning {{comparison of integers of different signs}}
+         ((short) a == (unsigned short) b) +
+         ((signed char) a == (unsigned char) b) +
          (a < (unsigned long) b) +  // expected-warning {{comparison of integers of different signs}}
          (a < (unsigned int) b) +
          (a < (unsigned short) b) +
@@ -31,8 +31,8 @@ int test0(long a, unsigned long b) {
          ((signed char) a < b) +  // expected-warning {{comparison of integers of different signs}}
          ((long) a < (unsigned long) b) +  // expected-warning {{comparison of integers of different signs}}
          ((int) a < (unsigned int) b) +  // expected-warning {{comparison of integers of different signs}}
-         ((short) a < (unsigned short) b) +  // expected-warning {{comparison of integers of different signs}}
-         ((signed char) a < (unsigned char) b) +  // expected-warning {{comparison of integers of different signs}}
+         ((short) a < (unsigned short) b) +
+         ((signed char) a < (unsigned char) b) +
 
          // (A,b)
          (A == (unsigned long) b) +
@@ -83,8 +83,8 @@ int test0(long a, unsigned long b) {
          ((signed char) a < B) +
          ((long) a < (unsigned long) B) +  // expected-warning {{comparison of integers of different signs}}
          ((int) a < (unsigned int) B) +  // expected-warning {{comparison of integers of different signs}}
-         ((short) a < (unsigned short) B) +  // expected-warning {{comparison of integers of different signs}}
-         ((signed char) a < (unsigned char) B) +  // expected-warning {{comparison of integers of different signs}}
+         ((short) a < (unsigned short) B) +
+         ((signed char) a < (unsigned char) B) +
 
          // (C,b)
          (C == (unsigned long) b) +
@@ -135,8 +135,8 @@ int test0(long a, unsigned long b) {
          ((signed char) a < C) +
          ((long) a < (unsigned long) C) +  // expected-warning {{comparison of integers of different signs}}
          ((int) a < (unsigned int) C) +  // expected-warning {{comparison of integers of different signs}}
-         ((short) a < (unsigned short) C) +  // expected-warning {{comparison of integers of different signs}}
-         ((signed char) a < (unsigned char) C) +  // expected-warning {{comparison of integers of different signs}}
+         ((short) a < (unsigned short) C) +
+         ((signed char) a < (unsigned char) C) +
 
          // (0x80000,b)
          (0x80000 == (unsigned long) b) +
@@ -187,8 +187,8 @@ int test0(long a, unsigned long b) {
          ((signed char) a < 0x80000) +
          ((long) a < (unsigned long) 0x80000) +  // expected-warning {{comparison of integers of different signs}}
          ((int) a < (unsigned int) 0x80000) +  // expected-warning {{comparison of integers of different signs}}
-         ((short) a < (unsigned short) 0x80000) +  // expected-warning {{comparison of integers of different signs}}
-         ((signed char) a < (unsigned char) 0x80000) +  // expected-warning {{comparison of integers of different signs}}
+         ((short) a < (unsigned short) 0x80000) +
+         ((signed char) a < (unsigned char) 0x80000) +
 
          10
     ;
index a812a5920d65a50424ba0ebfe78fb7e760cdb241..f1fe8ba79bbb6c2fd7591e1f07c819a57017f591 100644 (file)
@@ -238,3 +238,20 @@ namespace PR6757 {
     (void)(true ? Bar() : Foo3()); // expected-error{{no viable constructor copying temporary}}
   }
 }
+
+// Reduced from selfhost.
+namespace test1 {
+  struct A {
+    enum Foo {
+      fa, fb, fc, fd, fe, ff
+    };
+
+    Foo x();
+  };
+
+  void foo(int);
+
+  void test(A *a) {
+    foo(a ? a->x() : 0);
+  }
+}