[clang] Fix dependency output for #embed (#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
This commit is contained in:
parent
23f9e42480
commit
485e69bc52
@ -222,6 +222,8 @@ Bug Fixes in This Version
|
||||
- Fixed a preprocessor crash in ``__has_cpp_attribute`` on incomplete scoped attributes. (#GH178098)
|
||||
- Fixes an assertion failure when evaluating ``__underlying_type`` on enum redeclarations. (#GH177943)
|
||||
|
||||
- Clang now outputs relative paths of embeds for dependency output. (#GH161950)
|
||||
|
||||
Bug Fixes to Compiler Builtins
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@ -2604,13 +2604,11 @@ public:
|
||||
/// 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 @@ private:
|
||||
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);
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -69,6 +69,33 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
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,54 @@ 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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user