diff --git a/llvm/include/llvm/ADT/StringRef.h b/llvm/include/llvm/ADT/StringRef.h --- a/llvm/include/llvm/ADT/StringRef.h +++ b/llvm/include/llvm/ADT/StringRef.h @@ -523,6 +523,17 @@ /// string is well-formed in the given radix. bool getAsInteger(unsigned Radix, APInt &Result) const; + /// Parse the current string as an integer of the specified \p Radix. If + /// \p Radix is specified as zero, this does radix autosensing using + /// extended C rules: 0 is octal, 0x is hex, 0b is binary. + /// + /// If the string does not begin with a number of the specified radix, + /// this returns true to signify the error. The string is considered + /// erroneous if empty. + /// The portion of the string representing the discovered numeric value + /// is removed from the beginning of the string. + bool consumeInteger(unsigned Radix, APInt &Result); + /// Parse the current string as an IEEE double-precision floating /// point value. The string must be a well-formed double. /// diff --git a/llvm/lib/Support/StringRef.cpp b/llvm/lib/Support/StringRef.cpp --- a/llvm/lib/Support/StringRef.cpp +++ b/llvm/lib/Support/StringRef.cpp @@ -509,7 +509,7 @@ return !Str.empty(); } -bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const { +bool StringRef::consumeInteger(unsigned Radix, APInt &Result) { StringRef Str = *this; // Autosense radix if not specified. @@ -529,6 +529,7 @@ // If it was nothing but zeroes.... if (Str.empty()) { Result = APInt(64, 0); + *this = Str; return false; } @@ -561,12 +562,12 @@ else if (Str[0] >= 'A' && Str[0] <= 'Z') CharVal = Str[0]-'A'+10; else - return true; + break; // If the parsed value is larger than the integer radix, the string is // invalid. if (CharVal >= Radix) - return true; + break; // Add in this character. if (IsPowerOf2Radix) { @@ -581,9 +582,25 @@ Str = Str.substr(1); } + // We consider the operation a failure if no characters were consumed + // successfully. + if (size() == Str.size()) + return true; + + *this = Str; return false; } +bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const { + StringRef Str = *this; + if (Str.consumeInteger(Radix, Result)) + return true; + + // For getAsInteger, we require the whole string to be consumed or else we + // consider it a failure. + return !Str.empty(); +} + bool StringRef::getAsDouble(double &Result, bool AllowInexact) const { APFloat F(0.0); auto StatusOrErr = F.convertFromString(*this, APFloat::rmNearestTiesToEven); diff --git a/llvm/unittests/ADT/StringRefTest.cpp b/llvm/unittests/ADT/StringRefTest.cpp --- a/llvm/unittests/ADT/StringRefTest.cpp +++ b/llvm/unittests/ADT/StringRefTest.cpp @@ -818,6 +818,7 @@ uint16_t U16; uint32_t U32; uint64_t U64; + APInt U; for (size_t i = 0; i < std::size(ConsumeUnsigned); ++i) { StringRef Str = ConsumeUnsigned[i].Str; @@ -858,6 +859,12 @@ ASSERT_FALSE(U64Success); EXPECT_EQ(U64, ConsumeUnsigned[i].Expected); EXPECT_EQ(Str, ConsumeUnsigned[i].Leftover); + + Str = ConsumeUnsigned[i].Str; + U64Success = Str.consumeInteger(0, U); + ASSERT_FALSE(U64Success); + EXPECT_EQ(U.getZExtValue(), ConsumeUnsigned[i].Expected); + EXPECT_EQ(Str, ConsumeUnsigned[i].Leftover); } }