Skip to content

Commit 7c8f4ea

Browse files
committed
WIP
1 parent b775b72 commit 7c8f4ea

File tree

11 files changed

+450
-122
lines changed

11 files changed

+450
-122
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4563,6 +4563,9 @@ def iapinotes_modules : JoinedOrSeparate<["-"], "iapinotes-modules">, Group<clan
45634563
def idirafter : JoinedOrSeparate<["-"], "idirafter">, Group<clang_i_Group>,
45644564
Visibility<[ClangOption, CC1Option]>,
45654565
HelpText<"Add directory to AFTER include search path">;
4566+
def iexternal : JoinedOrSeparate<["-"], "iexternal">, Group<clang_i_Group>,
4567+
Visibility<[ClangOption, CC1Option]>,
4568+
HelpText<"Add directory to external include search path">, MetaVarName<"<directory>">;
45664569
def iframework : JoinedOrSeparate<["-"], "iframework">, Group<clang_i_Group>,
45674570
Visibility<[ClangOption, CC1Option]>,
45684571
HelpText<"Add directory to SYSTEM framework search path">;
@@ -8426,7 +8429,7 @@ def _SLASH_diagnostics_classic : CLFlag<"diagnostics:classic">,
84268429
def _SLASH_D : CLJoinedOrSeparate<"D", [CLOption, DXCOption]>,
84278430
HelpText<"Define macro">, MetaVarName<"<macro[=value]>">, Alias<D>;
84288431
def _SLASH_E : CLFlag<"E">, HelpText<"Preprocess to stdout">, Alias<E>;
8429-
def _SLASH_external_COLON_I : CLJoinedOrSeparate<"external:I">, Alias<isystem>,
8432+
def _SLASH_external_COLON_I : CLJoinedOrSeparate<"external:I">, Alias<iexternal>,
84308433
HelpText<"Add directory to include search path with warnings suppressed">,
84318434
MetaVarName<"<dir>">;
84328435
def _SLASH_fp_contract : CLFlag<"fp:contract">, HelpText<"">, Alias<ffp_contract>, AliasArgs<["on"]>;

clang/include/clang/Lex/HeaderSearchOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ enum IncludeDirGroup {
3838
/// Like Angled, but marks header maps used when building frameworks.
3939
IndexHeaderMap,
4040

41+
/// Like Angled, but marks system directories while retaining relative order
42+
/// with user directories.
43+
External,
44+
4145
/// Like Angled, but marks system directories.
4246
System,
4347

clang/lib/Driver/Driver.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1298,7 +1298,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
12981298

12991299
// Check for missing include directories.
13001300
if (!Diags.isIgnored(diag::warn_missing_include_dirs, SourceLocation())) {
1301-
for (auto IncludeDir : Args.getAllArgValues(options::OPT_I_Group)) {
1301+
for (auto IncludeDir :
1302+
Args.getAllArgValues(options::OPT_I_Group, options::OPT_iexternal)) {
13021303
if (!VFS->exists(IncludeDir))
13031304
Diag(diag::warn_missing_include_dirs) << IncludeDir;
13041305
}

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1185,7 +1185,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
11851185
Args.addAllArgs(CmdArgs,
11861186
{options::OPT_D, options::OPT_U, options::OPT_I_Group,
11871187
options::OPT_F, options::OPT_index_header_map,
1188-
options::OPT_embed_dir_EQ});
1188+
options::OPT_embed_dir_EQ,
1189+
options::OPT_iexternal});
11891190

11901191
// Add -Wp, and -Xpreprocessor if using the preprocessor.
11911192

clang/lib/Driver/ToolChains/MSVC.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,8 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
660660
return false;
661661
};
662662

