// 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",
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">,
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);
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();
<< 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;
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)
#endif
-char c[] = {
+int c[] = {
'df', // expected-warning {{multi-character character constant}}
'\t',
'\\
#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[] = {
#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}}
--- /dev/null
+// 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}}
+}
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;
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;
}
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;
}
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;
// <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