forked from OSchip/llvm-project
Split out -Wconversion warnings about constant precision into their
own subcategory, -Wconstant-conversion, which is on by default. Tweak the constant folder to give better results in the invalid case of a negative shift amount. Implements rdar://problem/6792488 llvm-svn: 118636
This commit is contained in:
parent
b332ba3a51
commit
18a2c2c0b9
|
@ -164,10 +164,15 @@ def CharSubscript : DiagGroup<"char-subscripts">;
|
|||
// missing parentheses; it is off by default.
|
||||
def Parentheses : DiagGroup<"parentheses", [DiagGroup<"idiomatic-parentheses">]>;
|
||||
|
||||
// -Wconversion has its own warnings, but we split this one out for
|
||||
// legacy reasons.
|
||||
// -Wconversion has its own warnings, but we split a few out for
|
||||
// legacy reasons:
|
||||
// - some people want just 64-to-32 warnings
|
||||
// - conversion warnings with constant sources are on by default
|
||||
// - bool-to-pointer conversion warnings are on by default
|
||||
def Conversion : DiagGroup<"conversion",
|
||||
[DiagGroup<"shorten-64-to-32">, BoolConversions]>,
|
||||
[DiagGroup<"shorten-64-to-32">,
|
||||
DiagGroup<"constant-conversion">,
|
||||
BoolConversions]>,
|
||||
DiagCategory<"Value Conversion Issue">;
|
||||
|
||||
def Unused : DiagGroup<"unused",
|
||||
|
|
|
@ -1041,6 +1041,9 @@ def warn_impcast_integer_precision : Warning<
|
|||
def warn_impcast_integer_64_32 : Warning<
|
||||
"implicit conversion loses integer precision: %0 to %1">,
|
||||
InGroup<DiagGroup<"shorten-64-to-32">>, DefaultIgnore;
|
||||
def warn_impcast_integer_precision_constant : Warning<
|
||||
"implicit conversion from %2 to %3 changes value from %0 to %1">,
|
||||
InGroup<DiagGroup<"constant-conversion">>;
|
||||
|
||||
def warn_cast_align : Warning<
|
||||
"cast from %0 to %1 increases required alignment from %2 to %3">,
|
||||
|
|
|
@ -1458,12 +1458,25 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
|
|||
return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E);
|
||||
return Success(Result.getInt() % RHS, E);
|
||||
case BO_Shl: {
|
||||
// FIXME: Warn about out of range shift amounts!
|
||||
unsigned SA =
|
||||
(unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
|
||||
// During constant-folding, a negative shift is an opposite shift.
|
||||
if (RHS.isSigned() && RHS.isNegative()) {
|
||||
RHS = -RHS;
|
||||
goto shift_right;
|
||||
}
|
||||
|
||||
shift_left:
|
||||
unsigned SA
|
||||
= (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
|
||||
return Success(Result.getInt() << SA, E);
|
||||
}
|
||||
case BO_Shr: {
|
||||
// During constant-folding, a negative shift is an opposite shift.
|
||||
if (RHS.isSigned() && RHS.isNegative()) {
|
||||
RHS = -RHS;
|
||||
goto shift_left;
|
||||
}
|
||||
|
||||
shift_right:
|
||||
unsigned SA =
|
||||
(unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
|
||||
return Success(Result.getInt() >> SA, E);
|
||||
|
|
|
@ -2165,8 +2165,12 @@ struct IntRange {
|
|||
if (const ComplexType *CT = dyn_cast<ComplexType>(T))
|
||||
T = CT->getElementType().getTypePtr();
|
||||
|
||||
// For enum types, use the known bit width of the enumerators.
|
||||
if (const EnumType *ET = dyn_cast<EnumType>(T)) {
|
||||
EnumDecl *Enum = ET->getDecl();
|
||||
if (!Enum->isDefinition())
|
||||
return IntRange(C.getIntWidth(QualType(T, 0)), false);
|
||||
|
||||
unsigned NumPositive = Enum->getNumPositiveBits();
|
||||
unsigned NumNegative = Enum->getNumNegativeBits();
|
||||
|
||||
|
@ -2590,6 +2594,15 @@ void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext,
|
|||
<< E->getType() << T << E->getSourceRange() << SourceRange(CContext);
|
||||
}
|
||||
|
||||
std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
|
||||
if (!Range.Width) return "0";
|
||||
|
||||
llvm::APSInt ValueInRange = Value;
|
||||
ValueInRange.setIsSigned(!Range.NonNegative);
|
||||
ValueInRange.trunc(Range.Width);
|
||||
return ValueInRange.toString(10);
|
||||
}
|
||||
|
||||
void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
|
||||
SourceLocation CC, bool *ICContext = 0) {
|
||||
if (E->isTypeDependent() || E->isValueDependent()) return;
|
||||
|
@ -2670,6 +2683,19 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
|
|||
IntRange TargetRange = IntRange::forCanonicalType(S.Context, Target);
|
||||
|
||||
if (SourceRange.Width > TargetRange.Width) {
|
||||
// If the source is a constant, use a default-on diagnostic.
|
||||
// TODO: this should happen for bitfield stores, too.
|
||||
llvm::APSInt Value(32);
|
||||
if (E->isIntegerConstantExpr(Value, S.Context)) {
|
||||
std::string PrettySourceValue = Value.toString(10);
|
||||
std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
|
||||
|
||||
S.Diag(E->getExprLoc(), diag::warn_impcast_integer_precision_constant)
|
||||
<< PrettySourceValue << PrettyTargetValue
|
||||
<< E->getType() << T << E->getSourceRange() << clang::SourceRange(CC);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
|
|
@ -15,7 +15,7 @@ float Y = 08.123456;
|
|||
#endif
|
||||
|
||||
|
||||
char c[] = {
|
||||
int c[] = {
|
||||
'df', // expected-warning {{multi-character character constant}}
|
||||
'\t',
|
||||
'\\
|
||||
|
@ -34,12 +34,12 @@ int m3 = '\\\
|
|||
|
||||
#pragma clang diagnostic ignored "-Wmultichar"
|
||||
|
||||
char d = 'df'; // no warning.
|
||||
char e = 'abcd'; // still warn: expected-warning {{multi-character character constant}}
|
||||
int d = 'df'; // no warning.
|
||||
int e = 'abcd'; // still warn: expected-warning {{multi-character character constant}}
|
||||
|
||||
#pragma clang diagnostic ignored "-Wfour-char-constants"
|
||||
|
||||
char f = 'abcd'; // ignored.
|
||||
int f = 'abcd'; // ignored.
|
||||
|
||||
// rdar://problem/6974641
|
||||
float t0[] = {
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
|
||||
#pragma clang diagnostic puhs // expected-warning {{pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal', 'push', or 'pop'}}
|
||||
|
||||
char a = 'df'; // expected-warning{{multi-character character constant}}
|
||||
int a = 'df'; // expected-warning{{multi-character character constant}}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmultichar"
|
||||
|
||||
char b = 'df'; // no warning.
|
||||
int b = 'df'; // no warning.
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
char c = 'df'; // expected-warning{{multi-character character constant}}
|
||||
int c = 'df'; // expected-warning{{multi-character character constant}}
|
||||
|
||||
#pragma clang diagnostic pop // expected-warning{{pragma diagnostic pop could not pop, no matching push}}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin %s
|
||||
|
||||
// This file tests -Wconstant-conversion, a subcategory of -Wconversion
|
||||
// which is on by default.
|
||||
|
||||
// rdar://problem/6792488
|
||||
void test_6792488(void) {
|
||||
int x = 0x3ff0000000000000U; // expected-warning {{implicit conversion from 'unsigned long' to 'int' changes value from 4607182418800017408 to 0}}
|
||||
}
|
|
@ -40,17 +40,17 @@ void test0(char c, short s, int i, long l, long long ll) {
|
|||
l = (long) 0;
|
||||
|
||||
c = (char) BIG;
|
||||
c = (short) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
c = (int) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
c = (long) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
c = (short) BIG; // expected-warning {{implicit conversion from 'short' to 'char' changes value}}
|
||||
c = (int) BIG; // expected-warning {{implicit conversion from 'int' to 'char' changes value}}
|
||||
c = (long) BIG; // expected-warning {{implicit conversion from 'long' to 'char' changes value}}
|
||||
s = (char) BIG;
|
||||
s = (short) BIG;
|
||||
s = (int) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
s = (long) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
s = (int) BIG; // expected-warning {{implicit conversion from 'int' to 'short' changes value}}
|
||||
s = (long) BIG; // expected-warning {{implicit conversion from 'long' to 'short' changes value}}
|
||||
i = (char) BIG;
|
||||
i = (short) BIG;
|
||||
i = (int) BIG;
|
||||
i = (long) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
i = (long) BIG; // expected-warning {{implicit conversion from 'long' to 'int' changes value}}
|
||||
l = (char) BIG;
|
||||
l = (short) BIG;
|
||||
l = (int) BIG;
|
||||
|
@ -63,10 +63,10 @@ char test1(long long ll) {
|
|||
return (int) ll; // expected-warning {{implicit conversion loses integer precision}}
|
||||
return (short) ll; // expected-warning {{implicit conversion loses integer precision}}
|
||||
return (char) ll;
|
||||
return (long long) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
return (long) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
return (int) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
return (short) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
return (long long) BIG; // expected-warning {{implicit conversion from 'long long' to 'char' changes value}}
|
||||
return (long) BIG; // expected-warning {{implicit conversion from 'long' to 'char' changes value}}
|
||||
return (int) BIG; // expected-warning {{implicit conversion from 'int' to 'char' changes value}}
|
||||
return (short) BIG; // expected-warning {{implicit conversion from 'short' to 'char' changes value}}
|
||||
return (char) BIG;
|
||||
}
|
||||
|
||||
|
@ -76,9 +76,9 @@ short test2(long long ll) {
|
|||
return (int) ll; // expected-warning {{implicit conversion loses integer precision}}
|
||||
return (short) ll;
|
||||
return (char) ll;
|
||||
return (long long) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
return (long) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
return (int) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
return (long long) BIG; // expected-warning {{implicit conversion from 'long long' to 'short' changes value}}
|
||||
return (long) BIG; // expected-warning {{implicit conversion from 'long' to 'short' changes value}}
|
||||
return (int) BIG; // expected-warning {{implicit conversion from 'int' to 'short' changes value}}
|
||||
return (short) BIG;
|
||||
return (char) BIG;
|
||||
}
|
||||
|
@ -89,8 +89,8 @@ int test3(long long ll) {
|
|||
return (int) ll;
|
||||
return (short) ll;
|
||||
return (char) ll;
|
||||
return (long long) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
return (long) BIG; // expected-warning {{implicit conversion loses integer precision}}
|
||||
return (long long) BIG; // expected-warning {{implicit conversion from 'long long' to 'int' changes value}}
|
||||
return (long) BIG; // expected-warning {{implicit conversion from 'long' to 'int' changes value}}
|
||||
return (int) BIG;
|
||||
return (short) BIG;
|
||||
return (char) BIG;
|
||||
|
@ -277,7 +277,7 @@ unsigned char test19(unsigned long u64) {
|
|||
// <rdar://problem/7631400>
|
||||
void test_7631400(void) {
|
||||
// This should show up despite the caret being inside a macro substitution
|
||||
char s = LONG_MAX; // expected-warning {{implicit conversion loses integer precision: 'long' to 'char'}}
|
||||
char s = LONG_MAX; // expected-warning {{implicit conversion from 'long' to 'char' changes value}}
|
||||
}
|
||||
|
||||
// <rdar://problem/7676608>: assertion for compound operators with non-integral RHS
|
||||
|
|
Loading…
Reference in New Issue