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" <[email protected]>
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

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to