[cfe-commits] r63003 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def include/clang/Lex/Preprocessor.h lib/Lex/PPDirectives.cpp test/Preprocessor/line-directive.c
Chris Lattner
sabre at nondot.org
Sun Jan 25 22:19:46 PST 2009
Author: lattner
Date: Mon Jan 26 00:19:46 2009
New Revision: 63003
URL: http://llvm.org/viewvc/llvm-project?rev=63003&view=rev
Log:
add parsing and constraint enforcement for GNU line marker directives.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/include/clang/Lex/Preprocessor.h
cfe/trunk/lib/Lex/PPDirectives.cpp
cfe/trunk/test/Preprocessor/line-directive.c
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=63003&r1=63002&r2=63003&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Mon Jan 26 00:19:46 2009
@@ -204,6 +204,12 @@
"#line directive requires a positive integer argument")
DIAG(err_pp_line_invalid_filename, ERROR,
"invalid filename for #line directive")
+DIAG(err_pp_linemarker_requires_integer, ERROR,
+ "line marker directive requires a positive integer argument")
+DIAG(err_pp_linemarker_invalid_filename, ERROR,
+ "invalid filename for line marker directive")
+DIAG(err_pp_linemarker_invalid_flag, ERROR,
+ "invalid flag line marker directive")
DIAG(ext_pp_line_too_big, EXTENSION,
"C requires #line number to be less than %0, allowed as extension")
Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=63003&r1=63002&r2=63003&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Mon Jan 26 00:19:46 2009
@@ -532,6 +532,11 @@
/// CheckEndOfDirective - Ensure that the next token is a tok::eom token. If
/// not, emit a diagnostic and consume up until the eom.
void CheckEndOfDirective(const char *Directive);
+
+ /// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the
+ /// current line until the tok::eom token is found.
+ void DiscardUntilEndOfDirective();
+
private:
void PushIncludeMacroStack() {
@@ -566,10 +571,6 @@
/// #include.
bool isInPrimaryFile() const;
- /// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the
- /// current line until the tok::eom token is found.
- void DiscardUntilEndOfDirective();
-
/// ReadMacroName - Lex and validate a macro name, which occurs after a
/// #define or #undef. This emits a diagnostic, sets the token kind to eom,
/// and discards the rest of the macro line if the macro name is invalid.
@@ -690,8 +691,8 @@
/// Handle*Directive - implement the various preprocessor directives. These
/// 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 HandleDigitDirective(Token &Tok);
void HandleUserDiagnosticDirective(Token &Tok, bool isWarning);
void HandleIdentSCCSDirective(Token &Tok);
Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=63003&r1=63002&r2=63003&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
+++ cfe/trunk/lib/Lex/PPDirectives.cpp Mon Jan 26 00:19:46 2009
@@ -478,9 +478,8 @@
LexUnexpandedToken(Result);
goto TryAgain;
- case tok::numeric_constant:
- // FIXME: implement # 7 line numbers!
- return DiscardUntilEndOfDirective();
+ case tok::numeric_constant: // # 7 GNU line marker directive.
+ return HandleDigitDirective(Result);
default:
IdentifierInfo *II = Result.getIdentifierInfo();
if (II == 0) break; // Not an identifier.
@@ -556,56 +555,68 @@
// 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.
+/// GetLineValue - Convert a numeric token into an unsigned value, emitting
+/// Diagnostic DiagID if it is invalid, and returning the value in Val.
+static bool GetLineValue(Token &DigitTok, unsigned &Val,
+ unsigned DiagID, Preprocessor &PP) {
if (DigitTok.isNot(tok::numeric_constant)) {
- Diag(DigitTok, diag::err_pp_line_requires_integer);
+ PP.Diag(DigitTok, DiagID);
+
if (DigitTok.isNot(tok::eom))
- DiscardUntilEndOfDirective();
- return;
+ PP.DiscardUntilEndOfDirective();
+ return true;
}
- // 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);
+ unsigned ActualLength = PP.getSpelling(DigitTok, DigitTokBegin);
NumericLiteralParser Literal(DigitTokBegin, DigitTokBegin+ActualLength,
- DigitTok.getLocation(), *this);
+ DigitTok.getLocation(), PP);
if (Literal.hadError)
- return DiscardUntilEndOfDirective(); // a diagnostic was already reported.
+ return true; // Error already emitted.
if (Literal.isFloatingLiteral() || Literal.isImaginary) {
- Diag(DigitTok, diag::err_pp_line_requires_integer);
- return;
+ PP.Diag(DigitTok, DiagID);
+ return true;
}
// Parse the integer literal into Result.
- llvm::APInt Val(32, 0);
- if (Literal.GetIntegerValue(Val)) {
+ llvm::APInt APVal(32, 0);
+ if (Literal.GetIntegerValue(APVal)) {
// Overflow parsing integer literal.
- Diag(DigitTok, diag::err_pp_line_requires_integer);
- return DiscardUntilEndOfDirective();
+ PP.Diag(DigitTok, DiagID);
+ return true;
}
-
- // 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();
+ Val = APVal.getZExtValue();
+
+ // Reject 0, this is needed both by #line numbers and flags.
+ if (Val == 0) {
+ PP.Diag(DigitTok, DiagID);
+ PP.DiscardUntilEndOfDirective();
+ return true;
}
- // C90 requires that the line # be less than 32767, and C99 ups the limit.
+ return false;
+}
+
+/// 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);
+
+ // Validate the number and convert it to an unsigned.
+ unsigned LineNo;
+ if (GetLineValue(DigitTok, LineNo, diag::err_pp_line_requires_integer, *this))
+ return;
+
+ // Enforce C99 6.10.4p3: "The digit sequence shall not specify ... a
+ // number greater than 2147483647". C90 requires that the line # be <= 32767.
unsigned LineLimit = Features.C99 ? 2147483648U : 32768U;
if (LineNo >= LineLimit)
Diag(DigitTok, diag::ext_pp_line_too_big) << LineLimit;
@@ -629,6 +640,108 @@
// FIXME: do something with the #line info.
}
+/// ReadLineMarkerFlags - Parse and validate any flags at the end of a GNU line
+/// marker directive.
+static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
+ bool &IsSystemHeader, bool &IsExternCHeader,
+ Preprocessor &PP) {
+ unsigned FlagVal;
+ Token FlagTok;
+ PP.Lex(FlagTok);
+ if (FlagTok.is(tok::eom)) return false;
+ if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag, PP))
+ return true;
+
+ if (FlagVal == 1) {
+ IsFileEntry = true;
+
+ PP.Lex(FlagTok);
+ if (FlagTok.is(tok::eom)) return false;
+ if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag,PP))
+ return true;
+ } else if (FlagVal == 2) {
+ IsFileExit = true;
+
+ PP.Lex(FlagTok);
+ if (FlagTok.is(tok::eom)) return false;
+ if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag,PP))
+ return true;
+ }
+
+ // We must have 3 if there are still flags.
+ if (FlagVal != 3) {
+ PP.Diag(FlagTok, diag::err_pp_linemarker_invalid_flag);
+ return true;
+ }
+
+ IsSystemHeader = true;
+
+ PP.Lex(FlagTok);
+ if (FlagTok.is(tok::eom)) return false;
+ if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag,PP))
+ return true;
+
+ // We must have 4 if there is yet another flag.
+ if (FlagVal != 4) {
+ PP.Diag(FlagTok, diag::err_pp_linemarker_invalid_flag);
+ return true;
+ }
+
+ IsExternCHeader = true;
+
+ PP.Lex(FlagTok);
+ if (FlagTok.is(tok::eom)) return false;
+
+ // There are no more valid flags here.
+ PP.Diag(FlagTok, diag::err_pp_linemarker_invalid_flag);
+ return true;
+}
+
+/// HandleDigitDirective - Handle a GNU line marker directive, whose syntax is
+/// one of the following forms:
+///
+/// # 42
+/// # 42 "file" ('1' | '2')?
+/// # 42 "file" ('1' | '2')? '3' '4'?
+///
+void Preprocessor::HandleDigitDirective(Token &DigitTok) {
+ // Validate the number and convert it to an unsigned. GNU does not have a
+ // line # limit other than it fit in 32-bits.
+ unsigned LineNo;
+ if (GetLineValue(DigitTok, LineNo, diag::err_pp_linemarker_requires_integer,
+ *this))
+ return;
+
+ Token StrTok;
+ Lex(StrTok);
+
+ bool IsFileEntry = false, IsFileExit = false;
+ bool IsSystemHeader = false, IsExternCHeader = false;
+
+ // 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_linemarker_invalid_filename);
+ DiscardUntilEndOfDirective();
+ return;
+ } else {
+ // If a filename was present, read any flags that are present.
+ if (ReadLineMarkerFlags(IsFileEntry, IsFileExit,
+ IsSystemHeader, IsExternCHeader, *this)) {
+ DiscardUntilEndOfDirective();
+ return;
+ }
+ }
+
+ // FIXME: do something with the #line info.
+
+
+
+}
+
+
/// HandleUserDiagnosticDirective - Handle a #warning or #error directive.
///
void Preprocessor::HandleUserDiagnosticDirective(Token &Tok,
Modified: cfe/trunk/test/Preprocessor/line-directive.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/line-directive.c?rev=63003&r1=63002&r2=63003&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/line-directive.c (original)
+++ cfe/trunk/test/Preprocessor/line-directive.c Mon Jan 26 00:19:46 2009
@@ -12,3 +12,16 @@
#define A 42 "foo"
#line A
+# 42
+# 42 "foo"
+# 42 "foo" 1 3
+# 42 "foo" 2 3
+# 42 "foo" 2 3 4
+# 42 "foo" 3 4
+
+# 'a' // expected-error {{invalid preprocessing directive}}
+# 42 'f' // expected-error {{invalid filename for line marker directive}}
+# 42 1 3 // expected-error {{invalid filename for line marker directive}}
+# 42 "foo" 3 1 // expected-error {{invalid flag line marker directive}}
+# 42 "foo" 42 // expected-error {{invalid flag line marker directive}}
+# 42 "foo" 1 2 // expected-error {{invalid flag line marker directive}}
More information about the cfe-commits
mailing list