[cfe-commits] r103174 - in /cfe/trunk: 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

John McCall rjmccall at apple.com
Thu May 6 01:58:33 PDT 2010


Author: rjmccall
Date: Thu May  6 03:58:33 2010
New Revision: 103174

URL: http://llvm.org/viewvc/llvm-project?rev=103174&view=rev
Log:
Rearchitect -Wconversion and -Wsign-compare.  Instead of computing them
"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.


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

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=103174&r1=103173&r2=103174&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu May  6 03:58:33 2010
@@ -883,6 +883,12 @@
 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;

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=103174&r1=103173&r2=103174&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Thu May  6 03:58:33 2010
@@ -175,8 +175,6 @@
     }
   }
 
-  CheckImplicitConversion(Expr, Ty);
-
   if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
     if (ImpCast->getCastKind() == Kind && BasePath.empty()) {
       ImpCast->setType(Ty);

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=103174&r1=103173&r2=103174&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu May  6 03:58:33 2010
@@ -4456,9 +4456,7 @@
   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);
 };
 
 //===--------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=103174&r1=103173&r2=103174&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu May  6 03:58:33 2010
@@ -1731,8 +1731,14 @@
       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 @@
   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 @@
           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 @@
 /// \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();
+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);
 
-  // Only warn if both operands are integral.
-  if (!lt->isIntegerType() || !rt->isIntegerType())
-    return;
+  Expr *lex = E->getLHS()->IgnoreParenImpCasts();
+  Expr *rex = E->getRHS()->IgnoreParenImpCasts();
 
-  // 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;
+  // 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);
-
-  // 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;
+  // Otherwise, calculate the effective range of the signed operand.
+  IntRange signedRange = GetExprRange(S.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) {
-    // 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;
-  }
+  // 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);
+
+  // 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?");
+
+    if (unsignedRange.Width < comparisonWidth)
+      return;
+  }
 
-  Diag(OpLoc, BinOpc ? diag::warn_mixed_sign_comparison
-                     : diag::warn_mixed_sign_conditional)
-    << lt << rt << lex->getSourceRange() << rex->getSourceRange();
+  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;
-
-  const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr();
-  const Type *Target = Context.getCanonicalType(T).getTypePtr();
+void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
+                             bool *ICContext = 0) {
+  if (E->isTypeDependent() || E->isValueDependent()) return;
+
+  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 @@
   // 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 @@
   // 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 @@
         // 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 @@
     // 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 @@
   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

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=103174&r1=103173&r2=103174&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu May  6 03:58:33 2010
@@ -4081,8 +4081,6 @@
   if (getLangOptions().CPlusPlus)
     return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc);
 
-  CheckSignCompare(LHS, RHS, QuestionLoc);
-
   UsualUnaryConversions(Cond);
   UsualUnaryConversions(LHS);
   UsualUnaryConversions(RHS);
@@ -5274,8 +5272,6 @@
   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);

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=103174&r1=103173&r2=103174&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu May  6 03:58:33 2010
@@ -2113,8 +2113,6 @@
   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 @@
 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)

Modified: cfe/trunk/test/Sema/compare.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/compare.c?rev=103174&r1=103173&r2=103174&view=diff
==============================================================================
--- cfe/trunk/test/Sema/compare.c (original)
+++ cfe/trunk/test/Sema/compare.c Thu May  6 03:58:33 2010
@@ -23,8 +23,8 @@
          ((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 @@
          ((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 @@
          ((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 @@
          ((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 @@
          ((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)) +

Modified: cfe/trunk/test/Sema/conditional-expr.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/conditional-expr.c?rev=103174&r1=103173&r2=103174&view=diff
==============================================================================
--- cfe/trunk/test/Sema/conditional-expr.c (original)
+++ cfe/trunk/test/Sema/conditional-expr.c Thu May  6 03:58:33 2010
@@ -52,7 +52,9 @@
   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 @@
   // 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;
+}

Modified: cfe/trunk/test/Sema/conversion.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/conversion.c?rev=103174&r1=103173&r2=103174&view=diff
==============================================================================
--- cfe/trunk/test/Sema/conversion.c (original)
+++ cfe/trunk/test/Sema/conversion.c Thu May  6 03:58:33 2010
@@ -287,3 +287,13 @@
   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}}  
+}

Modified: cfe/trunk/test/SemaCXX/compare.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/compare.cpp?rev=103174&r1=103173&r2=103174&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/compare.cpp (original)
+++ cfe/trunk/test/SemaCXX/compare.cpp Thu May  6 03:58:33 2010
@@ -19,8 +19,8 @@
          ((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 @@
          ((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 @@
          ((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 @@
          ((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 @@
          ((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
     ;

Modified: cfe/trunk/test/SemaCXX/conditional-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conditional-expr.cpp?rev=103174&r1=103173&r2=103174&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/conditional-expr.cpp (original)
+++ cfe/trunk/test/SemaCXX/conditional-expr.cpp Thu May  6 03:58:33 2010
@@ -238,3 +238,20 @@
     (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);
+  }
+}





More information about the cfe-commits mailing list