aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticKinds.def7
-rw-r--r--include/clang/Lex/Preprocessor.h1
-rw-r--r--lib/Lex/PPDirectives.cpp100
-rw-r--r--test/Preprocessor/line-directive.c10
4 files changed, 104 insertions, 14 deletions
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index e9dbad94b6..09b24ad818 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -200,6 +200,13 @@ DIAG(err_pp_duplicate_name_in_arg_list, ERROR,
"duplicate macro parameter name %0")
DIAG(err_pp_stringize_not_parameter, ERROR,
"'#' is not followed by a macro parameter")
+DIAG(err_pp_line_requires_integer, ERROR,
+ "#line directive requires a positive integer argument")
+DIAG(err_pp_line_invalid_filename, ERROR,
+ "invalid filename for #line directive")
+DIAG(ext_pp_line_too_big, EXTENSION,
+ "C requires #line number to be less than %0, allowed as extension")
+
DIAG(err_pp_malformed_ident, ERROR,
"invalid #ident directive")
DIAG(err_pp_unterminated_conditional, ERROR,
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 2954c676e8..8081759e96 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -691,6 +691,7 @@ private:
/// should side-effect the current preprocessor object so that the next call
/// to Lex() will return the appropriate token next.
+ void HandleLineDirective(Token &Tok);
void HandleUserDiagnosticDirective(Token &Tok, bool isWarning);
void HandleIdentSCCSDirective(Token &Tok);
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index ec5b67fb78..4ab293b9b7 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -12,10 +12,12 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/APInt.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -478,8 +480,7 @@ TryAgain:
case tok::numeric_constant:
// FIXME: implement # 7 line numbers!
- DiscardUntilEndOfDirective();
- return;
+ return DiscardUntilEndOfDirective();
default:
IdentifierInfo *II = Result.getIdentifierInfo();
if (II == 0) break; // Not an identifier.
@@ -513,9 +514,7 @@ TryAgain:
// C99 6.10.4 - Line Control.
case tok::pp_line:
- // FIXME: implement #line
- DiscardUntilEndOfDirective();
- return;
+ return HandleLineDirective(Result);
// C99 6.10.5 - Error Directive.
case tok::pp_error:
@@ -557,22 +556,95 @@ TryAgain:
// Okay, we're done parsing the directive.
}
+/// HandleLineDirective - Handle #line directive: C99 6.10.4. The two
+/// acceptable forms are:
+/// # line digit-sequence
+/// # line digit-sequence "s-char-sequence"
+void Preprocessor::HandleLineDirective(Token &Tok) {
+ // Read the line # and string argument. Per C99 6.10.4p5, these tokens are
+ // expanded.
+ Token DigitTok;
+ Lex(DigitTok);
+
+ // Verify that we get a number.
+ if (DigitTok.isNot(tok::numeric_constant)) {
+ Diag(DigitTok, diag::err_pp_line_requires_integer);
+ if (DigitTok.isNot(tok::eom))
+ DiscardUntilEndOfDirective();
+ return;
+ }
+
+ // Validate the number and convert it to an unsigned.
+ llvm::SmallString<64> IntegerBuffer;
+ IntegerBuffer.resize(DigitTok.getLength());
+ const char *DigitTokBegin = &IntegerBuffer[0];
+ unsigned ActualLength = getSpelling(DigitTok, DigitTokBegin);
+ NumericLiteralParser Literal(DigitTokBegin, DigitTokBegin+ActualLength,
+ DigitTok.getLocation(), *this);
+ if (Literal.hadError)
+ return DiscardUntilEndOfDirective(); // a diagnostic was already reported.
+
+ if (Literal.isFloatingLiteral() || Literal.isImaginary) {
+ Diag(DigitTok, diag::err_pp_line_requires_integer);
+ return;
+ }
+
+ // Parse the integer literal into Result.
+ llvm::APInt Val(32, 0);
+ if (Literal.GetIntegerValue(Val)) {
+ // Overflow parsing integer literal.
+ Diag(DigitTok, diag::err_pp_line_requires_integer);
+ return DiscardUntilEndOfDirective();
+ }
+
+ // Enforce C99 6.10.4p3: The digit sequence shall not specify zero, nor a
+ // number greater than 2147483647.
+ unsigned LineNo = Val.getZExtValue();
+ if (LineNo == 0) {
+ Diag(DigitTok, diag::err_pp_line_requires_integer);
+ return DiscardUntilEndOfDirective();
+ }
+
+ // C90 requires that the line # be less than 32767, and C99 ups the limit.
+ unsigned LineLimit = Features.C99 ? 2147483648U : 32768U;
+ if (LineNo >= LineLimit)
+ Diag(DigitTok, diag::ext_pp_line_too_big) << LineLimit;
+
+ Token StrTok;
+ Lex(StrTok);
+
+ // If the StrTok is "eom", then it wasn't present. Otherwise, it must be a
+ // string followed by eom.
+ if (StrTok.is(tok::eom))
+ ; // ok
+ else if (StrTok.isNot(tok::string_literal)) {
+ Diag(StrTok, diag::err_pp_line_invalid_filename);
+ DiscardUntilEndOfDirective();
+ return;
+ } else {
+ // Verify that there is nothing after the string, other than EOM.
+ CheckEndOfDirective("#line");
+ }
+
+ // FIXME: do something with the #line info.
+}
+
+
void Preprocessor::HandleUserDiagnosticDirective(Token &Tok,
bool isWarning) {
+ if (!CurLexer)
+ return CurPTHLexer->DiscardToEndOfLine();
+
// Read the rest of the line raw. We do this because we don't want macros
// to be expanded and we don't require that the tokens be valid preprocessing
// tokens. For example, this is allowed: "#warning ` 'foo". GCC does
// collapse multiple consequtive white space between tokens, but this isn't
// specified by the standard.
-
- if (CurLexer) {
- std::string Message = CurLexer->ReadToEndOfLine();
- unsigned DiagID = isWarning ? diag::pp_hash_warning : diag::err_pp_hash_error;
- Diag(Tok, DiagID) << Message;
- }
- else {
- CurPTHLexer->DiscardToEndOfLine();
- }
+ std::string Message = CurLexer->ReadToEndOfLine();
+ if (isWarning)
+ Diag(Tok, diag::pp_hash_warning) << Message;
+ else
+ Diag(Tok, diag::err_pp_hash_error) << Message;
}
/// HandleIdentSCCSDirective - Handle a #ident/#sccs directive.
diff --git a/test/Preprocessor/line-directive.c b/test/Preprocessor/line-directive.c
new file mode 100644
index 0000000000..9b7950633b
--- /dev/null
+++ b/test/Preprocessor/line-directive.c
@@ -0,0 +1,10 @@
+// RUN: clang -fsyntax-only -verify -pedantic %s
+
+#line 'a' // expected-error {{#line directive requires a positive integer argument}}
+#line 0 // 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 {{nvalid filename for #line directive}}
+#line 42 "foo/bar/baz.h" // ok
+
+