Skip to content

[Lex & PP] Cherry-picks from upstream llvm.org, related to lexer and preprocessor #5085

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions clang-tools-extra/test/pp-trace/pp-trace-include.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// CHECK-NEXT: Loc: "<built-in>:1:1"
// CHECK-NEXT: Reason: EnterFile
// CHECK-NEXT: FileType: C_User
// CHECK-NEXT: PrevFID: (invalid)
// CHECK-NEXT: PrevFID: "{{.*}}{{[/\\]}}pp-trace-include.cpp"
// CHECK-NEXT: - Callback: FileChanged
// CHECK-NEXT: Loc: "<built-in>:1:1"
// CHECK-NEXT: Reason: RenameFile
Expand Down Expand Up @@ -63,7 +63,7 @@
// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}Inputs/Level1A.h:1:1"
// CHECK-NEXT: Reason: EnterFile
// CHECK-NEXT: FileType: C_User
// CHECK-NEXT: PrevFID: (invalid)
// CHECK-NEXT: PrevFID: "{{.*}}{{[/\\]}}pp-trace-include.cpp"
// CHECK-NEXT: - Callback: InclusionDirective
// CHECK-NEXT: IncludeTok: include
// CHECK-NEXT: FileName: "Level2A.h"
Expand All @@ -77,7 +77,7 @@
// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}Inputs/Level2A.h:1:1"
// CHECK-NEXT: Reason: EnterFile
// CHECK-NEXT: FileType: C_User
// CHECK-NEXT: PrevFID: (invalid)
// CHECK-NEXT: PrevFID: "{{.*}}{{[/\\]}}Inputs/Level1A.h"
// CHECK-NEXT: - Callback: MacroDefined
// CHECK-NEXT: MacroNameTok: MACRO_2A
// CHECK-NEXT: MacroDirective: MD_Define
Expand Down Expand Up @@ -107,7 +107,7 @@
// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}Inputs/Level1B.h:1:1"
// CHECK-NEXT: Reason: EnterFile
// CHECK-NEXT: FileType: C_User
// CHECK-NEXT: PrevFID: (invalid)
// CHECK-NEXT: PrevFID: "{{.*}}{{[/\\]}}pp-trace-include.cpp"
// CHECK-NEXT: - Callback: InclusionDirective
// CHECK-NEXT: IncludeTok: include
// CHECK-NEXT: FileName: "Level2B.h"
Expand All @@ -121,7 +121,7 @@
// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}Inputs/Level2B.h:1:1"
// CHECK-NEXT: Reason: EnterFile
// CHECK-NEXT: FileType: C_User
// CHECK-NEXT: PrevFID: (invalid)
// CHECK-NEXT: PrevFID: "{{.*}}{{[/\\]}}Inputs/Level1B.h"
// CHECK-NEXT: - Callback: MacroDefined
// CHECK-NEXT: MacroNameTok: MACRO_2B
// CHECK-NEXT: MacroDirective: MD_Define
Expand Down
31 changes: 30 additions & 1 deletion clang/include/clang/Lex/PPCallbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,34 @@ class PPCallbacks {
/// Callback invoked whenever a source file is entered or exited.
///
/// \param Loc Indicates the new location.
/// \param PrevFID the file that was exited if \p Reason is ExitFile.
/// \param PrevFID the file that was exited if \p Reason is ExitFile or the
/// the file before the new one entered for \p Reason EnterFile.
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
FileID PrevFID = FileID()) {
}

enum class LexedFileChangeReason { EnterFile, ExitFile };

/// Callback invoked whenever the \p Lexer moves to a different file for
/// lexing. Unlike \p FileChanged line number directives and other related
/// pragmas do not trigger callbacks to \p LexedFileChanged.
///
/// \param FID The \p FileID that the \p Lexer moved to.
///
/// \param Reason Whether the \p Lexer entered a new file or exited one.
///
/// \param FileType The \p CharacteristicKind of the file the \p Lexer moved
/// to.
///
/// \param PrevFID The \p FileID the \p Lexer was using before the change.
///
/// \param Loc The location where the \p Lexer entered a new file from or the
/// location that the \p Lexer moved into after exiting a file.
virtual void LexedFileChanged(FileID FID, LexedFileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
FileID PrevFID, SourceLocation Loc) {}

