[clang] [clang] Fix dependency output for #embed (PR #178001)
Mariya Podchishchaeva via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 26 09:31:13 PST 2026
https://github.com/Fznamznon created https://github.com/llvm/llvm-project/pull/178001
When requesting FileEntryRef for embedded file, make sure to not use an absolute path. Instead, create a proper relative path if we're looking for a file from current file.
Fixes https://github.com/llvm/llvm-project/issues/161950
>From 1d3080cb1f4258d3842f6a38241189d3007f2743 Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Mon, 26 Jan 2026 09:19:02 -0800
Subject: [PATCH] [clang] Fix dependency output for #embed
When requesting FileEntryRef for embedded file, make sure to not use an
absolute path. Instead, create a proper relative path if we're looking
for a file from current file.
Fixes https://github.com/llvm/llvm-project/issues/161950
---
clang/docs/ReleaseNotes.rst | 2 +
clang/include/clang/Lex/Preprocessor.h | 11 +--
clang/lib/Lex/PPDirectives.cpp | 30 ++++---
clang/lib/Lex/PPMacroExpansion.cpp | 5 +-
clang/test/Preprocessor/embed_dependencies.c | 7 +-
.../Lex/PPDependencyDirectivesTest.cpp | 81 +++++++++++++++++++
6 files changed, 106 insertions(+), 30 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f0d3d81f14e43..88faf96bc6297 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -194,6 +194,8 @@ Bug Fixes in This Version
- Fix lifetime extension of temporaries in for-range-initializers in templates. (#GH165182)
+- Clang now outputs relative paths of embeds for dependency output. (#GH161950)
+
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 5adc45a19ca79..5fb83eafc6b2a 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -2604,13 +2604,11 @@ class Preprocessor {
/// resource. \p isAngled indicates whether the file reference is for
/// system \#include's or not (i.e. using <> instead of ""). If \p OpenFile
/// is true, the file looked up is opened for reading, otherwise it only
- /// validates that the file exists. Quoted filenames are looked up relative
- /// to \p LookupFromFile if it is nonnull.
+ /// validates that the file exists.
///
/// Returns std::nullopt on failure.
- OptionalFileEntryRef
- LookupEmbedFile(StringRef Filename, bool isAngled, bool OpenFile,
- const FileEntry *LookupFromFile = nullptr);
+ OptionalFileEntryRef LookupEmbedFile(StringRef Filename, bool isAngled,
+ bool OpenFile);
/// Return true if we're in the top-level file, not in a \#include.
bool isInPrimaryFile() const;
@@ -2920,8 +2918,7 @@ class Preprocessor {
SmallVectorImpl<char> &RelativePath, SmallVectorImpl<char> &SearchPath,
ModuleMap::KnownHeader &SuggestedModule, bool isAngled);
// Binary data inclusion
- void HandleEmbedDirective(SourceLocation HashLoc, Token &Tok,
- const FileEntry *LookupFromFile = nullptr);
+ void HandleEmbedDirective(SourceLocation HashLoc, Token &Tok);
void HandleEmbedDirectiveImpl(SourceLocation HashLoc,
const LexEmbedParametersResult &Params,
StringRef BinaryContents, StringRef FileName);
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index b1d5c3636c99b..50611e4c0e07f 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -1187,9 +1187,9 @@ OptionalFileEntryRef Preprocessor::LookupFile(
return std::nullopt;
}
-OptionalFileEntryRef
-Preprocessor::LookupEmbedFile(StringRef Filename, bool isAngled, bool OpenFile,
- const FileEntry *LookupFromFile) {
+OptionalFileEntryRef Preprocessor::LookupEmbedFile(StringRef Filename,
+ bool isAngled,
+ bool OpenFile) {
FileManager &FM = this->getFileManager();
if (llvm::sys::path::is_absolute(Filename)) {
// lookup path or immediately fail
@@ -1215,13 +1215,15 @@ Preprocessor::LookupEmbedFile(StringRef Filename, bool isAngled, bool OpenFile,
SmallString<512> LookupPath;
// Non-angled lookup
if (!isAngled) {
+ OptionalFileEntryRef LookupFromFile = getCurrentFileLexer()->getFileEntry();
if (LookupFromFile) {
// Use file-based lookup.
- StringRef FullFileDir = LookupFromFile->tryGetRealPathName();
- if (!FullFileDir.empty()) {
- SeparateComponents(LookupPath, FullFileDir, Filename, true);
+ SmallString<1024> TmpDir;
+ TmpDir = LookupFromFile->getDir().getName();
+ llvm::sys::path::append(TmpDir, Filename);
+ if (!TmpDir.empty()) {
llvm::Expected<FileEntryRef> ShouldBeEntry = FM.getFileRef(
- LookupPath, OpenFile, /*CacheFailure=*/true, /*IsText=*/false);
+ TmpDir, OpenFile, /*CacheFailure=*/true, /*IsText=*/false);
if (ShouldBeEntry)
return llvm::expectedToOptional(std::move(ShouldBeEntry));
llvm::consumeError(ShouldBeEntry.takeError());
@@ -1487,12 +1489,8 @@ void Preprocessor::HandleDirective(Token &Result) {
return HandleIdentSCCSDirective(Result);
case tok::pp_sccs:
return HandleIdentSCCSDirective(Result);
- case tok::pp_embed: {
- if (PreprocessorLexer *CurrentFileLexer = getCurrentFileLexer())
- if (OptionalFileEntryRef FERef = CurrentFileLexer->getFileEntry())
- return HandleEmbedDirective(Introducer.getLocation(), Result, *FERef);
- return HandleEmbedDirective(Introducer.getLocation(), Result, nullptr);
- }
+ case tok::pp_embed:
+ return HandleEmbedDirective(Introducer.getLocation(), Result);
case tok::pp_assert:
//isExtension = true; // FIXME: implement #assert
break;
@@ -4076,8 +4074,8 @@ void Preprocessor::HandleEmbedDirectiveImpl(
EnterTokenStream(std::move(Toks), TotalNumToks, true, true);
}
-void Preprocessor::HandleEmbedDirective(SourceLocation HashLoc, Token &EmbedTok,
- const FileEntry *LookupFromFile) {
+void Preprocessor::HandleEmbedDirective(SourceLocation HashLoc,
+ Token &EmbedTok) {
// Give the usual extension/compatibility warnings.
if (LangOpts.C23)
Diag(EmbedTok, diag::warn_compat_pp_embed_directive);
@@ -4126,7 +4124,7 @@ void Preprocessor::HandleEmbedDirective(SourceLocation HashLoc, Token &EmbedTok,
return;
OptionalFileEntryRef MaybeFileRef =
- this->LookupEmbedFile(Filename, isAngled, true, LookupFromFile);
+ this->LookupEmbedFile(Filename, isAngled, /*OpenFile=*/ true);
if (!MaybeFileRef) {
// could not find file
if (Callbacks && Callbacks->EmbedFileNotFound(Filename)) {
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index 5efa4b5b3f872..4c07e7ab73ef2 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1287,11 +1287,8 @@ EmbedResult Preprocessor::EvaluateHasEmbed(Token &Tok, IdentifierInfo *II) {
this->GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
// error.
- const FileEntry *LookupFromFile =
- this->getCurrentFileLexer() ? *this->getCurrentFileLexer()->getFileEntry()
- : static_cast<FileEntry *>(nullptr);
OptionalFileEntryRef MaybeFileEntry =
- this->LookupEmbedFile(Filename, isAngled, false, LookupFromFile);
+ this->LookupEmbedFile(Filename, isAngled, false);
if (Callbacks) {
Callbacks->HasEmbed(LParenLoc, Filename, isAngled, MaybeFileEntry);
}
diff --git a/clang/test/Preprocessor/embed_dependencies.c b/clang/test/Preprocessor/embed_dependencies.c
index 4e00dc79ac190..d3a36d973c887 100644
--- a/clang/test/Preprocessor/embed_dependencies.c
+++ b/clang/test/Preprocessor/embed_dependencies.c
@@ -1,4 +1,4 @@
-// RUN: %clang %s -fsyntax-only -std=c23 -M --embed-dir=%S/Inputs -Xclang -verify | FileCheck %s
+// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c23 -MT %s.o --embed-dir=%S/Inputs -dependency-file - | FileCheck %s
// Yes this looks very strange indeed, but the goal is to test that we add
// files referenced by both __has_embed and #embed when we generate
@@ -14,7 +14,8 @@ _Static_assert('b' == data);
#endif
// expected-no-diagnostics
-// CHECK: embed_dependencies.c \
-// CHECK-NEXT: jk.txt \
+// CHECK: embed_dependencies.c.o
+// CHECK-NEXT: embed_dependencies.c
+// CHECK-NEXT: jk.txt
// CHECK-NEXT: Inputs{{[/\\]}}single_byte.txt
diff --git a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp
index 15cc2835e3fb7..0e12e476508f7 100644
--- a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp
+++ b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp
@@ -69,6 +69,33 @@ class IncludeCollector : public PPCallbacks {
}
};
+class EmbedCollector : public PPCallbacks {
+public:
+ Preprocessor &PP;
+ SmallVectorImpl<StringRef> &EmbeddedFiles;
+
+ EmbedCollector(Preprocessor &PP, SmallVectorImpl<StringRef> &EmbeddedFiles)
+ : PP(PP), EmbeddedFiles(EmbeddedFiles) {}
+
+ void EmbedDirective(SourceLocation, StringRef, bool,
+ OptionalFileEntryRef File,
+ const LexEmbedParametersResult &) override {
+ assert(File && "expected to only be called when the file is found");
+ StringRef Filename =
+ llvm::sys::path::remove_leading_dotslash(File->getName());
+ EmbeddedFiles.push_back(Filename);
+ }
+
+ void HasEmbed(SourceLocation, StringRef, bool,
+ OptionalFileEntryRef File) override {
+ if (!File)
+ return;
+ StringRef Filename =
+ llvm::sys::path::remove_leading_dotslash(File->getName());
+ EmbeddedFiles.push_back(Filename);
+ }
+};
+
TEST_F(PPDependencyDirectivesTest, MacroGuard) {
// "head1.h" has a macro guard and should only be included once.
// "head2.h" and "head3.h" have tokens following the macro check, they should
@@ -155,4 +182,58 @@ TEST_F(PPDependencyDirectivesTest, MacroGuard) {
EXPECT_EQ(IncludedFilesSlash, ExpectedIncludes);
}
+
+TEST_F(PPDependencyDirectivesTest, Embed) {
+ auto VFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
+ VFS->setCurrentWorkingDirectory("/source");
+ VFS->addFile("/source/inputs/jk.txt", 0, llvm::MemoryBuffer::getMemBuffer("jk"));
+ VFS->addFile(
+ "/source/inputs/single_byte.txt", 0,
+ llvm::MemoryBuffer::getMemBuffer("a"));
+ VFS->addFile(
+ "/source/inputs/single_byte1.txt", 0,
+ llvm::MemoryBuffer::getMemBuffer("b"));
+ VFS->addFile(
+ "/source/inc/head.h", 0,
+ llvm::MemoryBuffer::getMemBuffer("#embed \"inputs/single_byte.txt\"\n"
+ "extern int foo;\n"));
+ VFS->addFile("main.c", 0,
+ llvm::MemoryBuffer::getMemBuffer(
+ "#include \"inc/head.h\"\n"
+ "#if __has_embed(\"inputs/jk.txt\")\n"
+ "const char arr[] =\n"
+ "#embed \"inputs/single_byte1.txt\"\n"
+ ";\n"
+ "#endif\n"
+ ));
+ FileMgr.setVirtualFileSystem(VFS);
+
+ OptionalFileEntryRef FE;
+ ASSERT_THAT_ERROR(FileMgr.getFileRef("main.c").moveInto(FE),
+ llvm::Succeeded());
+ SourceMgr.setMainFileID(
+ SourceMgr.createFileID(*FE, SourceLocation(), SrcMgr::C_User));
+ PreprocessorOptions PPOpts;
+ HeaderSearchOptions HSOpts;
+ TrivialModuleLoader ModLoader;
+ HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());
+ Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
+ /*IILookup =*/nullptr,
+ /*OwnsHeaderSearch =*/false);
+ PP.Initialize(*Target);
+
+ SmallVector<StringRef> EmbeddedFiles;
+ PP.addPPCallbacks(std::make_unique<EmbedCollector>(PP, EmbeddedFiles));
+ PP.EnterMainSourceFile();
+ PP.LexTokensUntilEOF();
+
+
+ SmallVector<StringRef> ExpectedEmbeds{
+ "inputs/single_byte.txt",
+ "inputs/jk.txt",
+ "inputs/single_byte1.txt",
+ };
+ EXPECT_EQ(EmbeddedFiles, ExpectedEmbeds);
+}
+
} // anonymous namespace
More information about the cfe-commits
mailing list