663+
// FIXME: /external:env won't cause user paths already present in the
664+
// FIXME: search path to be dropped like /external:I does.
663665
// Add %INCLUDE%-like dirs via /external:env: flags.
664666
for (const auto &Var :
665667
DriverArgs.getAllArgValues(options::OPT__SLASH_external_env)) {

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3194,8 +3194,10 @@ static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
31943194
auto It = Opts.UserEntries.begin();
31953195
auto End = Opts.UserEntries.end();
31963196

3197-
// Add -I..., -F..., and -index-header-map options in order.
3198-
for (; It < End && Matches(*It, {frontend::IndexHeaderMap, frontend::Angled},
3197+
// Add the -I..., -F..., -index-header-map, and MSVC /external:I options
3198+
// in order.
3199+
for (; It < End && Matches(*It, {frontend::IndexHeaderMap, frontend::Angled,
3200+
frontend::External},
31993201
std::nullopt, true);
32003202
++It) {
32013203
OptSpecifier Opt = [It, Matches]() {
@@ -3207,13 +3209,15 @@ static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
32073209
return OPT_F;
32083210
if (Matches(*It, frontend::Angled, false, true))
32093211
return OPT_I;
3212+
if (Matches(*It, frontend::External, std::nullopt, true))
3213+
return OPT_iexternal;
32103214
llvm_unreachable("Unexpected HeaderSearchOptions::Entry.");
32113215
}();
32123216

32133217
if (It->Group == frontend::IndexHeaderMap)
32143218
GenerateArg(Consumer, OPT_index_header_map);
32153219
GenerateArg(Consumer, Opt, It->Path);
3216-
};
3220+
}
32173221

32183222
// Note: some paths that came from "[-iprefix=xx] -iwithprefixbefore=yy" may
32193223
// have already been generated as "-I[xx]yy". If that's the case, their
@@ -3323,8 +3327,8 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
33233327
llvm::CachedHashString(MacroDef.split('=').first));
33243328
}
33253329

3326-
// Add -I..., -F..., and -index-header-map options in order.
3327-
bool IsIndexHeaderMap = false;
3330+
// Add the -I..., -F..., -index-header-map, and MSVC /external:I options
3331+
// options in order.
33283332
bool IsSysrootSpecified =
33293333
Args.hasArg(OPT__sysroot_EQ) || Args.hasArg(OPT_isysroot);
33303334

@@ -3343,15 +3347,19 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
33433347
return A->getValue();
33443348
};
33453349

