#include "clang/Lex/Lexer.h"
#include "UnicodeCharSets.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/MemoryBuffer.h"
#include <cstring>
using namespace clang;
bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const {
if (IdentifierInfo *II = getIdentifierInfo())
return II->getObjCKeywordID() == objcKey;
return false;
}
tok::ObjCKeywordKind Token::getObjCKeywordID() const {
IdentifierInfo *specId = getIdentifierInfo();
return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword;
}
void Lexer::anchor() { }
void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
const char *BufEnd) {
BufferStart = BufStart;
BufferPtr = BufPtr;
BufferEnd = BufEnd;
assert(BufEnd[0] == 0 &&
"We assume that the input buffer has a null character at the end"
" to simplify lexing!");
if (BufferStart == BufferPtr) {
StringRef Buf(BufferStart, BufferEnd - BufferStart);
size_t BOMLength = llvm::StringSwitch<size_t>(Buf)
.StartsWith("\xEF\xBB\xBF", 3) .Default(0);
BufferPtr += BOMLength;
}
Is_PragmaLexer = false;
CurrentConflictMarkerState = CMK_None;
IsAtStartOfLine = true;
IsAtPhysicalStartOfLine = true;
HasLeadingSpace = false;
HasLeadingEmptyMacro = false;
ParsingPreprocessorDirective = false;
ParsingFilename = false;
LexingRawMode = false;
ExtendedTokenMode = 0;
}
Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP)
: PreprocessorLexer(&PP, FID),
FileLoc(PP.getSourceManager().getLocForStartOfFile(FID)),
LangOpts(PP.getLangOpts()) {
InitLexer(InputFile->getBufferStart(), InputFile->getBufferStart(),
InputFile->getBufferEnd());
resetExtendedTokenMode();
}
void Lexer::resetExtendedTokenMode() {
assert(PP && "Cannot reset token mode without a preprocessor");
if (LangOpts.TraditionalCPP)
SetKeepWhitespaceMode(true);
else
SetCommentRetentionState(PP->getCommentRetentionState());
}
Lexer::Lexer(SourceLocation fileloc, const LangOptions &langOpts,
const char *BufStart, const char *BufPtr, const char *BufEnd)
: FileLoc(fileloc), LangOpts(langOpts) {
InitLexer(BufStart, BufPtr, BufEnd);
LexingRawMode = true;
}
Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *FromFile,
const SourceManager &SM, const LangOptions &langOpts)
: FileLoc(SM.getLocForStartOfFile(FID)), LangOpts(langOpts) {
InitLexer(FromFile->getBufferStart(), FromFile->getBufferStart(),
FromFile->getBufferEnd());
LexingRawMode = true;
}
Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc,
SourceLocation ExpansionLocStart,
SourceLocation ExpansionLocEnd,
unsigned TokLen, Preprocessor &PP) {
SourceManager &SM = PP.getSourceManager();
FileID SpellingFID = SM.getFileID(SpellingLoc);
const llvm::MemoryBuffer *InputFile = SM.getBuffer(SpellingFID);
Lexer *L = new Lexer(SpellingFID, InputFile, PP);
const char *StrData = SM.getCharacterData(SpellingLoc);
L->BufferPtr = StrData;
L->BufferEnd = StrData+TokLen;
assert(L->BufferEnd[0] == 0 && "Buffer is not nul terminated!");
L->FileLoc = SM.createExpansionLoc(SM.getLocForStartOfFile(SpellingFID),
ExpansionLocStart,
ExpansionLocEnd, TokLen);
L->ParsingPreprocessorDirective = true;
L->Is_PragmaLexer = true;
return L;
}
std::string Lexer::Stringify(const std::string &Str, bool Charify) {
std::string Result = Str;
char Quote = Charify ? '\'' : '"';
for (unsigned i = 0, e = Result.size(); i != e; ++i) {
if (Result[i] == '\\' || Result[i] == Quote) {
Result.insert(Result.begin()+i, '\\');
++i; ++e;
}
}
return Result;
}
void Lexer::Stringify(SmallVectorImpl<char> &Str) {
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
if (Str[i] == '\\' || Str[i] == '"') {
Str.insert(Str.begin()+i, '\\');
++i; ++e;
}
}
}
static size_t getSpellingSlow(const Token &Tok, const char *BufPtr,
const LangOptions &LangOpts, char *Spelling) {
assert(Tok.needsCleaning() && "getSpellingSlow called on simple token");
size_t Length = 0;
const char *BufEnd = BufPtr + Tok.getLength();
if (Tok.is(tok::string_literal)) {
while (BufPtr < BufEnd) {
unsigned Size;
Spelling[Length++] = Lexer::getCharAndSizeNoWarn(BufPtr, Size, LangOpts);
BufPtr += Size;
if (Spelling[Length - 1] == '"')
break;
}
if (Length >= 2 &&
Spelling[Length - 2] == 'R' && Spelling[Length - 1] == '"') {
const char *RawEnd = BufEnd;
do --RawEnd; while (*RawEnd != '"');
size_t RawLength = RawEnd - BufPtr + 1;
memcpy(Spelling + Length, BufPtr, RawLength);
Length += RawLength;
BufPtr += RawLength;
}
}
while (BufPtr < BufEnd) {
unsigned Size;
Spelling[Length++] = Lexer::getCharAndSizeNoWarn(BufPtr, Size, LangOpts);
BufPtr += Size;
}
assert(Length < Tok.getLength() &&
"NeedsCleaning flag set on token that didn't need cleaning!");
return Length;
}
StringRef Lexer::getSpelling(SourceLocation loc,
SmallVectorImpl<char> &buffer,
const SourceManager &SM,
const LangOptions &options,
bool *invalid) {
std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
bool invalidTemp = false;
StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
if (invalidTemp) {
if (invalid) *invalid = true;
return StringRef();
}
const char *tokenBegin = file.data() + locInfo.second;
Lexer lexer(SM.getLocForStartOfFile(locInfo.first), options,
file.begin(), tokenBegin, file.end());
Token token;
lexer.LexFromRawLexer(token);
unsigned length = token.getLength();
if (!token.needsCleaning())
return StringRef(tokenBegin, length);
buffer.resize(length);
buffer.resize(getSpellingSlow(token, tokenBegin, options, buffer.data()));
return StringRef(buffer.data(), buffer.size());
}
std::string Lexer::getSpelling(const Token &Tok, const SourceManager &SourceMgr,
const LangOptions &LangOpts, bool *Invalid) {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
bool CharDataInvalid = false;
const char *TokStart = SourceMgr.getCharacterData(Tok.getLocation(),
&CharDataInvalid);
if (Invalid)
*Invalid = CharDataInvalid;
if (CharDataInvalid)
return std::string();
if (!Tok.needsCleaning())
return std::string(TokStart, TokStart + Tok.getLength());
std::string Result;
Result.resize(Tok.getLength());
Result.resize(getSpellingSlow(Tok, TokStart, LangOpts, &*Result.begin()));
return Result;
}
unsigned Lexer::getSpelling(const Token &Tok, const char *&Buffer,
const SourceManager &SourceMgr,
const LangOptions &LangOpts, bool *Invalid) {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
const char *TokStart = 0;
if (Tok.is(tok::raw_identifier))
TokStart = Tok.getRawIdentifierData();
else if (!Tok.hasUCN()) {
if (const IdentifierInfo *II = Tok.getIdentifierInfo()) {
Buffer = II->getNameStart();
return II->getLength();
}
}
if (Tok.isLiteral())
TokStart = Tok.getLiteralData();
if (TokStart == 0) {
bool CharDataInvalid = false;
TokStart = SourceMgr.getCharacterData(Tok.getLocation(), &CharDataInvalid);
if (Invalid)
*Invalid = CharDataInvalid;
if (CharDataInvalid) {
Buffer = "";
return 0;
}
}
if (!Tok.needsCleaning()) {
Buffer = TokStart;
return Tok.getLength();
}
return getSpellingSlow(Tok, TokStart, LangOpts, const_cast<char*>(Buffer));
}
unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts) {
Token TheTok;
if (getRawToken(Loc, TheTok, SM, LangOpts))
return 0;
return TheTok.getLength();
}
bool Lexer::getRawToken(SourceLocation Loc, Token &Result,
const SourceManager &SM,
const LangOptions &LangOpts,
bool IgnoreWhiteSpace) {
Loc = SM.getExpansionLoc(Loc);
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
bool Invalid = false;
StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
if (Invalid)
return true;
const char *StrData = Buffer.data()+LocInfo.second;
if (!IgnoreWhiteSpace && isWhitespace(StrData[0]))
return true;
Lexer TheLexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts,
Buffer.begin(), StrData, Buffer.end());
TheLexer.SetCommentRetentionState(true);
TheLexer.LexFromRawLexer(Result);
return false;
}
static SourceLocation getBeginningOfFileToken(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts) {
assert(Loc.isFileID());
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
if (LocInfo.first.isInvalid())
return Loc;
bool Invalid = false;
StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
if (Invalid)
return Loc;
const char *BufStart = Buffer.data();
if (LocInfo.second >= Buffer.size())
return Loc;
const char *StrData = BufStart+LocInfo.second;
if (StrData[0] == '\n' || StrData[0] == '\r')
return Loc;
const char *LexStart = StrData;
while (LexStart != BufStart) {
if (LexStart[0] == '\n' || LexStart[0] == '\r') {
++LexStart;
break;
}
--LexStart;
}
SourceLocation LexerStartLoc = Loc.getLocWithOffset(-LocInfo.second);
Lexer TheLexer(LexerStartLoc, LangOpts, BufStart, LexStart, Buffer.end());
TheLexer.SetCommentRetentionState(true);
Token TheTok;
do {
TheLexer.LexFromRawLexer(TheTok);
if (TheLexer.getBufferLocation() > StrData) {
if (TheLexer.getBufferLocation() - TheTok.getLength() <= StrData)
return TheTok.getLocation();
break;
}
} while (TheTok.getKind() != tok::eof);
return Loc;
}
SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts) {
if (Loc.isFileID())
return getBeginningOfFileToken(Loc, SM, LangOpts);
if (!SM.isMacroArgExpansion(Loc))
return Loc;
SourceLocation FileLoc = SM.getSpellingLoc(Loc);
SourceLocation BeginFileLoc = getBeginningOfFileToken(FileLoc, SM, LangOpts);
std::pair<FileID, unsigned> FileLocInfo = SM.getDecomposedLoc(FileLoc);
std::pair<FileID, unsigned> BeginFileLocInfo
= SM.getDecomposedLoc(BeginFileLoc);
assert(FileLocInfo.first == BeginFileLocInfo.first &&
FileLocInfo.second >= BeginFileLocInfo.second);
return Loc.getLocWithOffset(BeginFileLocInfo.second - FileLocInfo.second);
}
namespace {
enum PreambleDirectiveKind {
PDK_Skipped,
PDK_StartIf,
PDK_EndIf,
PDK_Unknown
};
}
std::pair<unsigned, bool>
Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer,
const LangOptions &LangOpts, unsigned MaxLines) {
const unsigned StartOffset = 1;
SourceLocation FileLoc = SourceLocation::getFromRawEncoding(StartOffset);
Lexer TheLexer(FileLoc, LangOpts, Buffer->getBufferStart(),
Buffer->getBufferStart(), Buffer->getBufferEnd());
TheLexer.SetCommentRetentionState(true);
SourceLocation StartLoc = TheLexer.getSourceLocation();
bool InPreprocessorDirective = false;
Token TheTok;
Token IfStartTok;
unsigned IfCount = 0;
SourceLocation ActiveCommentLoc;
unsigned MaxLineOffset = 0;
if (MaxLines) {
const char *CurPtr = Buffer->getBufferStart();
unsigned CurLine = 0;
while (CurPtr != Buffer->getBufferEnd()) {
char ch = *CurPtr++;
if (ch == '\n') {
++CurLine;
if (CurLine == MaxLines)
break;
}
}
if (CurPtr != Buffer->getBufferEnd())
MaxLineOffset = CurPtr - Buffer->getBufferStart();
}
do {
TheLexer.LexFromRawLexer(TheTok);
if (InPreprocessorDirective) {
if (TheTok.getKind() == tok::eof) {
break;
}
if (!TheTok.isAtStartOfLine())
continue;
InPreprocessorDirective = false;
}
if (TheTok.isAtStartOfLine()) {
unsigned TokOffset = TheTok.getLocation().getRawEncoding() - StartOffset;
if (MaxLineOffset && TokOffset >= MaxLineOffset)
break;
}
if (TheTok.getKind() == tok::comment) {
if (ActiveCommentLoc.isInvalid())
ActiveCommentLoc = TheTok.getLocation();
continue;
}
if (TheTok.isAtStartOfLine() && TheTok.getKind() == tok::hash) {
Token HashTok = TheTok;
InPreprocessorDirective = true;
ActiveCommentLoc = SourceLocation();
TheLexer.LexFromRawLexer(TheTok);
if (TheTok.getKind() == tok::raw_identifier && !TheTok.needsCleaning()) {
StringRef Keyword(TheTok.getRawIdentifierData(),
TheTok.getLength());
PreambleDirectiveKind PDK
= llvm::StringSwitch<PreambleDirectiveKind>(Keyword)
.Case("include", PDK_Skipped)
.Case("__include_macros", PDK_Skipped)
.Case("define", PDK_Skipped)
.Case("undef", PDK_Skipped)
.Case("line", PDK_Skipped)
.Case("error", PDK_Skipped)
.Case("pragma", PDK_Skipped)
.Case("import", PDK_Skipped)
.Case("include_next", PDK_Skipped)
.Case("warning", PDK_Skipped)
.Case("ident", PDK_Skipped)
.Case("sccs", PDK_Skipped)
.Case("assert", PDK_Skipped)
.Case("unassert", PDK_Skipped)
.Case("if", PDK_StartIf)
.Case("ifdef", PDK_StartIf)
.Case("ifndef", PDK_StartIf)
.Case("elif", PDK_Skipped)
.Case("else", PDK_Skipped)
.Case("endif", PDK_EndIf)
.Default(PDK_Unknown);
switch (PDK) {
case PDK_Skipped:
continue;
case PDK_StartIf:
if (IfCount == 0)
IfStartTok = HashTok;
++IfCount;
continue;
case PDK_EndIf:
if (IfCount == 0)
break;
--IfCount;
continue;
case PDK_Unknown:
break;
}
}
InPreprocessorDirective = false;
TheTok = HashTok;
}
break;
} while (true);
SourceLocation End;
if (IfCount)
End = IfStartTok.getLocation();
else if (ActiveCommentLoc.isValid())
End = ActiveCommentLoc; else
End = TheTok.getLocation();
return std::make_pair(End.getRawEncoding() - StartLoc.getRawEncoding(),
IfCount? IfStartTok.isAtStartOfLine()
: TheTok.isAtStartOfLine());
}
SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart,
unsigned CharNo,
const SourceManager &SM,
const LangOptions &LangOpts) {
bool Invalid = false;
const char *TokPtr = SM.getCharacterData(TokStart, &Invalid);
if (Invalid || (CharNo == 0 && Lexer::isObviouslySimpleCharacter(*TokPtr)))
return TokStart;
unsigned PhysOffset = 0;
while (Lexer::isObviouslySimpleCharacter(*TokPtr)) {
if (CharNo == 0)
return TokStart.getLocWithOffset(PhysOffset);
++TokPtr, --CharNo, ++PhysOffset;
}
for (; CharNo; --CharNo) {
unsigned Size;
Lexer::getCharAndSizeNoWarn(TokPtr, Size, LangOpts);
TokPtr += Size;
PhysOffset += Size;
}
if (!Lexer::isObviouslySimpleCharacter(*TokPtr))
PhysOffset += Lexer::SkipEscapedNewLines(TokPtr)-TokPtr;
return TokStart.getLocWithOffset(PhysOffset);
}
SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset,
const SourceManager &SM,
const LangOptions &LangOpts) {
if (Loc.isInvalid())
return SourceLocation();
if (Loc.isMacroID()) {
if (Offset > 0 || !isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
return SourceLocation(); }
unsigned Len = Lexer::MeasureTokenLength(Loc, SM, LangOpts);
if (Len > Offset)
Len = Len - Offset;
else
return Loc;
return Loc.getLocWithOffset(Len);
}
bool Lexer::isAtStartOfMacroExpansion(SourceLocation loc,
const SourceManager &SM,
const LangOptions &LangOpts,
SourceLocation *MacroBegin) {
assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
SourceLocation expansionLoc;
if (!SM.isAtStartOfImmediateMacroExpansion(loc, &expansionLoc))
return false;
if (expansionLoc.isFileID()) {
if (MacroBegin)
*MacroBegin = expansionLoc;
return true;
}
return isAtStartOfMacroExpansion(expansionLoc, SM, LangOpts, MacroBegin);
}
bool Lexer::isAtEndOfMacroExpansion(SourceLocation loc,
const SourceManager &SM,
const LangOptions &LangOpts,
SourceLocation *MacroEnd) {
assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
SourceLocation spellLoc = SM.getSpellingLoc(loc);
unsigned tokLen = MeasureTokenLength(spellLoc, SM, LangOpts);
if (tokLen == 0)
return false;
SourceLocation afterLoc = loc.getLocWithOffset(tokLen);
SourceLocation expansionLoc;
if (!SM.isAtEndOfImmediateMacroExpansion(afterLoc, &expansionLoc))
return false;
if (expansionLoc.isFileID()) {
if (MacroEnd)
*MacroEnd = expansionLoc;
return true;
}
return isAtEndOfMacroExpansion(expansionLoc, SM, LangOpts, MacroEnd);
}
static CharSourceRange makeRangeFromFileLocs(CharSourceRange Range,
const SourceManager &SM,
const LangOptions &LangOpts) {
SourceLocation Begin = Range.getBegin();
SourceLocation End = Range.getEnd();
assert(Begin.isFileID() && End.isFileID());
if (Range.isTokenRange()) {
End = Lexer::getLocForEndOfToken(End, 0, SM,LangOpts);
if (End.isInvalid())
return CharSourceRange();
}
FileID FID;
unsigned BeginOffs;
llvm::tie(FID, BeginOffs) = SM.getDecomposedLoc(Begin);
if (FID.isInvalid())
return CharSourceRange();
unsigned EndOffs;
if (!SM.isInFileID(End, FID, &EndOffs) ||
BeginOffs > EndOffs)
return CharSourceRange();
return CharSourceRange::getCharRange(Begin, End);
}
CharSourceRange Lexer::makeFileCharRange(CharSourceRange Range,
const SourceManager &SM,
const LangOptions &LangOpts) {
SourceLocation Begin = Range.getBegin();
SourceLocation End = Range.getEnd();
if (Begin.isInvalid() || End.isInvalid())
return CharSourceRange();
if (Begin.isFileID() && End.isFileID())
return makeRangeFromFileLocs(Range, SM, LangOpts);
if (Begin.isMacroID() && End.isFileID()) {
if (!isAtStartOfMacroExpansion(Begin, SM, LangOpts, &Begin))
return CharSourceRange();
Range.setBegin(Begin);
return makeRangeFromFileLocs(Range, SM, LangOpts);
}
if (Begin.isFileID() && End.isMacroID()) {
if ((Range.isTokenRange() && !isAtEndOfMacroExpansion(End, SM, LangOpts,
&End)) ||
(Range.isCharRange() && !isAtStartOfMacroExpansion(End, SM, LangOpts,
&End)))
return CharSourceRange();
Range.setEnd(End);
return makeRangeFromFileLocs(Range, SM, LangOpts);
}
assert(Begin.isMacroID() && End.isMacroID());
SourceLocation MacroBegin, MacroEnd;
if (isAtStartOfMacroExpansion(Begin, SM, LangOpts, &MacroBegin) &&
((Range.isTokenRange() && isAtEndOfMacroExpansion(End, SM, LangOpts,
&MacroEnd)) ||
(Range.isCharRange() && isAtStartOfMacroExpansion(End, SM, LangOpts,
&MacroEnd)))) {
Range.setBegin(MacroBegin);
Range.setEnd(MacroEnd);
return makeRangeFromFileLocs(Range, SM, LangOpts);
}
bool Invalid = false;
const SrcMgr::SLocEntry &BeginEntry = SM.getSLocEntry(SM.getFileID(Begin),
&Invalid);
if (Invalid)
return CharSourceRange();
if (BeginEntry.getExpansion().isMacroArgExpansion()) {
const SrcMgr::SLocEntry &EndEntry = SM.getSLocEntry(SM.getFileID(End),
&Invalid);
if (Invalid)
return CharSourceRange();
if (EndEntry.getExpansion().isMacroArgExpansion() &&
BeginEntry.getExpansion().getExpansionLocStart() ==
EndEntry.getExpansion().getExpansionLocStart()) {
Range.setBegin(SM.getImmediateSpellingLoc(Begin));
Range.setEnd(SM.getImmediateSpellingLoc(End));
return makeFileCharRange(Range, SM, LangOpts);
}
}
return CharSourceRange();
}
StringRef Lexer::getSourceText(CharSourceRange Range,
const SourceManager &SM,
const LangOptions &LangOpts,
bool *Invalid) {
Range = makeFileCharRange(Range, SM, LangOpts);
if (Range.isInvalid()) {
if (Invalid) *Invalid = true;
return StringRef();
}
std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(Range.getBegin());
if (beginInfo.first.isInvalid()) {
if (Invalid) *Invalid = true;
return StringRef();
}
unsigned EndOffs;
if (!SM.isInFileID(Range.getEnd(), beginInfo.first, &EndOffs) ||
beginInfo.second > EndOffs) {
if (Invalid) *Invalid = true;
return StringRef();
}
bool invalidTemp = false;
StringRef file = SM.getBufferData(beginInfo.first, &invalidTemp);
if (invalidTemp) {
if (Invalid) *Invalid = true;
return StringRef();
}
if (Invalid) *Invalid = false;
return file.substr(beginInfo.second, EndOffs - beginInfo.second);
}
StringRef Lexer::getImmediateMacroName(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts) {
assert(Loc.isMacroID() && "Only reasonble to call this on macros");
while (1) {
FileID FID = SM.getFileID(Loc);
const SrcMgr::SLocEntry *E = &SM.getSLocEntry(FID);
const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
Loc = Expansion.getExpansionLocStart();
if (!Expansion.isMacroArgExpansion())
break;
Loc = SM.getImmediateExpansionRange(Loc).first;
SourceLocation SpellLoc = Expansion.getSpellingLoc();
if (SpellLoc.isFileID())
break;
FileID MacroFID = SM.getFileID(Loc);
if (SM.isInFileID(SpellLoc, MacroFID))
break;
Loc = SpellLoc;
}
Loc = SM.getSpellingLoc(Loc);
std::pair<FileID, unsigned> ExpansionInfo = SM.getDecomposedLoc(Loc);
unsigned MacroTokenLength = Lexer::MeasureTokenLength(Loc, SM, LangOpts);
StringRef ExpansionBuffer = SM.getBufferData(ExpansionInfo.first);
return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength);
}
bool Lexer::isIdentifierBodyChar(char c, const LangOptions &LangOpts) {
return isIdentifierBody(c, LangOpts.DollarIdents);
}
static LLVM_ATTRIBUTE_NOINLINE SourceLocation GetMappedTokenLoc(
Preprocessor &PP, SourceLocation FileLoc, unsigned CharNo, unsigned TokLen);
static SourceLocation GetMappedTokenLoc(Preprocessor &PP,
SourceLocation FileLoc,
unsigned CharNo, unsigned TokLen) {
assert(FileLoc.isMacroID() && "Must be a macro expansion");
SourceManager &SM = PP.getSourceManager();
SourceLocation SpellingLoc = SM.getSpellingLoc(FileLoc);
SpellingLoc = SpellingLoc.getLocWithOffset(CharNo);
std::pair<SourceLocation,SourceLocation> II =
SM.getImmediateExpansionRange(FileLoc);
return SM.createExpansionLoc(SpellingLoc, II.first, II.second, TokLen);
}
SourceLocation Lexer::getSourceLocation(const char *Loc,
unsigned TokLen) const {
assert(Loc >= BufferStart && Loc <= BufferEnd &&
"Location out of range for this buffer!");
unsigned CharNo = Loc-BufferStart;
if (FileLoc.isFileID())
return FileLoc.getLocWithOffset(CharNo);
assert(PP && "This doesn't work on raw lexers");
return GetMappedTokenLoc(*PP, FileLoc, CharNo, TokLen);
}
DiagnosticBuilder Lexer::Diag(const char *Loc, unsigned DiagID) const {
return PP->Diag(getSourceLocation(Loc), DiagID);
}
static char GetTrigraphCharForLetter(char Letter) {
switch (Letter) {
default: return 0;
case '=': return '#';
case ')': return ']';
case '(': return '[';
case '!': return '|';
case '\'': return '^';
case '>': return '}';
case '/': return '\\';
case '<': return '{';
case '-': return '~';
}
}
static char DecodeTrigraphChar(const char *CP, Lexer *L) {
char Res = GetTrigraphCharForLetter(*CP);
if (!Res || !L) return Res;
if (!L->getLangOpts().Trigraphs) {
if (!L->isLexingRawMode())
L->Diag(CP-2, diag::trigraph_ignored);
return 0;
}
if (!L->isLexingRawMode())
L->Diag(CP-2, diag::trigraph_converted) << StringRef(&Res, 1);
return Res;
}
unsigned Lexer::getEscapedNewLineSize(const char *Ptr) {
unsigned Size = 0;
while (isWhitespace(Ptr[Size])) {
++Size;
if (Ptr[Size-1] != '\n' && Ptr[Size-1] != '\r')
continue;
if ((Ptr[Size] == '\r' || Ptr[Size] == '\n') &&
Ptr[Size-1] != Ptr[Size])
++Size;
return Size;
}
return 0;
}
const char *Lexer::SkipEscapedNewLines(const char *P) {
while (1) {
const char *AfterEscape;
if (*P == '\\') {
AfterEscape = P+1;
} else if (*P == '?') {
if (P[1] != '?' || P[2] != '/')
return P;
AfterEscape = P+3;
} else {
return P;
}
unsigned NewLineSize = Lexer::getEscapedNewLineSize(AfterEscape);
if (NewLineSize == 0) return P;
P = AfterEscape+NewLineSize;
}
}
SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc,
tok::TokenKind TKind,
const SourceManager &SM,
const LangOptions &LangOpts,
bool SkipTrailingWhitespaceAndNewLine) {
if (Loc.isMacroID()) {
if (!Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
return SourceLocation();
}
Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts);
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
bool InvalidTemp = false;
StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
if (InvalidTemp)
return SourceLocation();
const char *TokenBegin = File.data() + LocInfo.second;
Lexer lexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
TokenBegin, File.end());
Token Tok;
lexer.LexFromRawLexer(Tok);
if (Tok.isNot(TKind))
return SourceLocation();
SourceLocation TokenLoc = Tok.getLocation();
unsigned NumWhitespaceChars = 0;
if (SkipTrailingWhitespaceAndNewLine) {
const char *TokenEnd = SM.getCharacterData(TokenLoc) +
Tok.getLength();
unsigned char C = *TokenEnd;
while (isHorizontalWhitespace(C)) {
C = *(++TokenEnd);
NumWhitespaceChars++;
}
if (C == '\n' || C == '\r') {
char PrevC = C;
C = *(++TokenEnd);
NumWhitespaceChars++;
if ((C == '\n' || C == '\r') && C != PrevC)
NumWhitespaceChars++;
}
}
return TokenLoc.getLocWithOffset(Tok.getLength() + NumWhitespaceChars);
}
char Lexer::getCharAndSizeSlow(const char *Ptr, unsigned &Size,
Token *Tok) {
if (Ptr[0] == '\\') {
++Size;
++Ptr;
Slash:
if (!isWhitespace(Ptr[0])) return '\\';
if (unsigned EscapedNewLineSize = getEscapedNewLineSize(Ptr)) {
if (Tok) Tok->setFlag(Token::NeedsCleaning);
if (Ptr[0] != '\n' && Ptr[0] != '\r' && Tok && !isLexingRawMode())
Diag(Ptr, diag::backslash_newline_space);
Size += EscapedNewLineSize;
Ptr += EscapedNewLineSize;
if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
return ' ';
return getCharAndSizeSlow(Ptr, Size, Tok);
}
return '\\';
}
if (Ptr[0] == '?' && Ptr[1] == '?') {
if (char C = DecodeTrigraphChar(Ptr+2, Tok ? this : 0)) {
if (Tok) Tok->setFlag(Token::NeedsCleaning);
Ptr += 3;
Size += 3;
if (C == '\\') goto Slash;
return C;
}
}
++Size;
return *Ptr;
}
char Lexer::getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size,
const LangOptions &LangOpts) {
if (Ptr[0] == '\\') {
++Size;
++Ptr;
Slash:
if (!isWhitespace(Ptr[0])) return '\\';
if (unsigned EscapedNewLineSize = getEscapedNewLineSize(Ptr)) {
Size += EscapedNewLineSize;
Ptr += EscapedNewLineSize;
if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
return ' ';
return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts);
}
return '\\';
}
if (LangOpts.Trigraphs && Ptr[0] == '?' && Ptr[1] == '?') {
if (char C = GetTrigraphCharForLetter(Ptr[2])) {
Ptr += 3;
Size += 3;
if (C == '\\') goto Slash;
return C;
}
}
++Size;
return *Ptr;
}
void Lexer::SkipBytes(unsigned Bytes, bool StartOfLine) {
BufferPtr += Bytes;
if (BufferPtr > BufferEnd)
BufferPtr = BufferEnd;
IsAtStartOfLine = StartOfLine;
IsAtPhysicalStartOfLine = StartOfLine;
}
static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) {
if (LangOpts.CPlusPlus11 || 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);
return C99AllowedIDChars.contains(C);
}
}
static bool isAllowedInitiallyIDChar(uint32_t C, const LangOptions &LangOpts) {
assert(isAllowedIDChar(C, LangOpts));
if (LangOpts.CPlusPlus11 || 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 inline CharSourceRange makeCharRange(Lexer &L, const char *Begin,
const char *End) {
return CharSourceRange::getCharRange(L.getSourceLocation(Begin),
L.getSourceLocation(End));
}
static void maybeDiagnoseIDCharCompat(DiagnosticsEngine &Diags, uint32_t C,
CharSourceRange Range, bool IsFirst) {
if (Diags.getDiagnosticLevel(diag::warn_c99_compat_unicode_id,
Range.getBegin()) > DiagnosticsEngine::Ignored) {
enum {
CannotAppearInIdentifier = 0,
CannotStartIdentifier
};
static const llvm::sys::UnicodeCharSet C99AllowedIDChars(
C99AllowedIDCharRanges);
static const llvm::sys::UnicodeCharSet C99DisallowedInitialIDChars(
C99DisallowedInitialIDCharRanges);
if (!C99AllowedIDChars.contains(C)) {
Diags.Report(Range.getBegin(), diag::warn_c99_compat_unicode_id)
<< Range
<< CannotAppearInIdentifier;
} else if (IsFirst && C99DisallowedInitialIDChars.contains(C)) {
Diags.Report(Range.getBegin(), diag::warn_c99_compat_unicode_id)
<< Range
<< CannotStartIdentifier;
}
}
if (Diags.getDiagnosticLevel(diag::warn_cxx98_compat_unicode_id,
Range.getBegin()) > DiagnosticsEngine::Ignored) {
static const llvm::sys::UnicodeCharSet CXX03AllowedIDChars(
CXX03AllowedIDCharRanges);
if (!CXX03AllowedIDChars.contains(C)) {
Diags.Report(Range.getBegin(), diag::warn_cxx98_compat_unicode_id)
<< Range;
}
}
}
bool Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
unsigned Size;
unsigned char C = *CurPtr++;
while (isIdentifierBody(C))
C = *CurPtr++;
--CurPtr;
if (isASCII(C) && C != '\\' && C != '?' &&
(C != '$' || !LangOpts.DollarIdents)) {
FinishIdentifier:
const char *IdStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, tok::raw_identifier);
Result.setRawIdentifierData(IdStart);
if (LexingRawMode)
return true;
IdentifierInfo *II = PP->LookUpIdentifierInfo(Result);
if (II->isHandleIdentifierCase())
return PP->HandleIdentifier(Result);
return true;
}
C = getCharAndSize(CurPtr, Size);
while (1) {
if (C == '$') {
if (!LangOpts.DollarIdents) goto FinishIdentifier;
if (!isLexingRawMode())
Diag(CurPtr, diag::ext_dollar_in_identifier);
CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
continue;
} else if (C == '\\') {
const char *UCNPtr = CurPtr + Size;
uint32_t CodePoint = tryReadUCN(UCNPtr, CurPtr, 0);
if (CodePoint == 0 || !isAllowedIDChar(CodePoint, LangOpts))
goto FinishIdentifier;
if (!isLexingRawMode()) {
maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint,
makeCharRange(*this, CurPtr, UCNPtr),
false);
}
Result.setFlag(Token::HasUCN);
if ((UCNPtr - CurPtr == 6 && CurPtr[1] == 'u') ||
(UCNPtr - CurPtr == 10 && CurPtr[1] == 'U'))
CurPtr = UCNPtr;
else
while (CurPtr != UCNPtr)
(void)getAndAdvanceChar(CurPtr, Result);
C = getCharAndSize(CurPtr, Size);
continue;
} else if (!isASCII(C)) {
const char *UnicodePtr = CurPtr;
UTF32 CodePoint;
ConversionResult Result =
llvm::convertUTF8Sequence((const UTF8 **)&UnicodePtr,
(const UTF8 *)BufferEnd,
&CodePoint,
strictConversion);
if (Result != conversionOK ||
!isAllowedIDChar(static_cast<uint32_t>(CodePoint), LangOpts))
goto FinishIdentifier;
if (!isLexingRawMode()) {
maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint,
makeCharRange(*this, CurPtr, UnicodePtr),
false);
}
CurPtr = UnicodePtr;
C = getCharAndSize(CurPtr, Size);
continue;
} else if (!isIdentifierBody(C)) {
goto FinishIdentifier;
}
CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
while (isIdentifierBody(C)) {
CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
}
}
}
bool Lexer::isHexaLiteral(const char *Start, const LangOptions &LangOpts) {
unsigned Size;
char C1 = Lexer::getCharAndSizeNoWarn(Start, Size, LangOpts);
if (C1 != '0')
return false;
char C2 = Lexer::getCharAndSizeNoWarn(Start + Size, Size, LangOpts);
return (C2 == 'x' || C2 == 'X');
}
bool Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
unsigned Size;
char C = getCharAndSize(CurPtr, Size);
char PrevCh = 0;
while (isPreprocessingNumberBody(C)) { CurPtr = ConsumeChar(CurPtr, Size, Result);
PrevCh = C;
C = getCharAndSize(CurPtr, Size);
}
if ((C == '-' || C == '+') && (PrevCh == 'E' || PrevCh == 'e')) {
if (!LangOpts.MicrosoftExt || !isHexaLiteral(BufferPtr, LangOpts))
return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
}
if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p')) {
bool IsHexFloat = true;
if (!LangOpts.C99) {
if (!isHexaLiteral(BufferPtr, LangOpts))
IsHexFloat = false;
else if (std::find(BufferPtr, CurPtr, '_') != CurPtr)
IsHexFloat = false;
}
if (IsHexFloat)
return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
}
if (C == '\'' && getLangOpts().CPlusPlus1y) {
unsigned NextSize;
char Next = getCharAndSizeNoWarn(CurPtr + Size, NextSize, getLangOpts());
if (isIdentifierBody(Next)) {
if (!isLexingRawMode())
Diag(CurPtr, diag::warn_cxx11_compat_digit_separator);
CurPtr = ConsumeChar(CurPtr, Size, Result);
return LexNumericConstant(Result, CurPtr);
}
}
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, tok::numeric_constant);
Result.setLiteralData(TokStart);
return true;
}
const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr,
bool IsStringLiteral) {
assert(getLangOpts().CPlusPlus);
unsigned Size;
char C = getCharAndSize(CurPtr, Size);
if (isIdentifierHead(C)) {
if (!getLangOpts().CPlusPlus11) {
if (!isLexingRawMode())
Diag(CurPtr,
C == '_' ? diag::warn_cxx11_compat_user_defined_literal
: diag::warn_cxx11_compat_reserved_user_defined_literal)
<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " ");
return CurPtr;
}
bool IsUDSuffix = false;
if (C == '_')
IsUDSuffix = true;
else if (IsStringLiteral && getLangOpts().CPlusPlus1y) {
const unsigned MaxStandardSuffixLength = 3;
char Buffer[MaxStandardSuffixLength] = { C };
unsigned Consumed = Size;
unsigned Chars = 1;
while (true) {
unsigned NextSize;
char Next = getCharAndSizeNoWarn(CurPtr + Consumed, NextSize,
getLangOpts());
if (!isIdentifierBody(Next)) {
IsUDSuffix = (Chars == 1 && Buffer[0] == 's') ||
NumericLiteralParser::isValidUDSuffix(
getLangOpts(), StringRef(Buffer, Chars));
break;
}
if (Chars == MaxStandardSuffixLength)
break;
Buffer[Chars++] = Next;
Consumed += NextSize;
}
}
if (!IsUDSuffix) {
if (!isLexingRawMode())
Diag(CurPtr, getLangOpts().MSVCCompat
? diag::ext_ms_reserved_user_defined_literal
: diag::ext_reserved_user_defined_literal)
<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " ");
return CurPtr;
}
Result.setFlag(Token::HasUDSuffix);
do {
CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
} while (isIdentifierBody(C));
}
return CurPtr;
}
bool Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
tok::TokenKind Kind) {
const char *NulCharacter = 0;
if (!isLexingRawMode() &&
(Kind == tok::utf8_string_literal ||
Kind == tok::utf16_string_literal ||
Kind == tok::utf32_string_literal))
Diag(BufferPtr, getLangOpts().CPlusPlus
? diag::warn_cxx98_compat_unicode_literal
: diag::warn_c99_compat_unicode_literal);
char C = getAndAdvanceChar(CurPtr, Result);
while (C != '"') {
if (C == '\\')
C = getAndAdvanceChar(CurPtr, Result);
if (C == '\n' || C == '\r' || (C == 0 && CurPtr-1 == BufferEnd)) { if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::ext_unterminated_string);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return true;
}
if (C == 0) {
if (isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
cutOffLexing();
return true;
}
NulCharacter = CurPtr-1;
}
C = getAndAdvanceChar(CurPtr, Result);
}
if (getLangOpts().CPlusPlus)
CurPtr = LexUDSuffix(Result, CurPtr, true);
if (NulCharacter && !isLexingRawMode())
Diag(NulCharacter, diag::null_in_string);
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, Kind);
Result.setLiteralData(TokStart);
return true;
}
bool Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr,
tok::TokenKind Kind) {
if (!isLexingRawMode())
Diag(BufferPtr, diag::warn_cxx98_compat_raw_string_literal);
unsigned PrefixLen = 0;
while (PrefixLen != 16 && isRawStringDelimBody(CurPtr[PrefixLen]))
++PrefixLen;
if (CurPtr[PrefixLen] != '(') {
if (!isLexingRawMode()) {
const char *PrefixEnd = &CurPtr[PrefixLen];
if (PrefixLen == 16) {
Diag(PrefixEnd, diag::err_raw_delim_too_long);
} else {
Diag(PrefixEnd, diag::err_invalid_char_raw_delim)
<< StringRef(PrefixEnd, 1);
}
}
while (1) {
char C = *CurPtr++;
if (C == '"')
break;
if (C == 0 && CurPtr-1 == BufferEnd) {
--CurPtr;
break;
}
}
FormTokenWithChars(Result, CurPtr, tok::unknown);
return true;
}
const char *Prefix = CurPtr;
CurPtr += PrefixLen + 1;
while (1) {
char C = *CurPtr++;
if (C == ')') {
if (strncmp(CurPtr, Prefix, PrefixLen) == 0 && CurPtr[PrefixLen] == '"') {
CurPtr += PrefixLen + 1; break;
}
} else if (C == 0 && CurPtr-1 == BufferEnd) { if (!isLexingRawMode())
Diag(BufferPtr, diag::err_unterminated_raw_string)
<< StringRef(Prefix, PrefixLen);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return true;
}
}
if (getLangOpts().CPlusPlus)
CurPtr = LexUDSuffix(Result, CurPtr, true);
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, Kind);
Result.setLiteralData(TokStart);
return true;
}
bool Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
const char *NulCharacter = 0; const char *AfterLessPos = CurPtr;
char C = getAndAdvanceChar(CurPtr, Result);
while (C != '>') {
if (C == '\\') {
getAndAdvanceChar(CurPtr, Result);
} else if (C == '\n' || C == '\r' || (C == 0 && (CurPtr-1 == BufferEnd || isCodeCompletionPoint(CurPtr-1)))) {
FormTokenWithChars(Result, AfterLessPos, tok::less);
return true;
} else if (C == 0) {
NulCharacter = CurPtr-1;
}
C = getAndAdvanceChar(CurPtr, Result);
}
if (NulCharacter && !isLexingRawMode())
Diag(NulCharacter, diag::null_in_string);
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, tok::angle_string_literal);
Result.setLiteralData(TokStart);
return true;
}
bool Lexer::LexCharConstant(Token &Result, const char *CurPtr,
tok::TokenKind Kind) {
const char *NulCharacter = 0;
if (!isLexingRawMode() &&
(Kind == tok::utf16_char_constant || Kind == tok::utf32_char_constant))
Diag(BufferPtr, getLangOpts().CPlusPlus
? diag::warn_cxx98_compat_unicode_literal
: diag::warn_c99_compat_unicode_literal);
char C = getAndAdvanceChar(CurPtr, Result);
if (C == '\'') {
if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::ext_empty_character);
FormTokenWithChars(Result, CurPtr, tok::unknown);
return true;
}
while (C != '\'') {
if (C == '\\')
C = getAndAdvanceChar(CurPtr, Result);
if (C == '\n' || C == '\r' || (C == 0 && CurPtr-1 == BufferEnd)) { if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::ext_unterminated_char);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return true;
}
if (C == 0) {
if (isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
cutOffLexing();
return true;
}
NulCharacter = CurPtr-1;
}
C = getAndAdvanceChar(CurPtr, Result);
}
if (getLangOpts().CPlusPlus)
CurPtr = LexUDSuffix(Result, CurPtr, false);
if (NulCharacter && !isLexingRawMode())
Diag(NulCharacter, diag::null_in_char);
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, Kind);
Result.setLiteralData(TokStart);
return true;
}
bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr,
bool &TokAtPhysicalStartOfLine) {
bool SawNewline = isVerticalWhitespace(CurPtr[-1]);
unsigned char Char = *CurPtr;
while (1) {
while (isHorizontalWhitespace(Char))
Char = *++CurPtr;
if (!isVerticalWhitespace(Char))
break;
if (ParsingPreprocessorDirective) {
BufferPtr = CurPtr;
return false;
}
SawNewline = true;
Char = *++CurPtr;
}
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
if (SawNewline) {
IsAtStartOfLine = true;
IsAtPhysicalStartOfLine = true;
}
return true;
}
char PrevChar = CurPtr[-1];
bool HasLeadingSpace = !isVerticalWhitespace(PrevChar);
Result.setFlagValue(Token::LeadingSpace, HasLeadingSpace);
if (SawNewline) {
Result.setFlag(Token::StartOfLine);
TokAtPhysicalStartOfLine = true;
}
BufferPtr = CurPtr;
return false;
}
bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
bool &TokAtPhysicalStartOfLine) {
if (!LangOpts.LineComment && !isLexingRawMode()) {
Diag(BufferPtr, diag::ext_line_comment);
LangOpts.LineComment = true;
}
char C;
do {
C = *CurPtr;
while (C != 0 && C != '\n' && C != '\r') C = *++CurPtr;
const char *NextLine = CurPtr;
if (C != 0) {
const char *EscapePtr = CurPtr-1;
bool HasSpace = false;
while (isHorizontalWhitespace(*EscapePtr)) { --EscapePtr;
HasSpace = true;
}
if (*EscapePtr == '\\') CurPtr = EscapePtr;
else if (EscapePtr[0] == '/' && EscapePtr[-1] == '?' &&
EscapePtr[-2] == '?') CurPtr = EscapePtr-2;
else
break;
if (HasSpace && !isLexingRawMode())
Diag(EscapePtr, diag::backslash_newline_space);
}
const char *OldPtr = CurPtr;
bool OldRawMode = isLexingRawMode();
LexingRawMode = true;
C = getAndAdvanceChar(CurPtr, Result);
LexingRawMode = OldRawMode;
if (C != 0 && CurPtr == OldPtr+1) {
CurPtr = NextLine;
break;
}
if (CurPtr != OldPtr+1 && C != '/' && CurPtr[0] != '/') {
for (; OldPtr != CurPtr; ++OldPtr)
if (OldPtr[0] == '\n' || OldPtr[0] == '\r') {
if (isWhitespace(C)) {
const char *ForwardPtr = CurPtr;
while (isWhitespace(*ForwardPtr)) ++ForwardPtr;
if (ForwardPtr[0] == '/' && ForwardPtr[1] == '/')
break;
}
if (!isLexingRawMode())
Diag(OldPtr-1, diag::ext_multi_line_line_comment);
break;
}
}
if (CurPtr == BufferEnd+1) {
--CurPtr;
break;
}
if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
cutOffLexing();
return false;
}
} while (C != '\n' && C != '\r');
if (PP && !isLexingRawMode() &&
PP->HandleComment(Result, SourceRange(getSourceLocation(BufferPtr),
getSourceLocation(CurPtr)))) {
BufferPtr = CurPtr;
return true; }
if (inKeepCommentMode())
return SaveLineComment(Result, CurPtr);
if (ParsingPreprocessorDirective || CurPtr == BufferEnd) {
BufferPtr = CurPtr;
return false;
}
++CurPtr;
Result.setFlag(Token::StartOfLine);
TokAtPhysicalStartOfLine = true;
Result.clearFlag(Token::LeadingSpace);
BufferPtr = CurPtr;
return false;
}
bool Lexer::SaveLineComment(Token &Result, const char *CurPtr) {
FormTokenWithChars(Result, CurPtr, tok::comment);
if (!ParsingPreprocessorDirective || LexingRawMode)
return true;
bool Invalid = false;
std::string Spelling = PP->getSpelling(Result, &Invalid);
if (Invalid)
return true;
assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not line comment?");
Spelling[1] = '*'; Spelling += "*/";
Result.setKind(tok::comment);
PP->CreateString(Spelling, Result,
Result.getLocation(), Result.getLocation());
return true;
}
static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr,
Lexer *L) {
assert(CurPtr[0] == '\n' || CurPtr[0] == '\r');
--CurPtr;
if (CurPtr[0] == '\n' || CurPtr[0] == '\r') {
if (CurPtr[0] == CurPtr[1])
return false;
--CurPtr;
}
bool HasSpace = false;
while (isHorizontalWhitespace(*CurPtr) || *CurPtr == 0) {
--CurPtr;
HasSpace = true;
}
if (*CurPtr == '\\') {
if (CurPtr[-1] != '*') return false;
} else {
if (CurPtr[0] != '/' || CurPtr[-1] != '?' || CurPtr[-2] != '?' ||
CurPtr[-3] != '*')
return false;
CurPtr -= 2;
if (!L->getLangOpts().Trigraphs) {
if (!L->isLexingRawMode())
L->Diag(CurPtr, diag::trigraph_ignored_block_comment);
return false;
}
if (!L->isLexingRawMode())
L->Diag(CurPtr, diag::trigraph_ends_block_comment);
}
if (!L->isLexingRawMode())
L->Diag(CurPtr, diag::escaped_newline_block_comment_end);
if (HasSpace && !L->isLexingRawMode())
L->Diag(CurPtr, diag::backslash_newline_space);
return true;
}
#ifdef __SSE2__
#include <emmintrin.h>
#elif __ALTIVEC__
#include <altivec.h>
#undef bool
#endif
bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr,
bool &TokAtPhysicalStartOfLine) {
unsigned CharSize;
unsigned char C = getCharAndSize(CurPtr, CharSize);
CurPtr += CharSize;
if (C == 0 && CurPtr == BufferEnd+1) {
if (!isLexingRawMode())
Diag(BufferPtr, diag::err_unterminated_block_comment);
--CurPtr;
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
return true;
}
BufferPtr = CurPtr;
return false;
}
if (C == '/')
C = *CurPtr++;
while (1) {
if (CurPtr + 24 < BufferEnd &&
!(PP && PP->getCodeCompletionFileLoc() == FileLoc)) {
while (C != '/' && ((intptr_t)CurPtr & 0x0F) != 0)
C = *CurPtr++;
if (C == '/') goto FoundSlash;
#ifdef __SSE2__
__m128i Slashes = _mm_set1_epi8('/');
while (CurPtr+16 <= BufferEnd) {
int cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(*(const __m128i*)CurPtr,
Slashes));
if (cmp != 0) {
CurPtr += llvm::countTrailingZeros<unsigned>(cmp) + 1;
goto FoundSlash;
}
CurPtr += 16;
}
#elif __ALTIVEC__
__vector unsigned char Slashes = {
'/', '/', '/', '/', '/', '/', '/', '/',
'/', '/', '/', '/', '/', '/', '/', '/'
};
while (CurPtr+16 <= BufferEnd &&
!vec_any_eq(*(vector unsigned char*)CurPtr, Slashes))
CurPtr += 16;
#else
while (CurPtr[0] != '/' &&
CurPtr[1] != '/' &&
CurPtr[2] != '/' &&
CurPtr[3] != '/' &&
CurPtr+4 < BufferEnd) {
CurPtr += 4;
}
#endif
C = *CurPtr++;
}
while (C != '/' && C != '\0')
C = *CurPtr++;
if (C == '/') {
FoundSlash:
if (CurPtr[-2] == '*') break;
if ((CurPtr[-2] == '\n' || CurPtr[-2] == '\r')) {
if (isEndOfBlockCommentWithEscapedNewLine(CurPtr-2, this)) {
break;
}
}
if (CurPtr[0] == '*' && CurPtr[1] != '/') {
if (!isLexingRawMode())
Diag(CurPtr-1, diag::warn_nested_block_comment);
}
} else if (C == 0 && CurPtr == BufferEnd+1) {
if (!isLexingRawMode())
Diag(BufferPtr, diag::err_unterminated_block_comment);
--CurPtr;
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
return true;
}
BufferPtr = CurPtr;
return false;
} else if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
cutOffLexing();
return false;
}
C = *CurPtr++;
}
if (PP && !isLexingRawMode() &&
PP->HandleComment(Result, SourceRange(getSourceLocation(BufferPtr),
getSourceLocation(CurPtr)))) {
BufferPtr = CurPtr;
return true; }
if (inKeepCommentMode()) {
FormTokenWithChars(Result, CurPtr, tok::comment);
return true;
}
if (isHorizontalWhitespace(*CurPtr)) {
SkipWhitespace(Result, CurPtr+1, TokAtPhysicalStartOfLine);
return false;
}
BufferPtr = CurPtr;
Result.setFlag(Token::LeadingSpace);
return false;
}
void Lexer::ReadToEndOfLine(SmallVectorImpl<char> *Result) {
assert(ParsingPreprocessorDirective && ParsingFilename == false &&
"Must be in a preprocessing directive!");
Token Tmp;
const char *CurPtr = BufferPtr;
while (1) {
char Char = getAndAdvanceChar(CurPtr, Tmp);
switch (Char) {
default:
if (Result)
Result->push_back(Char);
break;
case 0: if (CurPtr-1 != BufferEnd) {
if (isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
cutOffLexing();
return;
}
if (Result)
Result->push_back(Char);
break;
}
case '\r':
case '\n':
assert(CurPtr[-1] == Char && "Trigraphs for newline?");
BufferPtr = CurPtr-1;
Lex(Tmp);
if (Tmp.is(tok::code_completion)) {
if (PP)
PP->CodeCompleteNaturalLanguage();
Lex(Tmp);
}
assert(Tmp.is(tok::eod) && "Unexpected token!");
return;
}
}
}
bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
if (ParsingPreprocessorDirective) {
ParsingPreprocessorDirective = false;
FormTokenWithChars(Result, CurPtr, tok::eod);
if (PP)
resetExtendedTokenMode();
return true; }
if (isLexingRawMode()) {
Result.startToken();
BufferPtr = BufferEnd;
FormTokenWithChars(Result, BufferEnd, tok::eof);
return true;
}
while (!ConditionalStack.empty()) {
if (PP->getCodeCompletionFileLoc() != FileLoc)
PP->Diag(ConditionalStack.back().IfLoc,
diag::err_pp_unterminated_conditional);
ConditionalStack.pop_back();
}
if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r')) {
DiagnosticsEngine &Diags = PP->getDiagnostics();
SourceLocation EndLoc = getSourceLocation(BufferEnd);
unsigned DiagID;
if (LangOpts.CPlusPlus11) {
if (Diags.getDiagnosticLevel(diag::warn_cxx98_compat_no_newline_eof,
EndLoc) != DiagnosticsEngine::Ignored) {
DiagID = diag::warn_cxx98_compat_no_newline_eof;
} else {
DiagID = diag::warn_no_newline_eof;
}
} else {
DiagID = diag::ext_no_newline_eof;
}
Diag(BufferEnd, DiagID)
<< FixItHint::CreateInsertion(EndLoc, "\n");
}
BufferPtr = CurPtr;
return PP->HandleEndOfFile(Result, isPragmaLexer());
}
unsigned Lexer::isNextPPTokenLParen() {
assert(!LexingRawMode && "How can we expand a macro from a skipping buffer?");
LexingRawMode = true;
const char *TmpBufferPtr = BufferPtr;
bool inPPDirectiveMode = ParsingPreprocessorDirective;
bool atStartOfLine = IsAtStartOfLine;
bool atPhysicalStartOfLine = IsAtPhysicalStartOfLine;
bool leadingSpace = HasLeadingSpace;
Token Tok;
Lex(Tok);
BufferPtr = TmpBufferPtr;
ParsingPreprocessorDirective = inPPDirectiveMode;
HasLeadingSpace = leadingSpace;
IsAtStartOfLine = atStartOfLine;
IsAtPhysicalStartOfLine = atPhysicalStartOfLine;
LexingRawMode = false;
if (Tok.is(tok::eof))
return 2;
return Tok.is(tok::l_paren);
}
static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd,
ConflictMarkerKind CMK) {
const char *Terminator = CMK == CMK_Perforce ? "<<<<\n" : ">>>>>>>";
size_t TermLen = CMK == CMK_Perforce ? 5 : 7;
StringRef RestOfBuffer(CurPtr+TermLen, BufferEnd-CurPtr-TermLen);
size_t Pos = RestOfBuffer.find(Terminator);
while (Pos != StringRef::npos) {
if (RestOfBuffer[Pos-1] != '\r' &&
RestOfBuffer[Pos-1] != '\n') {
RestOfBuffer = RestOfBuffer.substr(Pos+TermLen);
Pos = RestOfBuffer.find(Terminator);
continue;
}
return RestOfBuffer.data()+Pos;
}
return 0;
}
bool Lexer::IsStartOfConflictMarker(const char *CurPtr) {
if (CurPtr != BufferStart &&
CurPtr[-1] != '\n' && CurPtr[-1] != '\r')
return false;
if ((BufferEnd-CurPtr < 8 || StringRef(CurPtr, 7) != "<<<<<<<") &&
(BufferEnd-CurPtr < 6 || StringRef(CurPtr, 5) != ">>>> "))
return false;
if (CurrentConflictMarkerState || isLexingRawMode())
return false;
ConflictMarkerKind Kind = *CurPtr == '<' ? CMK_Normal : CMK_Perforce;
if (FindConflictEnd(CurPtr, BufferEnd, Kind)) {
Diag(CurPtr, diag::err_conflict_marker);
CurrentConflictMarkerState = Kind;
while (*CurPtr != '\r' && *CurPtr != '\n') {
assert(CurPtr != BufferEnd && "Didn't find end of line");
++CurPtr;
}
BufferPtr = CurPtr;
return true;
}
return false;
}
bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) {
if (CurPtr != BufferStart &&
CurPtr[-1] != '\n' && CurPtr[-1] != '\r')
return false;
if (!CurrentConflictMarkerState || isLexingRawMode())
return false;
for (unsigned i = 1; i != 4; ++i)
if (CurPtr[i] != CurPtr[0])
return false;
if (const char *End = FindConflictEnd(CurPtr, BufferEnd,
CurrentConflictMarkerState)) {
CurPtr = End;
while (CurPtr != BufferEnd && *CurPtr != '\r' && *CurPtr != '\n')
++CurPtr;
BufferPtr = CurPtr;
CurrentConflictMarkerState = CMK_None;
return true;
}
return false;
}
bool Lexer::isCodeCompletionPoint(const char *CurPtr) const {
if (PP && PP->isCodeCompletionEnabled()) {
SourceLocation Loc = FileLoc.getLocWithOffset(CurPtr-BufferStart);
return Loc == PP->getCodeCompletionLoc();
}
return false;
}
uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc,
Token *Result) {
unsigned CharSize;
char Kind = getCharAndSize(StartPtr, CharSize);
unsigned NumHexDigits;
if (Kind == 'u')
NumHexDigits = 4;
else if (Kind == 'U')
NumHexDigits = 8;
else
return 0;
if (!LangOpts.CPlusPlus && !LangOpts.C99) {
if (Result && !isLexingRawMode())
Diag(SlashLoc, diag::warn_ucn_not_valid_in_c89);
return 0;
}
const char *CurPtr = StartPtr + CharSize;
const char *KindLoc = &CurPtr[-1];
uint32_t CodePoint = 0;
for (unsigned i = 0; i < NumHexDigits; ++i) {
char C = getCharAndSize(CurPtr, CharSize);
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 (i == 4 && NumHexDigits == 8) {
CharSourceRange URange = makeCharRange(*this, KindLoc, KindLoc + 1);
Diag(KindLoc, diag::note_ucn_four_not_eight)
<< FixItHint::CreateReplacement(URange, "u");
}
}
}
return 0;
}
CodePoint <<= 4;
CodePoint += Value;
CurPtr += CharSize;
}
if (Result) {
Result->setFlag(Token::HasUCN);
if (CurPtr - StartPtr == (ptrdiff_t)NumHexDigits + 2)
StartPtr = CurPtr;
else
while (StartPtr != CurPtr)
(void)getAndAdvanceChar(StartPtr, *Result);
} else {
StartPtr = CurPtr;
}
if (LangOpts.AsmPreprocessor)
return CodePoint;
if (CodePoint < 0xA0) {
if (CodePoint == 0x24 || CodePoint == 0x40 || CodePoint == 0x60)
return CodePoint;
if (Result && PP) {
if (CodePoint < 0x20 || CodePoint >= 0x7F)
Diag(BufferPtr, diag::err_ucn_control_character);
else {
char C = static_cast<char>(CodePoint);
Diag(BufferPtr, diag::err_ucn_escape_basic_scs) << StringRef(&C, 1);
}
}
return 0;
} else if (CodePoint >= 0xD800 && CodePoint <= 0xDFFF) {
if (Result && PP) {
if (LangOpts.CPlusPlus && !LangOpts.CPlusPlus11)
Diag(BufferPtr, diag::warn_ucn_escape_surrogate);
else
Diag(BufferPtr, diag::err_ucn_escape_invalid);
}
return 0;
}
return CodePoint;
}
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)) {
Diag(BufferPtr, diag::ext_unicode_whitespace)
<< makeCharRange(*this, BufferPtr, CurPtr);
Result.setFlag(Token::LeadingSpace);
return true;
}
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),
true);
}
MIOpt.ReadToken();
return LexIdentifier(Result, CurPtr);
}
if (!isLexingRawMode() && !ParsingPreprocessorDirective &&
!PP->isPreprocessedOutput() &&
!isASCII(*BufferPtr) && !isAllowedIDChar(C, LangOpts)) {
Diag(BufferPtr, diag::err_non_ascii)
<< FixItHint::CreateRemoval(makeCharRange(*this, BufferPtr, CurPtr));
BufferPtr = CurPtr;
return false;
}
MIOpt.ReadToken();
FormTokenWithChars(Result, CurPtr, tok::unknown);
return true;
}
void Lexer::PropagateLineStartLeadingSpaceInfo(Token &Result) {
IsAtStartOfLine = Result.isAtStartOfLine();
HasLeadingSpace = Result.hasLeadingSpace();
HasLeadingEmptyMacro = Result.hasLeadingEmptyMacro();
}
bool Lexer::Lex(Token &Result) {
Result.startToken();
if (IsAtStartOfLine) {
Result.setFlag(Token::StartOfLine);
IsAtStartOfLine = false;
}
if (HasLeadingSpace) {
Result.setFlag(Token::LeadingSpace);
HasLeadingSpace = false;
}
if (HasLeadingEmptyMacro) {
Result.setFlag(Token::LeadingEmptyMacro);
HasLeadingEmptyMacro = false;
}
bool atPhysicalStartOfLine = IsAtPhysicalStartOfLine;
IsAtPhysicalStartOfLine = false;
bool isRawLex = isLexingRawMode();
(void) isRawLex;
bool returnedToken = LexTokenInternal(Result, atPhysicalStartOfLine);
assert((returnedToken || !isRawLex) && "Raw lex must succeed");
return returnedToken;
}
bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) {
LexNextToken:
Result.clearFlag(Token::NeedsCleaning);
Result.setIdentifierInfo(0);
const char *CurPtr = BufferPtr;
if ((*CurPtr == ' ') || (*CurPtr == '\t')) {
++CurPtr;
while ((*CurPtr == ' ') || (*CurPtr == '\t'))
++CurPtr;
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
return true;
}
BufferPtr = CurPtr;
Result.setFlag(Token::LeadingSpace);
}
unsigned SizeTmp, SizeTmp2;
char Char = getAndAdvanceChar(CurPtr, Result);
tok::TokenKind Kind;
switch (Char) {
case 0: if (CurPtr-1 == BufferEnd)
return LexEndOfFile(Result, CurPtr-1);
if (isCodeCompletionPoint(CurPtr-1)) {
Result.startToken();
FormTokenWithChars(Result, CurPtr, tok::code_completion);
return true;
}
if (!isLexingRawMode())
Diag(CurPtr-1, diag::null_in_file);
Result.setFlag(Token::LeadingSpace);
if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine))
return true;
goto LexNextToken;
case 26: if (LangOpts.MicrosoftExt)
return LexEndOfFile(Result, CurPtr-1);
Kind = tok::unknown;
break;
case '\n':
case '\r':
if (ParsingPreprocessorDirective) {
ParsingPreprocessorDirective = false;
if (PP)
resetExtendedTokenMode();
IsAtStartOfLine = true;
IsAtPhysicalStartOfLine = true;
Kind = tok::eod;
break;
}
Result.clearFlag(Token::LeadingSpace);
if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine))
return true;
goto LexNextToken;
case ' ':
case '\t':
case '\f':
case '\v':
SkipHorizontalWhitespace:
Result.setFlag(Token::LeadingSpace);
if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine))
return true;
SkipIgnoredUnits:
CurPtr = BufferPtr;
if (CurPtr[0] == '/' && CurPtr[1] == '/' && !inKeepCommentMode() &&
LangOpts.LineComment &&
(LangOpts.CPlusPlus || !LangOpts.TraditionalCPP)) {
if (SkipLineComment(Result, CurPtr+2, TokAtPhysicalStartOfLine))
return true; goto SkipIgnoredUnits;
} else if (CurPtr[0] == '/' && CurPtr[1] == '*' && !inKeepCommentMode()) {
if (SkipBlockComment(Result, CurPtr+2, TokAtPhysicalStartOfLine))
return true; goto SkipIgnoredUnits;
} else if (isHorizontalWhitespace(*CurPtr)) {
goto SkipHorizontalWhitespace;
}
goto LexNextToken;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
MIOpt.ReadToken();
return LexNumericConstant(Result, CurPtr);
case 'u': MIOpt.ReadToken();
if (LangOpts.CPlusPlus11 || LangOpts.C11) {
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '"')
return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::utf16_string_literal);
if (Char == '\'')
return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::utf16_char_constant);
if (Char == 'R' && LangOpts.CPlusPlus11 &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
tok::utf16_string_literal);
if (Char == '8') {
char Char2 = getCharAndSize(CurPtr + SizeTmp, SizeTmp2);
if (Char2 == '"')
return LexStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
tok::utf8_string_literal);
if (Char2 == 'R' && LangOpts.CPlusPlus11) {
unsigned SizeTmp3;
char Char3 = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3);
if (Char3 == '"') {
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
SizeTmp3, Result),
tok::utf8_string_literal);
}
}
}
}
return LexIdentifier(Result, CurPtr);
case 'U': MIOpt.ReadToken();
if (LangOpts.CPlusPlus11 || LangOpts.C11) {
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '"')
return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::utf32_string_literal);
if (Char == '\'')
return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::utf32_char_constant);
if (Char == 'R' && LangOpts.CPlusPlus11 &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
tok::utf32_string_literal);
}
return LexIdentifier(Result, CurPtr);
case 'R': MIOpt.ReadToken();
if (LangOpts.CPlusPlus11) {
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '"')
return LexRawStringLiteral(Result,
ConsumeChar(CurPtr, SizeTmp, Result),
tok::string_literal);
}
return LexIdentifier(Result, CurPtr);
case 'L': MIOpt.ReadToken();
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '"')
return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::wide_string_literal);
if (LangOpts.CPlusPlus11 && Char == 'R' &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
tok::wide_string_literal);
if (Char == '\'')
return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::wide_char_constant);
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'S': case 'T':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't':
case 'v': case 'w': case 'x': case 'y': case 'z':
case '_':
MIOpt.ReadToken();
return LexIdentifier(Result, CurPtr);
case '$': if (LangOpts.DollarIdents) {
if (!isLexingRawMode())
Diag(CurPtr-1, diag::ext_dollar_in_identifier);
MIOpt.ReadToken();
return LexIdentifier(Result, CurPtr);
}
Kind = tok::unknown;
break;
case '\'':
MIOpt.ReadToken();
return LexCharConstant(Result, CurPtr, tok::char_constant);
case '"':
MIOpt.ReadToken();
return LexStringLiteral(Result, CurPtr, tok::string_literal);
case '?':
Kind = tok::question;
break;
case '[':
Kind = tok::l_square;
break;
case ']':
Kind = tok::r_square;
break;
case '(':
Kind = tok::l_paren;
break;
case ')':
Kind = tok::r_paren;
break;
case '{':
Kind = tok::l_brace;
break;
case '}':
Kind = tok::r_brace;
break;
case '.':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char >= '0' && Char <= '9') {
MIOpt.ReadToken();
return LexNumericConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result));
} else if (LangOpts.CPlusPlus && Char == '*') {
Kind = tok::periodstar;
CurPtr += SizeTmp;
} else if (Char == '.' &&
getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '.') {
Kind = tok::ellipsis;
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
} else {
Kind = tok::period;
}
break;
case '&':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '&') {
Kind = tok::ampamp;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else if (Char == '=') {
Kind = tok::ampequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
Kind = tok::amp;
}
break;
case '*':
if (getCharAndSize(CurPtr, SizeTmp) == '=') {
Kind = tok::starequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
Kind = tok::star;
}
break;
case '+':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '+') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::plusplus;
} else if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::plusequal;
} else {
Kind = tok::plus;
}
break;
case '-':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '-') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::minusminus;
} else if (Char == '>' && LangOpts.CPlusPlus &&
getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '*') { CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
Kind = tok::arrowstar;
} else if (Char == '>') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::arrow;
} else if (Char == '=') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::minusequal;
} else {
Kind = tok::minus;
}
break;
case '~':
Kind = tok::tilde;
break;
case '!':
if (getCharAndSize(CurPtr, SizeTmp) == '=') {
Kind = tok::exclaimequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
Kind = tok::exclaim;
}
break;
case '/':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '/') { bool TreatAsComment = LangOpts.LineComment &&
(LangOpts.CPlusPlus || !LangOpts.TraditionalCPP);
if (!TreatAsComment)
if (!(PP && PP->isPreprocessedOutput()))
TreatAsComment = getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*';
if (TreatAsComment) {
if (SkipLineComment(Result, ConsumeChar(CurPtr, SizeTmp, Result),
TokAtPhysicalStartOfLine))
return true;
goto SkipIgnoredUnits;
}
}
if (Char == '*') { if (SkipBlockComment(Result, ConsumeChar(CurPtr, SizeTmp, Result),
TokAtPhysicalStartOfLine))
return true;
goto LexNextToken;
}
if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::slashequal;
} else {
Kind = tok::slash;
}
break;
case '%':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '=') {
Kind = tok::percentequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else if (LangOpts.Digraphs && Char == '>') {
Kind = tok::r_brace; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else if (LangOpts.Digraphs && Char == ':') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '%' && getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == ':') {
Kind = tok::hashhash; CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
} else if (Char == '@' && LangOpts.MicrosoftExt) { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
if (!isLexingRawMode())
Diag(BufferPtr, diag::ext_charize_microsoft);
Kind = tok::hashat;
} else { if (TokAtPhysicalStartOfLine && !LexingRawMode && !Is_PragmaLexer)
goto HandleDirective;
Kind = tok::hash;
}
} else {
Kind = tok::percent;
}
break;
case '<':
Char = getCharAndSize(CurPtr, SizeTmp);
if (ParsingFilename) {
return LexAngledStringLiteral(Result, CurPtr);
} else if (Char == '<') {
char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2);
if (After == '=') {
Kind = tok::lesslessequal;
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
} else if (After == '<' && IsStartOfConflictMarker(CurPtr-1)) {
goto LexNextToken;
} else if (After == '<' && HandleEndOfConflictMarker(CurPtr-1)) {
goto LexNextToken;
} else if (LangOpts.CUDA && After == '<') {
Kind = tok::lesslessless;
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
} else {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::lessless;
}
} else if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::lessequal;
} else if (LangOpts.Digraphs && Char == ':') { if (LangOpts.CPlusPlus11 &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == ':') {
unsigned SizeTmp3;
char After = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3);
if (After != ':' && After != '>') {
Kind = tok::less;
if (!isLexingRawMode())
Diag(BufferPtr, diag::warn_cxx98_compat_less_colon_colon);
break;
}
}
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::l_square;
} else if (LangOpts.Digraphs && Char == '%') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::l_brace;
} else {
Kind = tok::less;
}
break;
case '>':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::greaterequal;
} else if (Char == '>') {
char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2);
if (After == '=') {
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
Kind = tok::greatergreaterequal;
} else if (After == '>' && IsStartOfConflictMarker(CurPtr-1)) {
goto LexNextToken;
} else if (After == '>' && HandleEndOfConflictMarker(CurPtr-1)) {
goto LexNextToken;
} else if (LangOpts.CUDA && After == '>') {
Kind = tok::greatergreatergreater;
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
} else {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::greatergreater;
}
} else {
Kind = tok::greater;
}
break;
case '^':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::caretequal;
} else {
Kind = tok::caret;
}
break;
case '|':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '=') {
Kind = tok::pipeequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else if (Char == '|') {
if (CurPtr[1] == '|' && HandleEndOfConflictMarker(CurPtr-1))
goto LexNextToken;
Kind = tok::pipepipe;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
Kind = tok::pipe;
}
break;
case ':':
Char = getCharAndSize(CurPtr, SizeTmp);
if (LangOpts.Digraphs && Char == '>') {
Kind = tok::r_square; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else if (LangOpts.CPlusPlus && Char == ':') {
Kind = tok::coloncolon;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
Kind = tok::colon;
}
break;
case ';':
Kind = tok::semi;
break;
case '=':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '=') {
if (CurPtr[1] == '=' && HandleEndOfConflictMarker(CurPtr-1))
goto LexNextToken;
Kind = tok::equalequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
Kind = tok::equal;
}
break;
case ',':
Kind = tok::comma;
break;
case '#':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '#') {
Kind = tok::hashhash;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else if (Char == '@' && LangOpts.MicrosoftExt) { Kind = tok::hashat;
if (!isLexingRawMode())
Diag(BufferPtr, diag::ext_charize_microsoft);
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
if (TokAtPhysicalStartOfLine && !LexingRawMode && !Is_PragmaLexer)
goto HandleDirective;
Kind = tok::hash;
}
break;
case '@':
if (CurPtr[-1] == '@' && LangOpts.ObjC1)
Kind = tok::at;
else
Kind = tok::unknown;
break;
case '\\':
if (uint32_t CodePoint = tryReadUCN(CurPtr, BufferPtr, &Result)) {
if (CheckUnicodeWhitespace(Result, CodePoint, CurPtr)) {
if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine))
return true;
goto LexNextToken;
}
return LexUnicode(Result, CodePoint, CurPtr);
}
Kind = tok::unknown;
break;
default: {
if (isASCII(Char)) {
Kind = tok::unknown;
break;
}
UTF32 CodePoint;
--CurPtr;
ConversionResult Status =
llvm::convertUTF8Sequence((const UTF8 **)&CurPtr,
(const UTF8 *)BufferEnd,
&CodePoint,
strictConversion);
if (Status == conversionOK) {
if (CheckUnicodeWhitespace(Result, CodePoint, CurPtr)) {
if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine))
return true;
goto LexNextToken;
}
return LexUnicode(Result, CodePoint, CurPtr);
}
if (isLexingRawMode() || ParsingPreprocessorDirective ||
PP->isPreprocessedOutput()) {
++CurPtr;
Kind = tok::unknown;
break;
}
Diag(CurPtr, diag::err_invalid_utf8);
BufferPtr = CurPtr+1;
goto LexNextToken;
}
}
MIOpt.ReadToken();
FormTokenWithChars(Result, CurPtr, Kind);
return true;
HandleDirective:
FormTokenWithChars(Result, CurPtr, tok::hash);
PP->HandleDirective(Result);
if (PP->hadModuleLoaderFatalFailure()) {
assert(Result.is(tok::eof) && "Preprocessor did not set tok:eof");
return true;
}
return false;
}