forked from OSchip/llvm-project
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. llvm-svn: 103174
This commit is contained in:
parent
9aa35bed45
commit
cc7e5bff5c
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
|
@ -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;
|
||||
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");
|
||||
|
||||
// If either expression is value-dependent, don't warn. We'll get another
|
||||
// chance at instantiation time.
|
||||
if (lex->isValueDependent() || rex->isValueDependent())
|
||||
return;
|
||||
// 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);
|
||||
|
||||
QualType lt = lex->getType(), rt = rex->getType();
|
||||
Expr *lex = E->getLHS()->IgnoreParenImpCasts();
|
||||
Expr *rex = E->getRHS()->IgnoreParenImpCasts();
|
||||
|
||||
// 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;
|
||||
// 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);
|
||||
|
||||
Diag(OpLoc, BinOpc ? diag::warn_mixed_sign_comparison
|
||||
: diag::warn_mixed_sign_conditional)
|
||||
<< lt << rt << lex->getSourceRange() << rex->getSourceRange();
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
|
||||
bool *ICContext = 0) {
|
||||
if (E->isTypeDependent() || E->isValueDependent()) 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();
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)) +
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue