Skip to content

Commit bde2abd

Browse files
authored
[clang] load umbrella dir headers in sorted order (#156108)
Clang modules sort the umbrella dir headers by name before adding to the module's includes to ensure deterministic output across different file systems. This is insufficient however, as the header search table is also serialized. This includes all the loaded headers by file reference, which are allocated incrementally. To ensure stable output we have to also create the file references in sorted order.
1 parent 8513699 commit bde2abd

File tree

9 files changed

+35
-19
lines changed

9 files changed

+35
-19
lines changed

clang/lib/Frontend/FrontendAction.cpp

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ static std::error_code collectModuleHeaderIncludes(
623623
llvm::sys::path::native(UmbrellaDir->Entry.getName(), DirNative);
624624

625625
llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem();
626-
SmallVector<std::pair<std::string, FileEntryRef>, 8> Headers;
626+
SmallVector<std::pair<std::string, std::string>, 8> HeaderPaths;
627627
for (llvm::vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End;
628628
Dir != End && !EC; Dir.increment(EC)) {
629629
// Check whether this entry has an extension typically associated with
@@ -633,17 +633,6 @@ static std::error_code collectModuleHeaderIncludes(
633633
.Default(false))
634634
continue;
635635

636-
auto Header = FileMgr.getOptionalFileRef(Dir->path());
637-
// FIXME: This shouldn't happen unless there is a file system race. Is
638-
// that worth diagnosing?
639-
if (!Header)
640-
continue;
641-
642-
// If this header is marked 'unavailable' in this module, don't include
643-
// it.
644-
if (ModMap.isHeaderUnavailableInModule(*Header, Module))
645-
continue;
646-
647636
// Compute the relative path from the directory to this file.
648637
SmallVector<StringRef, 16> Components;
649638
auto PathIt = llvm::sys::path::rbegin(Dir->path());
@@ -655,20 +644,33 @@ static std::error_code collectModuleHeaderIncludes(
655644
++It)
656645
llvm::sys::path::append(RelativeHeader, *It);
657646

658-
std::string RelName = RelativeHeader.c_str();
659-
Headers.push_back(std::make_pair(RelName, *Header));
647+
HeaderPaths.push_back(
648+
std::make_pair(Dir->path().str(), RelativeHeader.c_str()));
660649
}
661650

662651
if (EC)
663652
return EC;
664653

665654
// Sort header paths and make the header inclusion order deterministic
666-
// across different OSs and filesystems.
667-
llvm::sort(Headers, llvm::less_first());
668-
for (auto &H : Headers) {
655+
// across different OSs and filesystems. As the header search table
656+
// serialization order depends on the file reference UID, we need to create
657+
// file references in deterministic order too.
658+
llvm::sort(HeaderPaths, llvm::less_first());
659+
for (auto &[Path, RelPath] : HeaderPaths) {
660+
auto Header = FileMgr.getOptionalFileRef(Path);
661+
// FIXME: This shouldn't happen unless there is a file system race. Is
662+
// that worth diagnosing?
663+
if (!Header)
664+
continue;
665+
666+
// If this header is marked 'unavailable' in this module, don't include
667+
// it.
668+
if (ModMap.isHeaderUnavailableInModule(*Header, Module))
669+
continue;
670+
669671
// Include this header as part of the umbrella directory.
670-
Module->addTopHeader(H.second);
671-
addHeaderInclude(H.first, Includes, LangOpts, Module->IsExternC);
672+
Module->addTopHeader(*Header);
673+
addHeaderInclude(RelPath, Includes, LangOpts, Module->IsExternC);
672674
}
673675
}
674676

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module x {
2+
umbrella "umbrella"
3+
}

clang/test/Modules/Inputs/umbrella_header_order/umbrella/A.h

Whitespace-only changes.

clang/test/Modules/Inputs/umbrella_header_order/umbrella/B.h

Whitespace-only changes.

clang/test/Modules/Inputs/umbrella_header_order/umbrella/C.h

Whitespace-only changes.

clang/test/Modules/Inputs/umbrella_header_order/umbrella/D.h

Whitespace-only changes.

clang/test/Modules/Inputs/umbrella_header_order/umbrella/E.h

Whitespace-only changes.

clang/test/Modules/Inputs/umbrella_header_order/umbrella/F.h

Whitespace-only changes.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: cd %S
2+
// RUN: %clang_cc1 -fmodules -fno-implicit-modules -x objective-c -fmodule-name=x -emit-module Inputs/umbrella_header_order/module.modulemap -o %t/mod.pcm
3+
// RUN: llvm-bcanalyzer --dump --disable-histogram %t/mod.pcm | FileCheck %s
4+
5+
// CHECK: <INPUT_FILE abbrevid=4 op0=1 op1=36 op2=0 op3=0 op4=0 op5=1 op6=1 op7=16/> blob data = 'module.modulemap'
6+
// CHECK: <INPUT_FILE abbrevid=4 op0=2 op1=0 op2=0 op3=0 op4=0 op5=0 op6=0 op7=12/> blob data = 'umbrella{{[/\\]}}A.h'
7+
// CHECK: <INPUT_FILE abbrevid=4 op0=3 op1=0 op2=0 op3=0 op4=0 op5=0 op6=0 op7=12/> blob data = 'umbrella{{[/\\]}}B.h'
8+
// CHECK: <INPUT_FILE abbrevid=4 op0=4 op1=0 op2=0 op3=0 op4=0 op5=0 op6=0 op7=12/> blob data = 'umbrella{{[/\\]}}C.h'
9+
// CHECK: <INPUT_FILE abbrevid=4 op0=5 op1=0 op2=0 op3=0 op4=0 op5=0 op6=0 op7=12/> blob data = 'umbrella{{[/\\]}}D.h'
10+
// CHECK: <INPUT_FILE abbrevid=4 op0=6 op1=0 op2=0 op3=0 op4=0 op5=0 op6=0 op7=12/> blob data = 'umbrella{{[/\\]}}E.h'
11+
// CHECK: <INPUT_FILE abbrevid=4 op0=7 op1=0 op2=0 op3=0 op4=0 op5=0 op6=0 op7=12/> blob data = 'umbrella{{[/\\]}}F.h'

0 commit comments

Comments
 (0)