diff options
author | John McCall <rjmccall@apple.com> | 2009-12-24 09:08:04 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2009-12-24 09:08:04 +0000 |
commit | 94c939dc1d4958b62ea5a89294dd8b2905f3191f (patch) | |
tree | ba5da62308448bfafcbb683c433bc9b8d53f15eb | |
parent | 8cc4f1036608c7538ad38f397afc13de94aa8dc3 (diff) |
Diagnose out-of-bounds floating-point constants. Fixes rdar://problem/6974641
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92127 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 6 | ||||
-rw-r--r-- | include/clang/Lex/LiteralSupport.h | 10 | ||||
-rw-r--r-- | lib/Lex/LiteralSupport.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 24 | ||||
-rw-r--r-- | test/Lexer/constants.c | 22 |
5 files changed, 54 insertions, 25 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 6f1039e978..bb507d17a7 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -26,9 +26,13 @@ def ext_null_pointer_expr_not_ice : Extension< -// Semantic analysis of string and character constant literals. +// Semantic analysis of constant literals. def ext_predef_outside_function : Warning< "predefined identifier is only valid inside function">; +def err_float_overflow : Error< + "magnitude of floating-point constant too large for type %0; maximum is %1">; +def err_float_underflow : Error< + "magnitude of floating-point constant too small for type %0; minimum is %1">; // C99 Designated Initializers def err_array_designator_negative : Error< diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h index c4ab5aebf7..2334d728f6 100644 --- a/include/clang/Lex/LiteralSupport.h +++ b/include/clang/Lex/LiteralSupport.h @@ -16,15 +16,10 @@ #define CLANG_LITERALSUPPORT_H #include <string> +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallString.h" #include "llvm/System/DataTypes.h" -namespace llvm { - class APInt; - class APFloat; - struct fltSemantics; -} - namespace clang { class Diagnostic; @@ -82,8 +77,7 @@ public: /// The optional bool isExact (passed-by-reference) has its value /// set to true if the returned APFloat can represent the number in the /// literal exactly, and false otherwise. - llvm::APFloat GetFloatValue(const llvm::fltSemantics &Format, - bool* isExact = NULL); + llvm::APFloat::opStatus GetFloatValue(llvm::APFloat &Result); private: diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index f1993d2264..9aaa82d626 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -610,23 +610,14 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) { return OverflowOccurred; } -llvm::APFloat NumericLiteralParser:: -GetFloatValue(const llvm::fltSemantics &Format, bool* isExact) { +llvm::APFloat::opStatus +NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) { using llvm::APFloat; using llvm::StringRef; unsigned n = std::min(SuffixBegin - ThisTokBegin, ThisTokEnd - ThisTokBegin); - - APFloat V (Format, APFloat::fcZero, false); - APFloat::opStatus status; - - status = V.convertFromString(StringRef(ThisTokBegin, n), - APFloat::rmNearestTiesToEven); - - if (isExact) - *isExact = status == APFloat::opOK; - - return V; + return Result.convertFromString(StringRef(ThisTokBegin, n), + APFloat::rmNearestTiesToEven); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 24bc29560d..0951677db2 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1585,9 +1585,27 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { const llvm::fltSemantics &Format = Context.getFloatTypeSemantics(Ty); - // isExact will be set by GetFloatValue(). - bool isExact = false; - llvm::APFloat Val = Literal.GetFloatValue(Format, &isExact); + using llvm::APFloat; + APFloat Val(Format); + + APFloat::opStatus result = Literal.GetFloatValue(Val); + if (result & (APFloat::opOverflow | APFloat::opUnderflow)) { + unsigned diagnostic; + llvm::SmallVector<char, 20> buffer; + if (result & APFloat::opOverflow) { + diagnostic = diag::err_float_overflow; + APFloat::getLargest(Format).toString(buffer); + } else { + diagnostic = diag::err_float_underflow; + APFloat::getSmallest(Format).toString(buffer); + } + + Diag(Tok.getLocation(), diagnostic) + << Ty + << llvm::StringRef(buffer.data(), buffer.size()); + } + + bool isExact = (result == APFloat::opOK); Res = new (Context) FloatingLiteral(Val, isExact, Ty, Tok.getLocation()); } else if (!Literal.isIntegerLiteral()) { diff --git a/test/Lexer/constants.c b/test/Lexer/constants.c index 72e0dc4231..104a3a2a2b 100644 --- a/test/Lexer/constants.c +++ b/test/Lexer/constants.c @@ -33,3 +33,25 @@ char e = 'abcd'; // still warn: expected-warning {{multi-character character co #pragma clang diagnostic ignored "-Wfour-char-constants" char f = 'abcd'; // ignored. + +// rdar://problem/6974641 +float t0[] = { + 1.9e20f, + 1.9e-20f, + 1.9e50f, // expected-error {{too large}} + 1.9e-50f, // expected-error {{too small}} + -1.9e20f, + -1.9e-20f, + -1.9e50f, // expected-error {{too large}} + -1.9e-50f // expected-error {{too small}} +}; +double t1[] = { + 1.9e50, + 1.9e-50, + 1.9e500, // expected-error {{too large}} + 1.9e-500, // expected-error {{too small}} + -1.9e50, + -1.9e-50, + -1.9e500, // expected-error {{too large}} + -1.9e-500 // expected-error {{too small}} +}; |