forked from OSchip/llvm-project
add parsing and constraint enforcement for GNU line marker directives.
llvm-svn: 63003
This commit is contained in:
parent
e9193283c6
commit
76e689636b
|
@ -204,6 +204,12 @@ 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(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")
|
||||
|
||||
|
|
|
@ -532,6 +532,11 @@ public:
|
|||
/// 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 @@ private:
|
|||
/// #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 @@ private:
|
|||
/// 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);
|
||||
|
||||
|
|
|
@ -478,9 +478,8 @@ TryAgain:
|
|||
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,6 +555,51 @@ TryAgain:
|
|||
// Okay, we're done parsing the directive.
|
||||
}
|
||||
|
||||
/// 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)) {
|
||||
PP.Diag(DigitTok, DiagID);
|
||||
|
||||
if (DigitTok.isNot(tok::eom))
|
||||
PP.DiscardUntilEndOfDirective();
|
||||
return true;
|
||||
}
|
||||
|
||||
llvm::SmallString<64> IntegerBuffer;
|
||||
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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
PP.DiscardUntilEndOfDirective();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// HandleLineDirective - Handle #line directive: C99 6.10.4. The two
|
||||
/// acceptable forms are:
|
||||
/// # line digit-sequence
|
||||
|
@ -566,46 +610,13 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
|
|||
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);
|
||||
unsigned LineNo;
|
||||
if (GetLineValue(DigitTok, LineNo, diag::err_pp_line_requires_integer, *this))
|
||||
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.
|
||||
// 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 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
|
|||
// 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,
|
||||
|
|
|
@ -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}}
|
||||
|
|
Loading…
Reference in New Issue