diff --git a/clang/AST/SemaExpr.cpp b/clang/AST/SemaExpr.cpp index ad20eb38192b..3e4c06ea2946 100644 --- a/clang/AST/SemaExpr.cpp +++ b/clang/AST/SemaExpr.cpp @@ -305,11 +305,8 @@ Action::ExprResult Sema::ParseNumericConstant(const LexerToken &Tok) { return ExprResult(new IntegerLiteral(atoi(ThisTokBegin))); NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, - Tok.getLocation(), PP, Context.Target); - if (Literal.hadError) { - return ExprResult(true); - } - Expr *literal_expr; + Tok.getLocation(), PP); + Expr *literal_expr = 0; if (Literal.isIntegerLiteral()) { TypeRef t; @@ -323,13 +320,14 @@ Action::ExprResult Sema::ParseNumericConstant(const LexerToken &Tok) { } else { t = Context.IntTy; // implicit type is "int" } - intmax_t val; - if (Literal.GetValue(val)) { + uintmax_t val; + if (Literal.GetIntegerValue(val)) { literal_expr = new IntegerLiteral(val, t); } } else if (Literal.isFloatingLiteral()) { // TODO: add floating point processing... } + return literal_expr ? ExprResult(literal_expr) : ExprResult(true); } Action::ExprResult Sema::ParseParenExpr(SourceLocation L, SourceLocation R, diff --git a/clang/Lex/LiteralSupport.cpp b/clang/Lex/LiteralSupport.cpp index 4600e1b06730..2d0efbcaa43c 100644 --- a/clang/Lex/LiteralSupport.cpp +++ b/clang/Lex/LiteralSupport.cpp @@ -60,8 +60,8 @@ using namespace clang; NumericLiteralParser:: NumericLiteralParser(const char *begin, const char *end, - SourceLocation TokLoc, Preprocessor &pp, TargetInfo &t) : - PP(pp), Target(t), ThisTokBegin(begin), ThisTokEnd(end) + SourceLocation TokLoc, Preprocessor &pp) : + PP(pp), ThisTokBegin(begin), ThisTokEnd(end) { s = DigitsBegin = begin; saw_exponent = false; @@ -216,13 +216,38 @@ NumericLiteralParser(const char *begin, const char *end, } } -bool NumericLiteralParser::GetValue(intmax_t &val) { - intmax_t cutoff = INTMAX_MAX; - int cutlim = cutoff % radix; +bool NumericLiteralParser::GetIntegerValue(uintmax_t &val) { + uintmax_t cutoff = UINTMAX_MAX / radix; + int cutlim = UINTMAX_MAX % radix; + char c; + + val = 0; + s = DigitsBegin; + while (s < SuffixBegin) { + c = *s++; + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'F') // 10...15 + c -= 'A' - 10; + else if (c >= 'a' && c <= 'f') // 10...15 + c -= 'a' - 10; + + if (val > cutoff || (val == cutoff && c > cutlim)) { + return false; // Overflow! + } else { + val *= radix; + val += c; + } + } + return true; +} + +bool NumericLiteralParser::GetIntegerValue(int &val) { + intmax_t cutoff = INT_MAX / radix; + int cutlim = INT_MAX % radix; char c; val = 0; - cutoff /= radix; s = DigitsBegin; while (s < SuffixBegin) { c = *s++; diff --git a/clang/Lex/PPExpressions.cpp b/clang/Lex/PPExpressions.cpp index 34cd73fb8b9a..ffc653535f43 100644 --- a/clang/Lex/PPExpressions.cpp +++ b/clang/Lex/PPExpressions.cpp @@ -13,7 +13,6 @@ //===----------------------------------------------------------------------===// // // FIXME: implement testing for asserts. -// FIXME: Parse integer constants correctly. Reject 123.0, etc. // FIXME: Track signed/unsigned correctly. // FIXME: Track and report integer overflow correctly. // @@ -21,9 +20,11 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Lex/MacroInfo.h" +#include "clang/Lex/LiteralSupport.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TokenKinds.h" #include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/SmallString.h" using namespace llvm; using namespace clang; @@ -144,10 +145,18 @@ static bool EvaluateValue(int &Result, LexerToken &PeekTok, DefinedTracker &DT, PP.Diag(PeekTok, diag::err_pp_expected_value_in_expr); return true; case tok::numeric_constant: { - // FIXME: faster. FIXME: track signs. - std::string Spell = PP.getSpelling(PeekTok); - // FIXME: COMPUTE integer constants CORRECTLY. - Result = atoi(Spell.c_str()); + // FIXME: track signs. ?? snaroff: talk to Chris... + SmallString<512> IntegerBuffer; + IntegerBuffer.resize(PeekTok.getLength()); + const char *ThisTokBegin = &IntegerBuffer[0]; + unsigned ActualLength = PP.getSpelling(PeekTok, ThisTokBegin); + NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, + PeekTok.getLocation(), PP); + if (Literal.isIntegerLiteral()) { + Literal.GetIntegerValue(Result); + } else if (Literal.isFloatingLiteral()) { + PP.Diag(PeekTok, diag::err_pp_illegal_floating_literal); + } PP.LexNonComment(PeekTok); return false; } diff --git a/clang/Sema/SemaExpr.cpp b/clang/Sema/SemaExpr.cpp index ad20eb38192b..3e4c06ea2946 100644 --- a/clang/Sema/SemaExpr.cpp +++ b/clang/Sema/SemaExpr.cpp @@ -305,11 +305,8 @@ Action::ExprResult Sema::ParseNumericConstant(const LexerToken &Tok) { return ExprResult(new IntegerLiteral(atoi(ThisTokBegin))); NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, - Tok.getLocation(), PP, Context.Target); - if (Literal.hadError) { - return ExprResult(true); - } - Expr *literal_expr; + Tok.getLocation(), PP); + Expr *literal_expr = 0; if (Literal.isIntegerLiteral()) { TypeRef t; @@ -323,13 +320,14 @@ Action::ExprResult Sema::ParseNumericConstant(const LexerToken &Tok) { } else { t = Context.IntTy; // implicit type is "int" } - intmax_t val; - if (Literal.GetValue(val)) { + uintmax_t val; + if (Literal.GetIntegerValue(val)) { literal_expr = new IntegerLiteral(val, t); } } else if (Literal.isFloatingLiteral()) { // TODO: add floating point processing... } + return literal_expr ? ExprResult(literal_expr) : ExprResult(true); } Action::ExprResult Sema::ParseParenExpr(SourceLocation L, SourceLocation R, diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index cc5af40e256d..44159098f5cd 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -237,6 +237,8 @@ DIAG(err_pp_bad_paste, ERROR, "pasting formed \"%s\", an invalid preprocessing token") DIAG(err_pp_operator_used_as_macro_name, ERROR, "C++ operator \"%s\" cannot be used as a macro name") +DIAG(err_pp_illegal_floating_literal, ERROR, + "floating point literal in preprocessor expression") // Should be a sorry? DIAG(err_pp_I_dash_not_supported, ERROR, diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h index c7bf8ea59b99..c82decdfd17e 100644 --- a/clang/include/clang/Lex/LiteralSupport.h +++ b/clang/include/clang/Lex/LiteralSupport.h @@ -25,10 +25,9 @@ class TargetInfo; struct NumericLiteralParser { NumericLiteralParser(const char *begin, const char *end, - SourceLocation Loc, Preprocessor &PP, TargetInfo &T); + SourceLocation Loc, Preprocessor &PP); private: Preprocessor &PP; // needed for diagnostics - TargetInfo &Target; // needed to compute the size const char *const ThisTokBegin; const char *const ThisTokEnd; @@ -47,21 +46,22 @@ public: bool isLongLong; bool isIntegerLiteral() { - return !saw_period && !saw_exponent ? true : false; + return !saw_period && !saw_exponent && !hadError ? true : false; } bool isFloatingLiteral() { - return saw_period || saw_exponent ? true : false; + return saw_period || saw_exponent && !hadError ? true : false; } bool hasSuffix() { return SuffixBegin != ThisTokEnd; } - /// getValue - Convert the string into a number. At this point, we know - /// the digit characters are valid (0...9, a...f, A...F). We don't know - /// how many bits are needed to store the number. We return true if the - /// value fit into intmax_t (typically 64-bit's), false otherwise. This - /// API will likely be replaced by sizing hooks and APInt. Nevertheless, - /// this provides basic conversion support for now. - bool GetValue(intmax_t &val); + /// getIntegerValue - Convert the string into a number. At this point, we + /// know the digit characters are valid (0...9, a...f, A...F). We don't know + /// how many bits are needed to store the number. Sizing of the integer + /// type (int, unsigned, long, unsigned long, long long, unsigned long long) + /// will be done elsewhere - the computation is target dependent. We return + /// true if the value fit into uintmax_t, false otherwise. + bool GetIntegerValue(uintmax_t &val); + bool GetIntegerValue(int &val); private: void Diag(SourceLocation Loc, unsigned DiagID,