Skip to content

Commit 935a07e

Browse files
committed
[clang][deps][lex] Avoid canonicalization of remapped framework directories
In D134923, the scanner introduced canonicalization of framework directories when reporting module map paths in order to increase module sharing. However, if we canonicalize framework directory that plays a role in a VFS remapping, and later try to use that module map to build the module, header lookup can fail. This happens when the module headers are remapped using the original framework path. This patch fixes that. The implementation relies on the fact that the chain of directories in VFS remapping are assigned `DirectoryEntry` objects distinct from their on-disk counterparts. If we detect that case, we avoid the canonicalization. Reviewed By: benlangmuir Differential Revision: https://reviews.llvm.org/D135841
1 parent f9ed86a commit 935a07e

File tree

2 files changed

+100
-3
lines changed

2 files changed

+100
-3
lines changed

clang/lib/Lex/ModuleMap.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,9 +1303,16 @@ ModuleMap::canonicalizeModuleMapPath(SmallVectorImpl<char> &Path) {
13031303
// Canonicalize the directory.
13041304
StringRef CanonicalDir = FM.getCanonicalName(*DirEntry);
13051305
if (CanonicalDir != Dir) {
1306-
bool Done = llvm::sys::path::replace_path_prefix(Path, Dir, CanonicalDir);
1307-
(void)Done;
1308-
assert(Done && "Path should always start with Dir");
1306+
auto CanonicalDirEntry = FM.getDirectory(CanonicalDir);
1307+
// Only use the canonicalized path if it resolves to the same entry as the
1308+
// original. This is not true if there's a VFS overlay on top of a FS where
1309+
// the directory is a symlink. The overlay would not remap the target path
1310+
// of the symlink to the same directory entry in that case.
1311+
if (CanonicalDirEntry && *CanonicalDirEntry == *DirEntry) {
1312+
bool Done = llvm::sys::path::replace_path_prefix(Path, Dir, CanonicalDir);
1313+
(void)Done;
1314+
assert(Done && "Path should always start with Dir");
1315+
}
13091316
}
13101317

13111318
// In theory, the filename component should also be canonicalized if it
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// This test checks that we're not canonicalizing framework directories that
2+
// play a role in VFS remapping. This could lead header search to fail when
3+
// building that module.
4+
5+
// RUN: rm -rf %t
6+
// RUN: split-file %s %t
7+
8+
// REQUIRES: shell
9+
10+
// RUN: mkdir -p %t/frameworks-symlink
11+
// RUN: ln -s %t/frameworks/FW.framework %t/frameworks-symlink/FW.framework
12+
13+
// RUN: mkdir -p %t/copy
14+
// RUN: cp %t/frameworks/FW.framework/Headers/FW.h %t/copy
15+
// RUN: cp %t/frameworks/FW.framework/Headers/Header.h %t/copy
16+
17+
//--- frameworks/FW.framework/Modules/module.modulemap
18+
framework module FW { umbrella header "FW.h" }
19+
//--- frameworks/FW.framework/Headers/FW.h
20+
#import <FW/Header.h>
21+
//--- frameworks/FW.framework/Headers/Header.h
22+
// empty
23+
24+
//--- tu.m
25+
@import FW;
26+
27+
//--- overlay.json.template
28+
{
29+
"version": 0,
30+
"case-sensitive": "false",
31+
"roots": [
32+
{
33+
"contents": [
34+
{
35+
"external-contents": "DIR/copy/Header.h",
36+
"name": "Header.h",
37+
"type": "file"
38+
},
39+
{
40+
"external-contents": "DIR/copy/FW.h",
41+
"name": "FW.h",
42+
"type": "file"
43+
}
44+
],
45+
"name": "DIR/frameworks-symlink/FW.framework/Headers",
46+
"type": "directory"
47+
}
48+
]
49+
}
50+
51+
//--- cdb.json.template
52+
[{
53+
"directory": "DIR",
54+
"file": "DIR/tu.m",
55+
"command": "clang -fmodules -fmodules-cache-path=DIR/cache -ivfsoverlay DIR/overlay.json -F DIR/frameworks-symlink -c DIR/tu.m -o DIR/tu.o -Werror=non-modular-include-in-framework-module"
56+
}]
57+
58+
// RUN: sed -e "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json
59+
// RUN: sed -e "s|DIR|%/t|g" %t/overlay.json.template > %t/overlay.json
60+
61+
// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full > %t/result.json
62+
// RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t
63+
64+
// CHECK: {
65+
// CHECK-NEXT: "modules": [
66+
// CHECK-NEXT: {
67+
// CHECK-NEXT: "clang-module-deps": [],
68+
// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/frameworks-symlink/FW.framework/Modules/module.modulemap",
69+
// CHECK-NEXT: "command-line": [
70+
// CHECK-NEXT: "-cc1",
71+
// CHECK: "-emit-module",
72+
// CHECK-NEXT: "-x",
73+
// CHECK-NEXT: "objective-c",
74+
// CHECK-NEXT: "[[PREFIX]]/frameworks-symlink/FW.framework/Modules/module.modulemap",
75+
// CHECK: ],
76+
// CHECK-NEXT: "context-hash": "{{.*}}",
77+
// CHECK-NEXT: "file-deps": [
78+
// CHECK-NEXT: "[[PREFIX]]/copy/FW.h",
79+
// CHECK-NEXT: "[[PREFIX]]/copy/Header.h",
80+
// CHECK-NEXT: "[[PREFIX]]/frameworks-symlink/FW.framework/Modules/module.modulemap"
81+
// CHECK-NEXT: ],
82+
// CHECK-NEXT: "name": "FW"
83+
// CHECK-NEXT: }
84+
// CHECK-NEXT: ],
85+
// CHECK-NEXT: "translation-units": [
86+
// CHECK: ]
87+
// CHECK: }
88+
89+
// RUN: %deps-to-rsp %t/result.json --module-name=FW > %t/FW.cc1.rsp
90+
// RUN: %clang @%t/FW.cc1.rsp

0 commit comments

Comments
 (0)