diff options
Diffstat (limited to 'clang/lib/Lex/Lexer.cpp')
| -rw-r--r-- | clang/lib/Lex/Lexer.cpp | 467 |
1 files changed, 274 insertions, 193 deletions
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 3034af231e0e..38467a1835d0 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -133,10 +133,10 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr, /// assumes that the associated file buffer and Preprocessor objects will /// outlive it, so it doesn't take ownership of either of them. Lexer::Lexer(FileID FID, const llvm::MemoryBufferRef &InputFile, - Preprocessor &PP) + Preprocessor &PP, bool IsFirstIncludeOfFile) : PreprocessorLexer(&PP, FID), FileLoc(PP.getSourceManager().getLocForStartOfFile(FID)), - LangOpts(PP.getLangOpts()) { + LangOpts(PP.getLangOpts()), IsFirstTimeLexingFile(IsFirstIncludeOfFile) { InitLexer(InputFile.getBufferStart(), InputFile.getBufferStart(), InputFile.getBufferEnd()); @@ -147,8 +147,10 @@ Lexer::Lexer(FileID FID, const llvm::MemoryBufferRef &InputFile, /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. Lexer::Lexer(SourceLocation fileloc, const LangOptions &langOpts, - const char *BufStart, const char *BufPtr, const char *BufEnd) - : FileLoc(fileloc), LangOpts(langOpts) { + const char *BufStart, const char *BufPtr, const char *BufEnd, + bool IsFirstIncludeOfFile) + : FileLoc(fileloc), LangOpts(langOpts), + IsFirstTimeLexingFile(IsFirstIncludeOfFile) { InitLexer(BufStart, BufPtr, BufEnd); // We *are* in raw mode. @@ -159,9 +161,11 @@ Lexer::Lexer(SourceLocation fileloc, const LangOptions &langOpts, /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. Lexer::Lexer(FileID FID, const llvm::MemoryBufferRef &FromFile, - const SourceManager &SM, const LangOptions &langOpts) + const SourceManager &SM, const LangOptions &langOpts, + bool IsFirstIncludeOfFile) : Lexer(SM.getLocForStartOfFile(FID), langOpts, FromFile.getBufferStart(), - FromFile.getBufferStart(), FromFile.getBufferEnd()) {} + FromFile.getBufferStart(), FromFile.getBufferEnd(), + IsFirstIncludeOfFile) {} void Lexer::resetExtendedTokenMode() { assert(PP && "Cannot reset token mode without a preprocessor"); @@ -1062,8 +1066,8 @@ StringRef Lexer::getImmediateMacroNameForDiagnostics( return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength); } -bool Lexer::isIdentifierBodyChar(char c, const LangOptions &LangOpts) { - return isIdentifierBody(c, LangOpts.DollarIdents); +bool Lexer::isAsciiIdentifierContinueChar(char c, const LangOptions &LangOpts) { + return isAsciiIdentifierContinue(c, LangOpts.DollarIdents); } bool Lexer::isNewLineEscaped(const char *BufferStart, const char *Str) { @@ -1446,19 +1450,30 @@ void Lexer::SetByteOffset(unsigned Offset, bool StartOfLine) { IsAtPhysicalStartOfLine = StartOfLine; } +static bool isUnicodeWhitespace(uint32_t Codepoint) { + static const llvm::sys::UnicodeCharSet UnicodeWhitespaceChars( + UnicodeWhitespaceCharRanges); + return UnicodeWhitespaceChars.contains(Codepoint); +} + static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) { if (LangOpts.AsmPreprocessor) { return false; } else if (LangOpts.DollarIdents && '$' == C) { return true; - } else if (LangOpts.CPlusPlus11 || LangOpts.C11) { + } else if (LangOpts.CPlusPlus) { + // A non-leading codepoint must have the XID_Continue property. + // XIDContinueRanges doesn't contains characters also in XIDStartRanges, + // so we need to check both tables. + // '_' doesn't have the XID_Continue property but is allowed in C++. + static const llvm::sys::UnicodeCharSet XIDStartChars(XIDStartRanges); + static const llvm::sys::UnicodeCharSet XIDContinueChars(XIDContinueRanges); + return C == '_' || XIDStartChars.contains(C) || + XIDContinueChars.contains(C); + } else if (LangOpts.C11) { static const llvm::sys::UnicodeCharSet C11AllowedIDChars( C11AllowedIDCharRanges); return C11AllowedIDChars.contains(C); - } else if (LangOpts.CPlusPlus) { - static const llvm::sys::UnicodeCharSet CXX03AllowedIDChars( - CXX03AllowedIDCharRanges); - return CXX03AllowedIDChars.contains(C); } else { static const llvm::sys::UnicodeCharSet C99AllowedIDChars( C99AllowedIDCharRanges); @@ -1467,20 +1482,24 @@ static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) { } static bool isAllowedInitiallyIDChar(uint32_t C, const LangOptions &LangOpts) { - assert(isAllowedIDChar(C, LangOpts)); if (LangOpts.AsmPreprocessor) { return false; - } else if (LangOpts.CPlusPlus11 || LangOpts.C11) { + } + if (LangOpts.CPlusPlus) { + static const llvm::sys::UnicodeCharSet XIDStartChars(XIDStartRanges); + // '_' doesn't have the XID_Start property but is allowed in C++. + return C == '_' || XIDStartChars.contains(C); + } + if (!isAllowedIDChar(C, LangOpts)) + return false; + if (LangOpts.C11) { static const llvm::sys::UnicodeCharSet C11DisallowedInitialIDChars( C11DisallowedInitialIDCharRanges); return !C11DisallowedInitialIDChars.contains(C); - } else if (LangOpts.CPlusPlus) { - return true; - } else { - static const llvm::sys::UnicodeCharSet C99DisallowedInitialIDChars( - C99DisallowedInitialIDCharRanges); - return !C99DisallowedInitialIDChars.contains(C); } + static const llvm::sys::UnicodeCharSet C99DisallowedInitialIDChars( + C99DisallowedInitialIDCharRanges); + return !C99DisallowedInitialIDChars.contains(C); } static inline CharSourceRange makeCharRange(Lexer &L, const char *Begin, @@ -1512,16 +1531,6 @@ static void maybeDiagnoseIDCharCompat(DiagnosticsEngine &Diags, uint32_t C, << CannotStartIdentifier; } } - - // Check C++98 compatibility. - if (!Diags.isIgnored(diag::warn_cxx98_compat_unicode_id, Range.getBegin())) { - static const llvm::sys::UnicodeCharSet CXX03AllowedIDChars( - CXX03AllowedIDCharRanges); - if (!CXX03AllowedIDChars.contains(C)) { - Diags.Report(Range.getBegin(), diag::warn_cxx98_compat_unicode_id) - << Range; - } - } } /// After encountering UTF-8 character C and interpreting it as an identifier @@ -1608,14 +1617,56 @@ static void maybeDiagnoseUTF8Homoglyph(DiagnosticsEngine &Diags, uint32_t C, } } +static void diagnoseInvalidUnicodeCodepointInIdentifier( + DiagnosticsEngine &Diags, const LangOptions &LangOpts, uint32_t CodePoint, + CharSourceRange Range, bool IsFirst) { + if (isASCII(CodePoint)) + return; + + bool IsIDStart = isAllowedInitiallyIDChar(CodePoint, LangOpts); + bool IsIDContinue = IsIDStart || isAllowedIDChar(CodePoint, LangOpts); + + if ((IsFirst && IsIDStart) || (!IsFirst && IsIDContinue)) + return; + + bool InvalidOnlyAtStart = IsFirst && !IsIDStart && IsIDContinue; + + llvm::SmallString<5> CharBuf; + llvm::raw_svector_ostream CharOS(CharBuf); + llvm::write_hex(CharOS, CodePoint, llvm::HexPrintStyle::Upper, 4); + + if (!IsFirst || InvalidOnlyAtStart) { + Diags.Report(Range.getBegin(), diag::err_character_not_allowed_identifier) + << Range << CharBuf << int(InvalidOnlyAtStart) + << FixItHint::CreateRemoval(Range); + } else { + Diags.Report(Range.getBegin(), diag::err_character_not_allowed) + << Range << CharBuf << FixItHint::CreateRemoval(Range); + } +} + bool Lexer::tryConsumeIdentifierUCN(const char *&CurPtr, unsigned Size, Token &Result) { const char *UCNPtr = CurPtr + Size; uint32_t CodePoint = tryReadUCN(UCNPtr, CurPtr, /*Token=*/nullptr); - if (CodePoint == 0 || !isAllowedIDChar(CodePoint, LangOpts)) + if (CodePoint == 0) { return false; + } - if (!isLexingRawMode()) + if (!isAllowedIDChar(CodePoint, LangOpts)) { + if (isASCII(CodePoint) || isUnicodeWhitespace(CodePoint)) + return false; + if (!isLexingRawMode() && !ParsingPreprocessorDirective && + !PP->isPreprocessedOutput()) + diagnoseInvalidUnicodeCodepointInIdentifier( + PP->getDiagnostics(), LangOpts, CodePoint, + makeCharRange(*this, CurPtr, UCNPtr), + /*IsFirst=*/false); + + // We got a unicode codepoint that is neither a space nor a + // a valid identifier part. + // Carry on as if the codepoint was valid for recovery purposes. + } else if (!isLexingRawMode()) maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint, makeCharRange(*this, CurPtr, UCNPtr), /*IsFirst=*/false); @@ -1638,11 +1689,22 @@ bool Lexer::tryConsumeIdentifierUTF8Char(const char *&CurPtr) { (const llvm::UTF8 *)BufferEnd, &CodePoint, llvm::strictConversion); - if (Result != llvm::conversionOK || - !isAllowedIDChar(static_cast<uint32_t>(CodePoint), LangOpts)) + if (Result != llvm::conversionOK) return false; - if (!isLexingRawMode()) { + if (!isAllowedIDChar(static_cast<uint32_t>(CodePoint), LangOpts)) { + if (isASCII(CodePoint) || isUnicodeWhitespace(CodePoint)) + return false; + + if (!isLexingRawMode() && !ParsingPreprocessorDirective && + !PP->isPreprocessedOutput()) + diagnoseInvalidUnicodeCodepointInIdentifier( + PP->getDiagnostics(), LangOpts, CodePoint, + makeCharRange(*this, CurPtr, UnicodePtr), /*IsFirst=*/false); + // We got a unicode codepoint that is neither a space nor a + // a valid identifier part. Carry on as if the codepoint was + // valid for recovery purposes. + } else if (!isLexingRawMode()) { maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint, makeCharRange(*this, CurPtr, UnicodePtr), /*IsFirst=*/false); @@ -1654,103 +1716,128 @@ bool Lexer::tryConsumeIdentifierUTF8Char(const char *&CurPtr) { return true; } -bool Lexer::LexIdentifier(Token &Result, const char *CurPtr) { - // Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$] - unsigned Size; - unsigned char C = *CurPtr++; - while (isIdentifierBody(C)) - C = *CurPtr++; - - --CurPtr; // Back up over the skipped character. - - // Fast path, no $,\,? in identifier found. '\' might be an escaped newline - // or UCN, and ? might be a trigraph for '\', an escaped newline or UCN. - // - // TODO: Could merge these checks into an InfoTable flag to make the - // comparison cheaper - if (isASCII(C) && C != '\\' && C != '?' && - (C != '$' || !LangOpts.DollarIdents)) { -FinishIdentifier: - const char *IdStart = BufferPtr; - FormTokenWithChars(Result, CurPtr, tok::raw_identifier); - Result.setRawIdentifierData(IdStart); - - // If we are in raw mode, return this identifier raw. There is no need to - // look up identifier information or attempt to macro expand it. - if (LexingRawMode) - return true; - - // Fill in Result.IdentifierInfo and update the token kind, - // looking up the identifier in the identifier table. - IdentifierInfo *II = PP->LookUpIdentifierInfo(Result); - // Note that we have to call PP->LookUpIdentifierInfo() even for code - // completion, it writes IdentifierInfo into Result, and callers rely on it. - - // If the completion point is at the end of an identifier, we want to treat - // the identifier as incomplete even if it resolves to a macro or a keyword. - // This allows e.g. 'class^' to complete to 'classifier'. - if (isCodeCompletionPoint(CurPtr)) { - // Return the code-completion token. - Result.setKind(tok::code_completion); - // Skip the code-completion char and all immediate identifier characters. - // This ensures we get consistent behavior when completing at any point in - // an identifier (i.e. at the start, in the middle, at the end). Note that - // only simple cases (i.e. [a-zA-Z0-9_]) are supported to keep the code - // simpler. - assert(*CurPtr == 0 && "Completion character must be 0"); - ++CurPtr; - // Note that code completion token is not added as a separate character - // when the completion point is at the end of the buffer. Therefore, we need - // to check if the buffer has ended. - if (CurPtr < BufferEnd) { - while (isIdentifierBody(*CurPtr)) - ++CurPtr; - } - BufferPtr = CurPtr; - return true; +bool Lexer::LexUnicodeIdentifierStart(Token &Result, uint32_t C, + const char *CurPtr) { + if (isAllowedInitiallyIDChar(C, LangOpts)) { + if (!isLexingRawMode() && !ParsingPreprocessorDirective && + !PP->isPreprocessedOutput()) { + maybeDiagnoseIDCharCompat(PP->getDiagnostics(), C, + makeCharRange(*this, BufferPtr, CurPtr), + /*IsFirst=*/true); + maybeDiagnoseUTF8Homoglyph(PP->getDiagnostics(), C, + makeCharRange(*this, BufferPtr, CurPtr)); } - // Finally, now that we know we have an identifier, pass this off to the - // preprocessor, which may macro expand it or something. - if (II->isHandleIdentifierCase()) - return PP->HandleIdentifier(Result); + MIOpt.ReadToken(); + return LexIdentifierContinue(Result, CurPtr); + } - return true; + if (!isLexingRawMode() && !ParsingPreprocessorDirective && + !PP->isPreprocessedOutput() && !isASCII(*BufferPtr) && + !isAllowedInitiallyIDChar(C, LangOpts) && !isUnicodeWhitespace(C)) { + // Non-ASCII characters tend to creep into source code unintentionally. + // Instead of letting the parser complain about the unknown token, + // just drop the character. + // Note that we can /only/ do this when the non-ASCII character is actually + // spelled as Unicode, not written as a UCN. The standard requires that + // we not throw away any possible preprocessor tokens, but there's a + // loophole in the mapping of Unicode characters to basic character set + // characters that allows us to map these particular characters to, say, + // whitespace. + diagnoseInvalidUnicodeCodepointInIdentifier( + PP->getDiagnostics(), LangOpts, C, + makeCharRange(*this, BufferPtr, CurPtr), /*IsStart*/ true); + BufferPtr = CurPtr; + return false; } - // Otherwise, $,\,? in identifier found. Enter slower path. + // Otherwise, we have an explicit UCN or a character that's unlikely to show + // up by accident. + MIOpt.ReadToken(); + FormTokenWithChars(Result, CurPtr, tok::unknown); + return true; +} - C = getCharAndSize(CurPtr, Size); +bool Lexer::LexIdentifierContinue(Token &Result, const char *CurPtr) { + // Match [_A-Za-z0-9]*, we have already matched an identifier start. while (true) { + unsigned char C = *CurPtr; + // Fast path. + if (isAsciiIdentifierContinue(C)) { + ++CurPtr; + continue; + } + + unsigned Size; + // Slow path: handle trigraph, unicode codepoints, UCNs. + C = getCharAndSize(CurPtr, Size); + if (isAsciiIdentifierContinue(C)) { + CurPtr = ConsumeChar(CurPtr, Size, Result); + continue; + } if (C == '$') { // If we hit a $ and they are not supported in identifiers, we are done. - if (!LangOpts.DollarIdents) goto FinishIdentifier; - + if (!LangOpts.DollarIdents) + break; // Otherwise, emit a diagnostic and continue. if (!isLexingRawMode()) Diag(CurPtr, diag::ext_dollar_in_identifier); CurPtr = ConsumeChar(CurPtr, Size, Result); - C = getCharAndSize(CurPtr, Size); continue; - } else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) { - C = getCharAndSize(CurPtr, Size); + } + if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) continue; - } else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) { - C = getCharAndSize(CurPtr, Size); + if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) continue; - } else if (!isIdentifierBody(C)) { - goto FinishIdentifier; - } + // Neither an expected Unicode codepoint nor a UCN. + break; + } - // Otherwise, this character is good, consume it. - CurPtr = ConsumeChar(CurPtr, Size, Result); + const char *IdStart = BufferPtr; + FormTokenWithChars(Result, CurPtr, tok::raw_identifier); + Result.setRawIdentifierData(IdStart); - C = getCharAndSize(CurPtr, Size); - while (isIdentifierBody(C)) { - CurPtr = ConsumeChar(CurPtr, Size, Result); - C = getCharAndSize(CurPtr, Size); + // If we are in raw mode, return this identifier raw. There is no need to + // look up identifier information or attempt to macro expand it. + if (LexingRawMode) + return true; + + // Fill in Result.IdentifierInfo and update the token kind, + // looking up the identifier in the identifier table. + IdentifierInfo *II = PP->LookUpIdentifierInfo(Result); + // Note that we have to call PP->LookUpIdentifierInfo() even for code + // completion, it writes IdentifierInfo into Result, and callers rely on it. + + // If the completion point is at the end of an identifier, we want to treat + // the identifier as incomplete even if it resolves to a macro or a keyword. + // This allows e.g. 'class^' to complete to 'classifier'. + if (isCodeCompletionPoint(CurPtr)) { + // Return the code-completion token. + Result.setKind(tok::code_completion); + // Skip the code-completion char and all immediate identifier characters. + // This ensures we get consistent behavior when completing at any point in + // an identifier (i.e. at the start, in the middle, at the end). Note that + // only simple cases (i.e. [a-zA-Z0-9_]) are supported to keep the code + // simpler. + assert(*CurPtr == 0 && "Completion character must be 0"); + ++CurPtr; + // Note that code completion token is not added as a separate character + // when the completion point is at the end of the buffer. Therefore, we need + // to check if the buffer has ended. + if (CurPtr < BufferEnd) { + while (isAsciiIdentifierContinue(*CurPtr)) + ++CurPtr; } + BufferPtr = CurPtr; + return true; } + + // Finally, now that we know we have an identifier, pass this off to the + // preprocessor, which may macro expand it or something. + if (II->isHandleIdentifierCase()) + return PP->HandleIdentifier(Result); + + return true; } /// isHexaLiteral - Return true if Start points to a hex constant. @@ -1806,7 +1893,7 @@ bool Lexer::LexNumericConstant(Token &Result, const char *CurPtr) { if (C == '\'' && (getLangOpts().CPlusPlus14 || getLangOpts().C2x)) { unsigned NextSize; char Next = getCharAndSizeNoWarn(CurPtr + Size, NextSize, getLangOpts()); - if (isIdentifierBody(Next)) { + if (isAsciiIdentifierContinue(Next)) { if (!isLexingRawMode()) Diag(CurPtr, getLangOpts().CPlusPlus ? diag::warn_cxx11_compat_digit_separator @@ -1841,7 +1928,7 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr, char C = getCharAndSize(CurPtr, Size); bool Consumed = false; - if (!isIdentifierHead(C)) { + if (!isAsciiIdentifierStart(C)) { if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) Consumed = true; else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) @@ -1880,7 +1967,7 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr, unsigned NextSize; char Next = getCharAndSizeNoWarn(CurPtr + Consumed, NextSize, getLangOpts()); - if (!isIdentifierBody(Next)) { + if (!isAsciiIdentifierContinue(Next)) { // End of suffix. Check whether this is on the allowed list. const StringRef CompleteSuffix(Buffer, Chars); IsUDSuffix = StringLiteralParser::isValidUDSuffix(getLangOpts(), @@ -1912,10 +1999,12 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr, Result.setFlag(Token::HasUDSuffix); while (true) { C = getCharAndSize(CurPtr, Size); - if (isIdentifierBody(C)) { CurPtr = ConsumeChar(CurPtr, Size, Result); } - else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) {} - else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) {} - else break; + if (isAsciiIdentifierContinue(C)) { + CurPtr = ConsumeChar(CurPtr, Size, Result); + } else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) { + } else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) { + } else + break; } return CurPtr; @@ -2811,11 +2900,11 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { ConditionalStack.pop_back(); } + SourceLocation EndLoc = getSourceLocation(BufferEnd); // C99 5.1.1.2p2: If the file is non-empty and didn't end in a newline, issue // a pedwarn. if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r')) { DiagnosticsEngine &Diags = PP->getDiagnostics(); - SourceLocation EndLoc = getSourceLocation(BufferEnd); unsigned DiagID; if (LangOpts.CPlusPlus11) { @@ -2838,7 +2927,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { BufferPtr = CurPtr; // Finally, let the preprocessor handle this. - return PP->HandleEndOfFile(Result, isPragmaLexer()); + return PP->HandleEndOfFile(Result, EndLoc, isPragmaLexer()); } /// isNextPPTokenLParen - Return 1 if the next unexpanded token lexed from @@ -3027,6 +3116,10 @@ uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc, Token *Result) { unsigned CharSize; char Kind = getCharAndSize(StartPtr, CharSize); + bool Delimited = false; + bool FoundEndDelimiter = false; + unsigned Count = 0; + bool Diagnose = Result && !isLexingRawMode(); unsigned NumHexDigits; if (Kind == 'u') @@ -3037,7 +3130,7 @@ uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc, return 0; if (!LangOpts.CPlusPlus && !LangOpts.C99) { - if (Result && !isLexingRawMode()) + if (Diagnose) Diag(SlashLoc, diag::warn_ucn_not_valid_in_c89); return 0; } @@ -3046,39 +3139,70 @@ uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc, const char *KindLoc = &CurPtr[-1]; uint32_t CodePoint = 0; - for (unsigned i = 0; i < NumHexDigits; ++i) { + while (Count != NumHexDigits || Delimited) { char C = getCharAndSize(CurPtr, CharSize); + if (!Delimited && C == '{') { + Delimited = true; + CurPtr += CharSize; + continue; + } + + if (Delimited && C == '}') { + CurPtr += CharSize; + FoundEndDelimiter = true; + break; + } unsigned Value = llvm::hexDigitValue(C); if (Value == -1U) { - if (Result && !isLexingRawMode()) { - if (i == 0) { - Diag(BufferPtr, diag::warn_ucn_escape_no_digits) - << StringRef(KindLoc, 1); - } else { - Diag(BufferPtr, diag::warn_ucn_escape_incomplete); - - // If the user wrote \U1234, suggest a fixit to \u. - if (i == 4 && NumHexDigits == 8) { - CharSourceRange URange = makeCharRange(*this, KindLoc, KindLoc + 1); - Diag(KindLoc, diag::note_ucn_four_not_eight) - << FixItHint::CreateReplacement(URange, "u"); - } - } - } + if (!Delimited) + break; + if (Diagnose) + Diag(BufferPtr, diag::warn_delimited_ucn_incomplete) + << StringRef(&C, 1); + return 0; + } + if (CodePoint & 0xF000'0000) { + if (Diagnose) + Diag(KindLoc, diag::err_escape_too_large) << 0; return 0; } CodePoint <<= 4; - CodePoint += Value; - + CodePoint |= Value; CurPtr += CharSize; + Count++; + } + + if (Count == 0) { + if (Diagnose) + Diag(StartPtr, FoundEndDelimiter ? diag::warn_delimited_ucn_empty + : diag::warn_ucn_escape_no_digits) + << StringRef(KindLoc, 1); + return 0; + } + + if (!Delimited && Count != NumHexDigits) { + if (Diagnose) { + Diag(BufferPtr, diag::warn_ucn_escape_incomplete); + // If the user wrote \U1234, suggest a fixit to \u. + if (Count == 4 && NumHexDigits == 8) { + CharSourceRange URange = makeCharRange(*this, KindLoc, KindLoc + 1); + Diag(KindLoc, diag::note_ucn_four_not_eight) + << FixItHint::CreateReplacement(URange, "u"); + } + } + return 0; + } + + if (Delimited && PP) { + Diag(BufferPtr, diag::ext_delimited_escape_sequence); } if (Result) { Result->setFlag(Token::HasUCN); - if (CurPtr - StartPtr == (ptrdiff_t)NumHexDigits + 2) + if (CurPtr - StartPtr == (ptrdiff_t)(Count + 2 + (Delimited ? 2 : 0))) StartPtr = CurPtr; else while (StartPtr != CurPtr) @@ -3136,10 +3260,8 @@ uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc, bool Lexer::CheckUnicodeWhitespace(Token &Result, uint32_t C, const char *CurPtr) { - static const llvm::sys::UnicodeCharSet UnicodeWhitespaceChars( - UnicodeWhitespaceCharRanges); if (!isLexingRawMode() && !PP->isPreprocessedOutput() && - UnicodeWhitespaceChars.contains(C)) { + isUnicodeWhitespace(C)) { Diag(BufferPtr, diag::ext_unicode_whitespace) << makeCharRange(*this, BufferPtr, CurPtr); @@ -3149,47 +3271,6 @@ bool Lexer::CheckUnicodeWhitespace(Token &Result, uint32_t C, return false; } -bool Lexer::LexUnicode(Token &Result, uint32_t C, const char *CurPtr) { - if (isAllowedIDChar(C, LangOpts) && isAllowedInitiallyIDChar(C, LangOpts)) { - if (!isLexingRawMode() && !ParsingPreprocessorDirective && - !PP->isPreprocessedOutput()) { - maybeDiagnoseIDCharCompat(PP->getDiagnostics(), C, - makeCharRange(*this, BufferPtr, CurPtr), - /*IsFirst=*/true); - maybeDiagnoseUTF8Homoglyph(PP->getDiagnostics(), C, - makeCharRange(*this, BufferPtr, CurPtr)); - } - - MIOpt.ReadToken(); - return LexIdentifier(Result, CurPtr); - } - - if (!isLexingRawMode() && !ParsingPreprocessorDirective && - !PP->isPreprocessedOutput() && - !isASCII(*BufferPtr) && !isAllowedIDChar(C, LangOpts)) { - // Non-ASCII characters tend to creep into source code unintentionally. - // Instead of letting the parser complain about the unknown token, - // just drop the character. - // Note that we can /only/ do this when the non-ASCII character is actually - // spelled as Unicode, not written as a UCN. The standard requires that - // we not throw away any possible preprocessor tokens, but there's a - // loophole in the mapping of Unicode characters to basic character set - // characters that allows us to map these particular characters to, say, - // whitespace. - Diag(BufferPtr, diag::err_non_ascii) - << FixItHint::CreateRemoval(makeCharRange(*this, BufferPtr, CurPtr)); - - BufferPtr = CurPtr; - return false; - } - - // Otherwise, we have an explicit UCN or a character that's unlikely to show - // up by accident. - MIOpt.ReadToken(); - FormTokenWithChars(Result, CurPtr, tok::unknown); - return true; -} - void Lexer::PropagateLineStartLeadingSpaceInfo(Token &Result) { IsAtStartOfLine = Result.isAtStartOfLine(); HasLeadingSpace = Result.hasLeadingSpace(); @@ -3433,7 +3514,7 @@ LexNextToken: } // treat u like the start of an identifier. - return LexIdentifier(Result, CurPtr); + return LexIdentifierContinue(Result, CurPtr); case 'U': // Identifier (Uber) or C11/C++11 UTF-32 string literal // Notify MIOpt that we read a non-whitespace/non-comment token. @@ -3462,7 +3543,7 @@ LexNextToken: } // treat U like the start of an identifier. - return LexIdentifier(Result, CurPtr); + return LexIdentifierContinue(Result, CurPtr); case 'R': // Identifier or C++0x raw string literal // Notify MIOpt that we read a non-whitespace/non-comment token. @@ -3478,7 +3559,7 @@ LexNextToken: } // treat R like the start of an identifier. - return LexIdentifier(Result, CurPtr); + return LexIdentifierContinue(Result, CurPtr); case 'L': // Identifier (Loony) or wide literal (L'x' or L"xyz"). // Notify MIOpt that we read a non-whitespace/non-comment token. @@ -3517,7 +3598,7 @@ LexNextToken: case '_': // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); - return LexIdentifier(Result, CurPtr); + return LexIdentifierContinue(Result, CurPtr); case '$': // $ in identifiers. if (LangOpts.DollarIdents) { @@ -3525,7 +3606,7 @@ LexNextToken: Diag(CurPtr-1, diag::ext_dollar_in_identifier); // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); - return LexIdentifier(Result, CurPtr); + return LexIdentifierContinue(Result, CurPtr); } Kind = tok::unknown; @@ -3940,7 +4021,7 @@ LexNextToken: goto LexNextToken; } - return LexUnicode(Result, CodePoint, CurPtr); + return LexUnicodeIdentifierStart(Result, CodePoint, CurPtr); } } @@ -3972,7 +4053,7 @@ LexNextToken: // (We manually eliminate the tail call to avoid recursion.) goto LexNextToken; } - return LexUnicode(Result, CodePoint, CurPtr); + return LexUnicodeIdentifierStart(Result, CodePoint, CurPtr); } if (isLexingRawMode() || ParsingPreprocessorDirective || |
