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:
Douglas Gregor 2010-05-26 05:35:51 +00:00
parent b48414f4cb
commit 9af03022ff
4 changed files with 43 additions and 24 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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.

View File

@ -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}}
}