/// Callback invoked whenever a source file is skipped as the result
/// of header guard optimization.
///
Expand Down Expand Up @@ -420,6 +442,13 @@ class PPChainedCallbacks : public PPCallbacks {
Second->FileChanged(Loc, Reason, FileType, PrevFID);
}

void LexedFileChanged(FileID FID, LexedFileChangeReason Reason,
SrcMgr::CharacteristicKind FileType, FileID PrevFID,
SourceLocation Loc) override {
First->LexedFileChanged(FID, Reason, FileType, PrevFID, Loc);
Second->LexedFileChanged(FID, Reason, FileType, PrevFID, Loc);
}

void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
SrcMgr::CharacteristicKind FileType) override {
First->FileSkipped(SkippedFile, FilenameTok, FileType);
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,18 @@ class Preprocessor {
/// of that list.
MacroInfoChain *MIChainHead = nullptr;

/// True if \p Preprocessor::SkipExcludedConditionalBlock() is running.
/// This is used to guard against calling this function recursively.
///
/// See comments at the use-site for more context about why it is needed.
bool SkippingExcludedConditionalBlock = false;

/// Keeps track of skipped range mappings that were recorded while skipping
/// excluded conditional directives. It maps the source buffer pointer at
/// the beginning of a skipped block, to the number of bytes that should be
/// skipped.
llvm::DenseMap<const char *, unsigned> RecordedSkippedRanges;

void updateOutOfDateIdentifier(IdentifierInfo &II) const;

public:
Expand Down
32 changes: 15 additions & 17 deletions clang/lib/Frontend/DependencyFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,21 @@ using namespace clang;
namespace {
struct DepCollectorPPCallbacks : public PPCallbacks {
DependencyCollector &DepCollector;
SourceManager &SM;
DiagnosticsEngine &Diags;
DepCollectorPPCallbacks(DependencyCollector &L, SourceManager &SM,
DiagnosticsEngine &Diags)
: DepCollector(L), SM(SM), Diags(Diags) {}

void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
FileID PrevFID) override {
if (Reason != PPCallbacks::EnterFile)
Preprocessor &PP;
DepCollectorPPCallbacks(DependencyCollector &L, Preprocessor &PP)
: DepCollector(L), PP(PP) {}

void LexedFileChanged(FileID FID, LexedFileChangeReason Reason,
SrcMgr::CharacteristicKind FileType, FileID PrevFID,
SourceLocation Loc) override {
if (Reason != PPCallbacks::LexedFileChangeReason::EnterFile)
return;

// Dependency generation really does want to go all the way to the
// file entry for a source location to find out what is depended on.
// We do not want #line markers to affect dependency generation!
if (Optional<StringRef> Filename = SM.getNonBuiltinFilenameForID(
SM.getFileID(SM.getExpansionLoc(Loc))))
if (Optional<StringRef> Filename =
PP.getSourceManager().getNonBuiltinFilenameForID(FID))
DepCollector.maybeAddDependency(
llvm::sys::path::remove_leading_dotslash(*Filename),
/*FromModule*/ false, isSystem(FileType), /*IsModuleFile*/ false,
Expand Down Expand Up @@ -91,7 +89,9 @@ struct DepCollectorPPCallbacks : public PPCallbacks {
/*IsMissing=*/false);
}

void EndOfMainFile() override { DepCollector.finishedMainFile(Diags); }
void EndOfMainFile() override {
DepCollector.finishedMainFile(PP.getDiagnostics());
}
};

struct DepCollectorMMCallbacks : public ModuleMapCallbacks {
Expand Down Expand Up @@ -206,8 +206,7 @@ bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,

DependencyCollector::~DependencyCollector() { }
void DependencyCollector::attachToPreprocessor(Preprocessor &PP) {
PP.addPPCallbacks(std::make_unique<DepCollectorPPCallbacks>(
*this, PP.getSourceManager(), PP.getDiagnostics()));
PP.addPPCallbacks(std::make_unique<DepCollectorPPCallbacks>(*this, PP));
PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(
std::make_unique<DepCollectorMMCallbacks>(*this));
}
Expand Down Expand Up @@ -240,8 +239,7 @@ void DependencyFileGenerator::attachToPreprocessor(Preprocessor &PP) {

// FIXME: Restore the call to DependencyCollector::attachToPreprocessor(PP);
// once the SkipUnusedModuleMaps is upstreamed.
PP.addPPCallbacks(std::make_unique<DepCollectorPPCallbacks>(
*this, PP.getSourceManager(), PP.getDiagnostics()));
PP.addPPCallbacks(std::make_unique<DepCollectorPPCallbacks>(*this, PP));
PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(
std::make_unique<DFGMMCallback>(*this, SkipUnusedModuleMaps));
}
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Lex/Lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4165,6 +4165,10 @@ bool Lexer::LexDependencyDirectiveToken(Token &Result) {

const dependency_directives_scan::Token &DDTok =
DepDirectives.front().Tokens[NextDepDirectiveTokenIndex++];
if (NextDepDirectiveTokenIndex > 1 || DDTok.Kind != tok::hash) {
// Read something other than a preprocessor directive hash.
MIOpt.ReadToken();
}

const char *TokPtr = convertDependencyDirectiveToken(DDTok, Result);

Expand Down Expand Up @@ -4252,6 +4256,7 @@ bool Lexer::LexDependencyDirectiveTokenWhileSkipping(Token &Result) {
}
break;
case pp_eof:
NextDepDirectiveTokenIndex = 0;
return LexEndOfFile(Result, BufferEnd);
}
} while (!Stop);
Expand Down
74 changes: 72 additions & 2 deletions clang/lib/Lex/PPDirectives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,16 @@
#include "clang/Lex/Token.h"
#include "clang/Lex/VariadicMacroSupport.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SaveAndRestore.h"
#include <algorithm>
#include <cassert>
#include <cstring>
Expand Down Expand Up @@ -411,6 +412,19 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
bool FoundNonSkipPortion,
bool FoundElse,
SourceLocation ElseLoc) {
// In SkippingRangeStateTy we are depending on SkipExcludedConditionalBlock()
// not getting called recursively by storing the RecordedSkippedRanges
// DenseMap lookup pointer (field SkipRangePtr). SkippingRangeStateTy expects
// that RecordedSkippedRanges won't get modified and SkipRangePtr won't be
// invalidated. If this changes and there is a need to call
// SkipExcludedConditionalBlock() recursively, SkippingRangeStateTy should
// change to do a second lookup in endLexPass function instead of reusing the
// lookup pointer.
assert(!SkippingExcludedConditionalBlock &&
"calling SkipExcludedConditionalBlock recursively");
llvm::SaveAndRestore<bool> SARSkipping(SkippingExcludedConditionalBlock,
true);

++NumSkipped;
assert(!CurTokenLexer && CurPPLexer && "Lexing a macro, not a file?");

Expand All @@ -425,10 +439,53 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
CurPPLexer->LexingRawMode = true;
Token Tok;
SourceLocation endLoc;

/// Keeps track and caches skipped ranges and also retrieves a prior skipped
/// range if the same block is re-visited.
struct SkippingRangeStateTy {
Preprocessor &PP;

const char *BeginPtr = nullptr;
unsigned *SkipRangePtr = nullptr;

SkippingRangeStateTy(Preprocessor &PP) : PP(PP) {}

void beginLexPass() {
if (BeginPtr)
return; // continue skipping a block.

// Initiate a skipping block and adjust the lexer if we already skipped it
// before.
BeginPtr = PP.CurLexer->getBufferLocation();
SkipRangePtr = &PP.RecordedSkippedRanges[BeginPtr];
if (*SkipRangePtr) {
PP.CurLexer->seek(PP.CurLexer->getCurrentBufferOffset() + *SkipRangePtr,
/*IsAtStartOfLine*/ true);
}
}

void endLexPass(const char *Hashptr) {
if (!BeginPtr) {
// Not doing normal lexing.
assert(PP.CurLexer->isDependencyDirectivesLexer());
return;
}

// Finished skipping a block, record the range if it's first time visited.
if (!*SkipRangePtr) {
*SkipRangePtr = Hashptr - BeginPtr;
}
assert(*SkipRangePtr == Hashptr - BeginPtr);
BeginPtr = nullptr;
SkipRangePtr = nullptr;
}
} SkippingRangeState(*this);

while (true) {
if (CurLexer->isDependencyDirectivesLexer()) {
CurLexer->LexDependencyDirectiveTokenWhileSkipping(Tok);
} else {
SkippingRangeState.beginLexPass();
while (true) {
CurLexer->Lex(Tok);

Expand Down Expand Up @@ -467,6 +524,9 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
CurPPLexer->ParsingPreprocessorDirective = true;
if (CurLexer) CurLexer->SetKeepWhitespaceMode(false);

assert(Tok.is(tok::hash));
const char *Hashptr = CurLexer->getBufferLocation() - Tok.getLength();
assert(CurLexer->getSourceLocation(Hashptr) == Tok.getLocation());

// Read the next token, the directive flavor.
LexUnexpandedToken(Tok);
Expand Down Expand Up @@ -539,6 +599,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,

// If we popped the outermost skipping block, we're done skipping!
if (!CondInfo.WasSkipping) {
SkippingRangeState.endLexPass(Hashptr);
// Restore the value of LexingRawMode so that trailing comments
// are handled correctly, if we've reached the outermost block.
CurPPLexer->LexingRawMode = false;
Expand All @@ -556,6 +617,9 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
// as a non-skipping conditional.
PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();

if (!CondInfo.WasSkipping)
SkippingRangeState.endLexPass(Hashptr);

// If this is a #else with a #else before it, report the error.
if (CondInfo.FoundElse)
Diag(Tok, diag::pp_err_else_after_else);
Expand All @@ -581,6 +645,9 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
} else if (Sub == "lif") { // "elif".
PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();

if (!CondInfo.WasSkipping)
SkippingRangeState.endLexPass(Hashptr);

// If this is a #elif with a #else before it, report the error.
if (CondInfo.FoundElse)
Diag(Tok, diag::pp_err_elif_after_else) << PED_Elif;
Expand Down Expand Up @@ -623,6 +690,9 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();
Token DirectiveToken = Tok;

if (!CondInfo.WasSkipping)
SkippingRangeState.endLexPass(Hashptr);

// If this is a #elif with a #else before it, report the error.
if (CondInfo.FoundElse)
Diag(Tok, diag::pp_err_elif_after_else)
Expand Down
23 changes: 18 additions & 5 deletions clang/lib/Lex/PPLexerChange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ bool Preprocessor::EnterSourceFile(FileID FID, ConstSearchDirIterator CurDir,
/// and start lexing tokens from it instead of the current buffer.
void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer,
ConstSearchDirIterator CurDir) {
PreprocessorLexer *PrevPPLexer = CurPPLexer;

// Add the current lexer to the include stack.
if (CurPPLexer || CurTokenLexer)
Expand All @@ -131,8 +132,17 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer,
SrcMgr::CharacteristicKind FileType =
SourceMgr.getFileCharacteristic(CurLexer->getFileLoc());

Callbacks->FileChanged(CurLexer->getFileLoc(),
PPCallbacks::EnterFile, FileType);
FileID PrevFID;
SourceLocation EnterLoc;
if (PrevPPLexer) {
PrevFID = PrevPPLexer->getFileID();
EnterLoc = PrevPPLexer->getSourceLocation();
}
Callbacks->FileChanged(CurLexer->getFileLoc(), PPCallbacks::EnterFile,
FileType, PrevFID);
Callbacks->LexedFileChanged(CurLexer->getFileID(),
PPCallbacks::LexedFileChangeReason::EnterFile,
FileType, PrevFID, EnterLoc);
}
}

Expand Down Expand Up @@ -526,10 +536,13 @@ bool Preprocessor::HandleEndOfFile(Token &Result, SourceLocation EndLoc,

// Notify the client, if desired, that we are in a new source file.
if (Callbacks && !isEndOfMacro && CurPPLexer) {
SourceLocation Loc = CurPPLexer->getSourceLocation();
SrcMgr::CharacteristicKind FileType =
SourceMgr.getFileCharacteristic(CurPPLexer->getSourceLocation());
Callbacks->FileChanged(CurPPLexer->getSourceLocation(),
PPCallbacks::ExitFile, FileType, ExitedFID);
SourceMgr.getFileCharacteristic(Loc);
Callbacks->FileChanged(Loc, PPCallbacks::ExitFile, FileType, ExitedFID);
Callbacks->LexedFileChanged(CurPPLexer->getFileID(),
PPCallbacks::LexedFileChangeReason::ExitFile,
FileType, ExitedFID, Loc);
}

// Restore conditional stack as well as the recorded
Expand Down
2 changes: 1 addition & 1 deletion clang/test/ClangScanDeps/macro-expansions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//--- cdb.json.template
[{
"directory" : "DIR",
"command" : "clang -c DIR/test.cpp -o DIR/test.o",
"command" : "clang -target x86_64-apple-macosx10.7 -c DIR/test.cpp -o DIR/test.o",
"file" : "DIR/test.o"
}]

Expand Down
Loading