3346-
for (const auto *A : Args.filtered(OPT_I, OPT_F, OPT_index_header_map)) {
3350+
bool IsIndexHeaderMap = false;
3351+
for (const auto *A : Args.filtered(OPT_I, OPT_F, OPT_index_header_map,
3352+
OPT_iexternal)) {
3353+
frontend::IncludeDirGroup Group =
3354+
IsIndexHeaderMap ? frontend::IndexHeaderMap : frontend::Angled;
3355+
33473356
if (A->getOption().matches(OPT_index_header_map)) {
33483357
// -index-header-map applies to the next -I or -F.
33493358
IsIndexHeaderMap = true;
33503359
continue;
33513360
}
3352-
3353-
frontend::IncludeDirGroup Group =
3354-
IsIndexHeaderMap ? frontend::IndexHeaderMap : frontend::Angled;
3361+
if (A->getOption().matches(OPT_iexternal))
3362+
Group = frontend::External;
33553363

33563364
bool IsFramework = A->getOption().matches(OPT_F);
33573365
Opts.AddPath(PrefixHeaderPath(A, IsFramework), Group, IsFramework,

clang/lib/Lex/InitHeaderSearch.cpp

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,8 @@ void InitHeaderSearch::AddDefaultIncludePaths(
366366
}
367367

368368
/// If there are duplicate directory entries in the specified search list,
369-
/// remove the later (dead) ones. Returns the number of non-system headers
370-
/// removed, which is used to update NumAngled.
369+
/// identify and remove the ones to be ignored and issue a diagnostic.
370+
/// Returns the number of non-system search paths emoved.
371371
static unsigned RemoveDuplicates(const LangOptions &Lang,
372372
std::vector<DirectoryLookupInfo> &SearchList,
373373
unsigned First, bool Verbose) {
@@ -377,41 +377,43 @@ static unsigned RemoveDuplicates(const LangOptions &Lang,
377377
unsigned NonSystemRemoved = 0;
378378
for (unsigned i = First; i != SearchList.size(); ++i) {
379379
unsigned DirToRemove = i;
380+
bool NonSystemDirRemoved = false;
380381

381382
const DirectoryLookup &CurEntry = SearchList[i].Lookup;
382383

384+
// If the current entry is for a previously unseen location, cache it and
385+
// continue with the next entry.
383386
if (CurEntry.isNormalDir()) {
384-
// If this isn't the first time we've seen this dir, remove it.
385387
if (SeenDirs.insert(CurEntry.getDir()).second)
386388
continue;
387389
} else if (CurEntry.isFramework()) {
388-
// If this isn't the first time we've seen this framework dir, remove it.
389390
if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir()).second)
390391
continue;
391392
} else {
392393
assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
393-
// If this isn't the first time we've seen this headermap, remove it.
394394
if (SeenHeaderMaps.insert(CurEntry.getHeaderMap()).second)
395395
continue;
396396
}
397397

398-
// When not in MSVC compatibility mode, if we have a normal
399-
// #include dir/framework/headermap that is shadowed later in the chain by
400-
// a system include location, we actually want to ignore the user's request
401-
// and drop the user dir... keeping the system dir. This is weird, but
402-
// required to emulate GCC's search path correctly.
398+
// Pruning of duplicate search locations is intended to emulate the behavior
399+
// exhibited by GCC (by default) or MSVC (in Microsoft compatibility mode)
400+
// to ensure that #include and #include_next directives produce the same
401+
// results as these other compilers.
403402
//
404-
// Since dupes of system dirs are rare, just rescan to find the original
405-
// that we're nuking instead of using a DenseMap.
406-
if (!Lang.MSVCCompat && CurEntry.getDirCharacteristic() != SrcMgr::C_User) {
407-
// Find the dir that this is the same of.
403+
// GCC and MSVC both prune duplicate user search locations that follow a
404+
// previous matching user search location. Both compilers also prune user
405+
// search locations that are also present as system search locations
406+
// regardless of the order in which they appear. The compilers differ with
407+
// respect to pruning system search locations that duplicate a previous
408+
// system search location; GCC preserves the first such occurences while
409+
// MSVC preserves the last one.
410+
if (CurEntry.getDirCharacteristic() != SrcMgr::C_User) {
411+
// Find the matching search entry.
408412
unsigned FirstDir;
409-
for (FirstDir = First;; ++FirstDir) {
410-
assert(FirstDir != i && "Didn't find dupe?");
411-
413+
for (FirstDir = First; FirstDir < i; ++FirstDir) {
412414
const DirectoryLookup &SearchEntry = SearchList[FirstDir].Lookup;
413415

414-
// If these are different lookup types, then they can't be the dupe.
416+
// Different lookup types are not considered duplicate entries.
415417
if (SearchEntry.getLookupType() != CurEntry.getLookupType())
416418
continue;
417419

@@ -428,21 +430,34 @@ static unsigned RemoveDuplicates(const LangOptions &Lang,
428430
if (isSame)
429431
break;
430432
}
433+
assert(FirstDir < i && "Expected duplicate search location not found");
431434

432-
// If the first dir in the search path is a non-system dir, zap it
433-
// instead of the system one.
434-
if (SearchList[FirstDir].Lookup.getDirCharacteristic() == SrcMgr::C_User)
435+
if (Lang.MSVCCompat) {
436+
// In Microsoft compatibility mode, a later system search location entry
437+
// suppresses a previous user or system search location.
435438
DirToRemove = FirstDir;
439+
if (SearchList[FirstDir].Lookup.getDirCharacteristic() ==
440+
SrcMgr::C_User)
441+
NonSystemDirRemoved = true;
442+
} else {
443+
// In GCC compatibility mode, a later system search location entry
444+
// suppresses a previous user search location.
445+
if (SearchList[FirstDir].Lookup.getDirCharacteristic() ==
446+
SrcMgr::C_User) {
447+
DirToRemove = FirstDir;
448+
NonSystemDirRemoved = true;
449+
}
450+
}
436451
}
437452

438453
if (Verbose) {
439454
llvm::errs() << "ignoring duplicate directory \""
440455
<< CurEntry.getName() << "\"\n";
441-
if (DirToRemove != i)
456+
if (NonSystemDirRemoved)
442457
llvm::errs() << " as it is a non-system directory that duplicates "
443458
<< "a system directory\n";
444459
}
445-
if (DirToRemove != i)
460+
if (NonSystemDirRemoved)
446461
++NonSystemRemoved;
447462

448463
// This is reached if the current entry is a duplicate. Remove the
@@ -490,7 +505,8 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
490505
unsigned NumQuoted = SearchList.size();
491506

492507
for (auto &Include : IncludePath)
493-
if (Include.Group == Angled || Include.Group == IndexHeaderMap)
508+
if (Include.Group == Angled || Include.Group == IndexHeaderMap ||
509+
Include.Group == External)
494510
SearchList.push_back(Include);
495511

496512
RemoveDuplicates(Lang, SearchList, NumQuoted, Verbose);

0 commit comments

Comments
 (0)