From 871b4e101cb1cc0d8b99dd6bdb975592aae6da70 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Wed, 4 Apr 2007 06:36:34 +0000 Subject: [PATCH] Minor enhancements to GetIntegerValue(APInt): * Detect overflow correctly. When it occurs, return the truncated value. * Add fixme for radix analysis. llvm-svn: 39382 --- clang/Lex/LiteralSupport.cpp | 29 +++++++++++++++++------- clang/include/clang/Lex/LiteralSupport.h | 8 ++++++- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/clang/Lex/LiteralSupport.cpp b/clang/Lex/LiteralSupport.cpp index 286bcf6a3b09..944030f8c5a3 100644 --- a/clang/Lex/LiteralSupport.cpp +++ b/clang/Lex/LiteralSupport.cpp @@ -266,32 +266,45 @@ bool NumericLiteralParser::GetIntegerValue(int &val) { } /// GetIntegerValue - Convert this numeric literal value to an APInt that -/// matches Val's input width. If there is an overflow, saturate Val to zero -/// and return false. Otherwise, set Val and return true. +/// matches Val's input width. If there is an overflow, set Val to the low bits +/// of the result and return true. Otherwise, return false. bool NumericLiteralParser::GetIntegerValue(APInt &Val) { Val = 0; s = DigitsBegin; - // FIXME: This doesn't handle sign right, doesn't autopromote to wider - // integer, and is generally not conformant. APInt RadixVal(Val.getBitWidth(), radix); APInt CharVal(Val.getBitWidth(), 0); APInt OldVal = Val; + + bool OverflowOccurred = false; while (s < SuffixBegin) { unsigned C = HexLetterToVal(*s++); // If this letter is out of bound for this radix, reject it. - if (C >= radix) { Val = 0; return false; } + if (C >= radix) { + // FIXME: This is an error, not a warning. This should be caught by + // NumericLiteralParser ctor. + C = C % radix; + OverflowOccurred = true; + } CharVal = C; + // Add the digit to the value in the appropriate radix. If adding in digits + // made the value smaller, then this overflowed. OldVal = Val; + + // Multiply by radix, did overflow occur on the multiply? Val *= RadixVal; + OverflowOccurred |= Val.udiv(RadixVal) != OldVal; + + OldVal = Val; + // Add value, did overflow occur on the value? Val += CharVal; - if (OldVal.ugt(Val)) - return false; // Overflow! + OverflowOccurred |= Val.ult(OldVal); + OverflowOccurred |= Val.ult(CharVal); } - return true; + return OverflowOccurred; } diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h index ce134b427d78..b5b635a7ccc2 100644 --- a/clang/include/clang/Lex/LiteralSupport.h +++ b/clang/include/clang/Lex/LiteralSupport.h @@ -63,9 +63,15 @@ public: /// type (int, unsigned, long, unsigned long, long long, unsigned long long) /// will be done elsewhere - the size computation is target dependent. We /// return true if the value fit into "val", false otherwise. + /// NOTE: The api of these returns an inverted value for 'overflow' than the + /// version below does. bool GetIntegerValue(uintmax_t &val); bool GetIntegerValue(int &val); - bool GetIntegerValue(APInt &Val); //< Return the same width as Val. + + /// GetIntegerValue - Convert this numeric literal value to an APInt that + /// matches Val's input width. If there is an overflow, set Val to the low + /// bits of the result and return true. Otherwise, return false. + bool GetIntegerValue(APInt &Val); private: void Diag(SourceLocation Loc, unsigned DiagID,