forked from OSchip/llvm-project
Tell the string literal parser when it's not permitted to emit
diagnostics. That would be while we're parsing string literals for the sole purpose of producing a diagnostic about them. Fixes <rdar://problem/8026030>. llvm-svn: 104684
This commit is contained in:
parent
b48414f4cb
commit
9af03022ff
|
@ -147,7 +147,7 @@ class StringLiteralParser {
|
|||
char *ResultPtr; // cursor
|
||||
public:
|
||||
StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
|
||||
Preprocessor &PP);
|
||||
Preprocessor &PP, bool Complain = true);
|
||||
bool hadError;
|
||||
bool AnyWide;
|
||||
bool Pascal;
|
||||
|
@ -164,7 +164,7 @@ public:
|
|||
/// specified byte of the string data represented by Token. This handles
|
||||
/// advancing over escape sequences in the string.
|
||||
static unsigned getOffsetOfStringByte(const Token &TheTok, unsigned ByteNo,
|
||||
Preprocessor &PP);
|
||||
Preprocessor &PP, bool Complain = true);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -34,7 +34,7 @@ static int HexDigitValue(char C) {
|
|||
static unsigned ProcessCharEscape(const char *&ThisTokBuf,
|
||||
const char *ThisTokEnd, bool &HadError,
|
||||
SourceLocation Loc, bool IsWide,
|
||||
Preprocessor &PP) {
|
||||
Preprocessor &PP, bool Complain) {
|
||||
// Skip the '\' char.
|
||||
++ThisTokBuf;
|
||||
|
||||
|
@ -54,11 +54,13 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
|
|||
ResultChar = 8;
|
||||
break;
|
||||
case 'e':
|
||||
PP.Diag(Loc, diag::ext_nonstandard_escape) << "e";
|
||||
if (Complain)
|
||||
PP.Diag(Loc, diag::ext_nonstandard_escape) << "e";
|
||||
ResultChar = 27;
|
||||
break;
|
||||
case 'E':
|
||||
PP.Diag(Loc, diag::ext_nonstandard_escape) << "E";
|
||||
if (Complain)
|
||||
PP.Diag(Loc, diag::ext_nonstandard_escape) << "E";
|
||||
ResultChar = 27;
|
||||
break;
|
||||
case 'f':
|
||||
|
@ -79,7 +81,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
|
|||
case 'x': { // Hex escape.
|
||||
ResultChar = 0;
|
||||
if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
|
||||
PP.Diag(Loc, diag::err_hex_escape_no_digits);
|
||||
if (Complain)
|
||||
PP.Diag(Loc, diag::err_hex_escape_no_digits);
|
||||
HadError = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -106,7 +109,7 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
|
|||
}
|
||||
|
||||
// Check for overflow.
|
||||
if (Overflow) // Too many digits to fit in
|
||||
if (Overflow && Complain) // Too many digits to fit in
|
||||
PP.Diag(Loc, diag::warn_hex_escape_too_large);
|
||||
break;
|
||||
}
|
||||
|
@ -132,7 +135,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
|
|||
: PP.getTargetInfo().getCharWidth();
|
||||
|
||||
if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
|
||||
PP.Diag(Loc, diag::warn_octal_escape_too_large);
|
||||
if (Complain)
|
||||
PP.Diag(Loc, diag::warn_octal_escape_too_large);
|
||||
ResultChar &= ~0U >> (32-CharWidth);
|
||||
}
|
||||
break;
|
||||
|
@ -141,10 +145,14 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
|
|||
// Otherwise, these are not valid escapes.
|
||||
case '(': case '{': case '[': case '%':
|
||||
// GCC accepts these as extensions. We warn about them as such though.
|
||||
PP.Diag(Loc, diag::ext_nonstandard_escape)
|
||||
<< std::string()+(char)ResultChar;
|
||||
if (Complain)
|
||||
PP.Diag(Loc, diag::ext_nonstandard_escape)
|
||||
<< std::string()+(char)ResultChar;
|
||||
break;
|
||||
default:
|
||||
if (!Complain)
|
||||
break;
|
||||
|
||||
if (isgraph(ThisTokBuf[0]))
|
||||
PP.Diag(Loc, diag::ext_unknown_escape) << std::string()+(char)ResultChar;
|
||||
else
|
||||
|
@ -161,7 +169,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
|
|||
/// we will likely rework our support for UCN's.
|
||||
static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
|
||||
char *&ResultBuf, bool &HadError,
|
||||
SourceLocation Loc, bool IsWide, Preprocessor &PP)
|
||||
SourceLocation Loc, bool IsWide, Preprocessor &PP,
|
||||
bool Complain)
|
||||
{
|
||||
// FIXME: Add a warning - UCN's are only valid in C++ & C99.
|
||||
// FIXME: Handle wide strings.
|
||||
|
@ -173,7 +182,8 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
|
|||
ThisTokBuf += 2;
|
||||
|
||||
if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
|
||||
PP.Diag(Loc, diag::err_ucn_escape_no_digits);
|
||||
if (Complain)
|
||||
PP.Diag(Loc, diag::err_ucn_escape_no_digits);
|
||||
HadError = 1;
|
||||
return;
|
||||
}
|
||||
|
@ -189,8 +199,9 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
|
|||
}
|
||||
// If we didn't consume the proper number of digits, there is a problem.
|
||||
if (UcnLen) {
|
||||
PP.Diag(PP.AdvanceToTokenCharacter(Loc, ThisTokBuf-ThisTokBegin),
|
||||
diag::err_ucn_escape_incomplete);
|
||||
if (Complain)
|
||||
PP.Diag(PP.AdvanceToTokenCharacter(Loc, ThisTokBuf-ThisTokBegin),
|
||||
diag::err_ucn_escape_incomplete);
|
||||
HadError = 1;
|
||||
return;
|
||||
}
|
||||
|
@ -199,7 +210,8 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
|
|||
(UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60 )) // $, @, `
|
||||
|| (UcnVal >= 0xD800 && UcnVal <= 0xDFFF)
|
||||
|| (UcnVal > 0x10FFFF)) /* the maximum legal UTF32 value */ {
|
||||
PP.Diag(Loc, diag::err_ucn_escape_invalid);
|
||||
if (Complain)
|
||||
PP.Diag(Loc, diag::err_ucn_escape_invalid);
|
||||
HadError = 1;
|
||||
return;
|
||||
}
|
||||
|
@ -660,7 +672,8 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
|
|||
if (begin[0] != '\\') // If this is a normal character, consume it.
|
||||
ResultChar = *begin++;
|
||||
else // Otherwise, this is an escape character.
|
||||
ResultChar = ProcessCharEscape(begin, end, HadError, Loc, IsWide, PP);
|
||||
ResultChar = ProcessCharEscape(begin, end, HadError, Loc, IsWide, PP,
|
||||
/*Complain=*/true);
|
||||
|
||||
// If this is a multi-character constant (e.g. 'abc'), handle it. These are
|
||||
// implementation defined (C99 6.4.4.4p10).
|
||||
|
@ -746,7 +759,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
|
|||
///
|
||||
StringLiteralParser::
|
||||
StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
|
||||
Preprocessor &pp) : PP(pp) {
|
||||
Preprocessor &pp, bool Complain) : PP(pp) {
|
||||
// Scan all of the string portions, remember the max individual token length,
|
||||
// computing a bound on the concatenated string length, and see whether any
|
||||
// piece is a wide-string. If any of the string portions is a wide-string
|
||||
|
@ -871,13 +884,14 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
|
|||
// Is this a Universal Character Name escape?
|
||||
if (ThisTokBuf[1] == 'u' || ThisTokBuf[1] == 'U') {
|
||||
ProcessUCNEscape(ThisTokBuf, ThisTokEnd, ResultPtr,
|
||||
hadError, StringToks[i].getLocation(), ThisIsWide, PP);
|
||||
hadError, StringToks[i].getLocation(), ThisIsWide, PP,
|
||||
Complain);
|
||||
continue;
|
||||
}
|
||||
// Otherwise, this is a non-UCN escape character. Process it.
|
||||
unsigned ResultChar = ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError,
|
||||
StringToks[i].getLocation(),
|
||||
ThisIsWide, PP);
|
||||
ThisIsWide, PP, Complain);
|
||||
|
||||
// Note: our internal rep of wide char tokens is always little-endian.
|
||||
*ResultPtr++ = ResultChar & 0xFF;
|
||||
|
@ -893,7 +907,7 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
|
|||
ResultBuf[0] = ResultPtr-&ResultBuf[0]-1;
|
||||
|
||||
// Verify that pascal strings aren't too large.
|
||||
if (GetStringLength() > 256) {
|
||||
if (GetStringLength() > 256 && Complain) {
|
||||
PP.Diag(StringToks[0].getLocation(), diag::err_pascal_string_too_long)
|
||||
<< SourceRange(StringToks[0].getLocation(),
|
||||
StringToks[NumStringToks-1].getLocation());
|
||||
|
@ -909,7 +923,8 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
|
|||
/// advancing over escape sequences in the string.
|
||||
unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
|
||||
unsigned ByteNo,
|
||||
Preprocessor &PP) {
|
||||
Preprocessor &PP,
|
||||
bool Complain) {
|
||||
// Get the spelling of the token.
|
||||
llvm::SmallString<16> SpellingBuffer;
|
||||
SpellingBuffer.resize(Tok.getLength());
|
||||
|
@ -945,7 +960,7 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
|
|||
// Otherwise, this is an escape character. Advance over it.
|
||||
bool HadError = false;
|
||||
ProcessCharEscape(SpellingPtr, SpellingEnd, HadError,
|
||||
Tok.getLocation(), false, PP);
|
||||
Tok.getLocation(), false, PP, Complain);
|
||||
assert(!HadError && "This method isn't valid on erroneous strings");
|
||||
--ByteNo;
|
||||
}
|
||||
|
|
|
@ -75,14 +75,15 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
|
|||
TheLexer.LexFromRawLexer(TheTok);
|
||||
|
||||
// Use the StringLiteralParser to compute the length of the string in bytes.
|
||||
StringLiteralParser SLP(&TheTok, 1, PP);
|
||||
StringLiteralParser SLP(&TheTok, 1, PP, /*Complain=*/false);
|
||||
unsigned TokNumBytes = SLP.GetStringLength();
|
||||
|
||||
// If the byte is in this token, return the location of the byte.
|
||||
if (ByteNo < TokNumBytes ||
|
||||
(ByteNo == TokNumBytes && TokNo == SL->getNumConcatenated())) {
|
||||
unsigned Offset =
|
||||
StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP);
|
||||
StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP,
|
||||
/*Complain=*/false);
|
||||
|
||||
// Now that we know the offset of the token in the spelling, use the
|
||||
// preprocessor to get the offset in the original source.
|
||||
|
|
|
@ -251,3 +251,6 @@ void test_pr_6697() {
|
|||
myprintf_PR_6697("%1$s\n", 1, (int) 0); // expected-warning{{conversion specifies type 'char *' but the argument has type 'int'}}
|
||||
}
|
||||
|
||||
void rdar8026030(FILE *fp) {
|
||||
fprintf(fp, "\%"); // expected-warning{{incomplete format specifier}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue