From 01eb01c7fd7ad6f569ad4d7bf65b5327ac111955 Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Fri, 20 Jan 2023 11:13:44 +0100 Subject: [PATCH] [clang][Lex] Add back PPCallbacks::FileNotFound This callback was removed with commit 7a124f4859, but we use it downstream in ROOT/Cling to implement handling of a special include syntax. Add back a "safe" version of the callback that only takes the file name and return a bool to silently skip the file. Differential Revision: https://reviews.llvm.org/D142196 --- clang/include/clang/Lex/PPCallbacks.h | 18 ++++++++++++++ clang/lib/Lex/PPDirectives.cpp | 4 +++ clang/unittests/Lex/PPCallbacksTest.cpp | 44 +++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/clang/include/clang/Lex/PPCallbacks.h b/clang/include/clang/Lex/PPCallbacks.h index 2e99fd9..94f96cf 100644 --- a/clang/include/clang/Lex/PPCallbacks.h +++ b/clang/include/clang/Lex/PPCallbacks.h @@ -83,6 +83,16 @@ public: const Token &FilenameTok, SrcMgr::CharacteristicKind FileType) {} + /// Callback invoked whenever the preprocessor cannot find a file for an + /// inclusion directive. + /// + /// \param FileName The name of the file being included, as written in the + /// source code. + /// + /// \returns true to indicate that the preprocessor should skip this file + /// and not issue any diagnostic. + virtual bool FileNotFound(StringRef FileName) { return false; } + /// Callback invoked whenever an inclusion directive of /// any kind (\c \#include, \c \#import, etc.) has been processed, regardless /// of whether the inclusion will actually result in an inclusion. @@ -451,6 +461,14 @@ public: Second->FileSkipped(SkippedFile, FilenameTok, FileType); } + bool FileNotFound(StringRef FileName) override { + bool Skip = First->FileNotFound(FileName); + // Make sure to invoke the second callback, no matter if the first already + // returned true to skip the file. + Skip |= Second->FileNotFound(FileName); + return Skip; + } + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, CharSourceRange FilenameRange, diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index f08d5fe..6ae513d 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -2000,6 +2000,10 @@ OptionalFileEntryRef Preprocessor::LookupHeaderIncludeOrImport( if (File) return File; + // Give the clients a chance to silently skip this include. + if (Callbacks && Callbacks->FileNotFound(Filename)) + return std::nullopt; + if (SuppressIncludeNotFoundError) return std::nullopt; diff --git a/clang/unittests/Lex/PPCallbacksTest.cpp b/clang/unittests/Lex/PPCallbacksTest.cpp index ec71938..b2be40e 100644 --- a/clang/unittests/Lex/PPCallbacksTest.cpp +++ b/clang/unittests/Lex/PPCallbacksTest.cpp @@ -444,6 +444,50 @@ TEST_F(PPCallbacksTest, TrigraphInMacro) { ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range)); } +TEST_F(PPCallbacksTest, FileNotFoundSkipped) { + const char *SourceText = "#include \"skipped.h\"\n"; + + std::unique_ptr SourceBuf = + llvm::MemoryBuffer::getMemBuffer(SourceText); + SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf))); + + HeaderSearch HeaderInfo(std::make_shared(), SourceMgr, + Diags, LangOpts, Target.get()); + TrivialModuleLoader ModLoader; + + DiagnosticConsumer *DiagConsumer = new DiagnosticConsumer; + DiagnosticsEngine FileNotFoundDiags(DiagID, DiagOpts.get(), DiagConsumer); + Preprocessor PP(std::make_shared(), FileNotFoundDiags, + LangOpts, SourceMgr, HeaderInfo, ModLoader, + /*IILookup=*/nullptr, + /*OwnsHeaderSearch=*/false); + PP.Initialize(*Target); + + class FileNotFoundCallbacks : public PPCallbacks { + public: + unsigned int NumCalls = 0; + bool FileNotFound(StringRef FileName) override { + NumCalls++; + return FileName == "skipped.h"; + } + }; + + auto *Callbacks = new FileNotFoundCallbacks; + PP.addPPCallbacks(std::unique_ptr(Callbacks)); + + // Lex source text. + PP.EnterMainSourceFile(); + while (true) { + Token Tok; + PP.Lex(Tok); + if (Tok.is(tok::eof)) + break; + } + + ASSERT_EQ(1u, Callbacks->NumCalls); + ASSERT_EQ(0u, DiagConsumer->getNumErrors()); +} + TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) { const char* Source = "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n"; -- 2.7.4