Enhance the diagnostic for literal float -> int conversions to suggest
rewriting the literal when the value is integral. It is not uncommon to
see code written as:
const int kBigNumber = 42e5;
Without any real awareness that this is no longer an ICE. The note helps
automate and ease the process of fixing code that violates the warning.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129243 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index edcf4ef..4ec3d73 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1194,6 +1194,8 @@
"implicit conversion turns literal floating-point number into integer: "
"%0 to %1">,
InGroup<DiagGroup<"literal-conversion">>, DefaultIgnore;
+def note_fix_integral_float_as_integer : Note<
+ "this can be rewritten as an integer literal with the exact same value">;
def warn_impcast_different_enum_types : Warning<
"implicit conversion from enumeration type %0 to different enumeration type "
"%1">, InGroup<DiagGroup<"conversion">>;
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index e1adfd4..9372a16 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -2763,6 +2763,38 @@
DiagnoseImpCast(S, E, E->getType(), T, CContext, diag);
}
+/// Diagnose an implicit cast from a literal expression. Also attemps to supply
+/// fixit hints when the cast wouldn't lose information to simply write the
+/// expression with the expected type.
+void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T,
+ SourceLocation CContext) {
+ // Emit the primary warning first, then try to emit a fixit hint note if
+ // reasonable.
+ S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer)
+ << FL->getType() << T << FL->getSourceRange() << SourceRange(CContext);
+
+ const llvm::APFloat &Value = FL->getValue();
+
+ // Don't attempt to fix PPC double double literals.
+ if (&Value.getSemantics() == &llvm::APFloat::PPCDoubleDouble)
+ return;
+
+ // Try to convert this exactly to an 64-bit integer. FIXME: It would be
+ // nice to support arbitrarily large integers here.
+ bool isExact = false;
+ uint64_t IntegerPart;
+ if (Value.convertToInteger(&IntegerPart, 64, /*isSigned=*/true,
+ llvm::APFloat::rmTowardZero, &isExact)
+ != llvm::APFloat::opOK || !isExact)
+ return;
+
+ llvm::APInt IntegerValue(64, IntegerPart, /*isSigned=*/true);
+
+ std::string LiteralValue = IntegerValue.toString(10, /*isSigned=*/true);
+ S.Diag(FL->getExprLoc(), diag::note_fix_integral_float_as_integer)
+ << FixItHint::CreateReplacement(FL->getSourceRange(), LiteralValue);
+}
+
std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
if (!Range.Width) return "0";
@@ -2776,7 +2808,7 @@
SourceManager &smgr = S.Context.getSourceManager();
return loc.isMacroID() && smgr.isInSystemHeader(smgr.getSpellingLoc(loc));
}
-
+
void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
SourceLocation CC, bool *ICContext = 0) {
if (E->isTypeDependent() || E->isValueDependent()) return;
@@ -2859,9 +2891,8 @@
return;
Expr *InnerE = E->IgnoreParenImpCasts();
- if (FloatingLiteral *LiteralExpr = dyn_cast<FloatingLiteral>(InnerE)) {
- DiagnoseImpCast(S, LiteralExpr, T, CC,
- diag::warn_impcast_literal_float_to_integer);
+ if (FloatingLiteral *FL = dyn_cast<FloatingLiteral>(InnerE)) {
+ DiagnoseFloatingLiteralImpCast(S, FL, T, CC);
} else {
DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_integer);
}
diff --git a/test/Sema/knr-def-call.c b/test/Sema/knr-def-call.c
index d054a04..6243af6 100644
--- a/test/Sema/knr-def-call.c
+++ b/test/Sema/knr-def-call.c
@@ -36,6 +36,8 @@
}
void use_proto() {
- proto(42.0); // expected-warning{{implicit conversion turns literal floating-point number into integer}}
- (&proto)(42.0); // expected-warning{{implicit conversion turns literal floating-point number into integer}}
+ proto(42.0); // expected-warning{{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
+ (&proto)(42.0); // expected-warning{{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
}
diff --git a/test/SemaCXX/warn-literal-conversion.cpp b/test/SemaCXX/warn-literal-conversion.cpp
index dab5c01..b9c9528 100644
--- a/test/SemaCXX/warn-literal-conversion.cpp
+++ b/test/SemaCXX/warn-literal-conversion.cpp
@@ -8,13 +8,18 @@
int y0 = 1.2222F; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
int y1 = (1.2222F); // expected-warning {{implicit conversion turns literal floating-point number into integer}}
int y2 = (((1.2222F))); // expected-warning {{implicit conversion turns literal floating-point number into integer}}
- int y3 = 12E1F; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
- int y4 = 1.2E1F; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
+ int y3 = 12E1F; // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
+ int y4 = 1.2E1F; // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
// Double
int y5 = 1.2222; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
- int y6 = 12E1; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
- int y7 = 1.2E1; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
- int y8 = (1.2E1); // expected-warning {{implicit conversion turns literal floating-point number into integer}}
+ int y6 = 12E1; // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
+ int y7 = 1.2E1; // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
+ int y8 = (1.2E1); // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
// Test assignment to an existing variable.
y8 = 2.22F; // expected-warning {{implicit conversion turns literal floating-point number into integer}}