diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 564608865e62..e1e903fad06a 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -228,8 +228,8 @@ def err_pp_line_requires_integer : Error< def err_pp_line_invalid_filename : Error< "invalid filename for #line directive">; def warn_pp_line_decimal : Warning< - "#line directive requires decimal line number">; -def warn_pp_line_digit_sequence : Warning< + "#line directive interprets number as decimal, not octal">; +def err_pp_line_digit_sequence : Error< "#line directive requires a simple digit sequence">; def err_pp_linemarker_requires_integer : Error< "line marker directive requires a positive integer argument">; diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 3d312748f956..e0bd5a1ee073 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -624,25 +624,28 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val, IntegerBuffer.resize(DigitTok.getLength()); const char *DigitTokBegin = &IntegerBuffer[0]; unsigned ActualLength = PP.getSpelling(DigitTok, DigitTokBegin); - NumericLiteralParser Literal(DigitTokBegin, DigitTokBegin+ActualLength, - DigitTok.getLocation(), PP); - if (Literal.hadError) - return true; // Error already emitted. - if (Literal.isFloatingLiteral() || Literal.isImaginary) { - PP.Diag(DigitTok, DiagID); - return true; + // Verify that we have a simple digit-sequence, and compute the value. This + // is always a simple digit string computed in decimal, so we do this manually + // here. + Val = 0; + for (unsigned i = 0; i != ActualLength; ++i) { + if (!isdigit(DigitTokBegin[i])) { + PP.Diag(PP.AdvanceToTokenCharacter(DigitTok.getLocation(), i), + diag::err_pp_line_digit_sequence); + PP.DiscardUntilEndOfDirective(); + return true; + } + + unsigned NextVal = Val*10+(DigitTokBegin[i]-'0'); + if (NextVal < Val) { // overflow. + PP.Diag(DigitTok, DiagID); + PP.DiscardUntilEndOfDirective(); + return true; + } + Val = NextVal; } - // Parse the integer literal into Result. - llvm::APInt APVal(32, 0); - if (Literal.GetIntegerValue(APVal)) { - // Overflow parsing integer literal. - PP.Diag(DigitTok, DiagID); - return true; - } - Val = APVal.getZExtValue(); - // Reject 0, this is needed both by #line numbers and flags. if (Val == 0) { PP.Diag(DigitTok, DiagID); @@ -650,12 +653,9 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val, return true; } - // Warn about hex and octal line numbers. Do this after the check for 0, - // because it is octal. - if (Literal.getRadix() != 10) - PP.Diag(DigitTok, diag::warn_pp_line_decimal); - else if (Literal.hasSuffix()) - PP.Diag(DigitTok, diag::warn_pp_line_digit_sequence); + if (DigitTokBegin[0] == '0') + PP.Diag(DigitTok.getLocation(), diag::warn_pp_line_decimal); + return false; } @@ -671,7 +671,7 @@ void Preprocessor::HandleLineDirective(Token &Tok) { // Validate the number and convert it to an unsigned. unsigned LineNo; - if (GetLineValue(DigitTok, LineNo, diag::err_pp_line_requires_integer, *this)) + if (GetLineValue(DigitTok, LineNo, diag::err_pp_line_requires_integer,*this)) return; // Enforce C99 6.10.4p3: "The digit sequence shall not specify ... a diff --git a/clang/test/Preprocessor/line-directive.c b/clang/test/Preprocessor/line-directive.c index 98f92f130c65..04c69a6791ad 100644 --- a/clang/test/Preprocessor/line-directive.c +++ b/clang/test/Preprocessor/line-directive.c @@ -4,6 +4,7 @@ #line 'a' // expected-error {{#line directive requires a positive integer argument}} #line 0 // expected-error {{#line directive requires a positive integer argument}} +#line 00 // expected-error {{#line directive requires a positive integer argument}} #line 2147483648 // expected-warning {{C requires #line number to be less than 2147483648, allowed as extension}} #line 42 // ok #line 42 'a' // expected-error {{invalid filename for #line directive}} @@ -69,7 +70,12 @@ typedef int w; // expected-error {{redefinition of typedef 'w' is invalid in C} #line 2 "foo.c" NONEMPTY( ) // expected-warning{{extra tokens at end of #line directive}} // PR3940 -#line 0xf // expected-warning {{#line directive requires decimal line number}} -#line 42U // expected-warning {{#line directive requires a simple digit sequence}} +#line 0xf // expected-error {{#line directive requires a simple digit sequence}} +#line 42U // expected-error {{#line directive requires a simple digit sequence}} +// Line markers are digit strings interpreted as decimal numbers, this is +// 10, not 8. +#line 010 // expected-warning {{#line directive interprets number as decimal, not octal}} +extern int array[__LINE__ == 10 ? 1:-1]; +