aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-05-26 05:35:51 +0000
committerDouglas Gregor <dgregor@apple.com>2010-05-26 05:35:51 +0000
commitb90f4b3fb94056609da9cca5eef7358d95a363b2 (patch)
tree512a4ad9da7041f437030b121f1d65a747e8f30e
parentaa230b7bd2054e70e9500aff584845cb1cc34ca7 (diff)
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>. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104684 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Lex/LiteralSupport.h4
-rw-r--r--lib/Lex/LiteralSupport.cpp55
-rw-r--r--lib/Sema/SemaChecking.cpp5
-rw-r--r--test/Sema/format-strings.c3
4 files changed, 43 insertions, 24 deletions
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index 2334d728f6..ba46fb18a6 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -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
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index f425582264..b73f236641 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -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;
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 8474944f06..4f3f41b715 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -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.
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index bdc2bb0c9a..d6d37961d9 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -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}}
+}