Skip to content

Commit 346c969

Browse files
committed
[Clang] Match MSVC handling of duplicate header search paths in Microsoft compatibility modes.
Clang has historically matched GCC's behavior for header search path order and pruning of duplicate paths. That traditional behavior is to order user search paths before system search paths, to ignore user search paths that duplicate a (later) system search path, and to ignore search paths that duplicate an earlier search path of the same user/system kind. This differs from MSVC and can result in inconsistent header file resolution for `#include` directives. MSVC orders header search paths as follows: 1) Paths specified by the `/I` and `/external:I` options are processed in the order that they appear. Paths specified by `/I` that duplicate a path specified by `/external:I` are ignored regardless of the order of the options. Paths specified by `/I` that duplicate a path from a prior `/I` option are ignored. Paths specified by `/external:I` that duplicate a path from a later `/external:I` option are ignored. 2) Paths specified by `/external:env` are processed in the order that they appear. Paths that duplicate a path from a `/I` or `/external:I` option are ignored regardless of the order of the options. Paths that duplicate a path from a prior `/external:env` option or an earlier path from the same `/external:env` option are ignored. 3) Paths specified by the `INCLUDE` environment variable are processed in the order they appear. Paths that duplicate a path from a `/I`, `/external:I`, or `/external:env` option are ignored. Paths that duplicate an earlier path in the `INCLUDE` environment variable are ignored. 4) Paths specified by the `EXTERNAL_INCLUDE` environment variable are processed in the order they appear. Paths that duplicate a path from a `/I`, `/external:I`, or `/external:env` option are ignored. Paths that duplicate a path from the `INCLUDE` environment variable are ignored. Paths that duplicate an earlier path in the `EXTERNAL_INCLUDE environment variable are ignored. Prior to this change, Clang handled the `/external:I` and `/external:env` options and the paths present in the `INCLUDE` and `EXTERNAL_INCLUDE` environment variables as though they were specified with the `-isystem` option. The GCC behavior described above then lead to a command line such as `/external:I dir1 /Idir2` having a header search order of `dir2` followed by `dir1`; contrary to MSVC behavior. This change adds support for the MSVC external path concept for both the `clang` and `clang-cl` drivers with the following option syntax. These options match the MSVC behavior described above for both drivers. clang clang-cl -------------------- ------------------- -iexternal <dir> /external:I <dir> -iexternal-env=<ENV> /external:env:<ENV> Paths specified by these options are still treated as system paths. That is, whether warnings are issued in header files found via these paths remains subject to use of the `-Wsystem-headers` and `-Wno-system-headers` options. In the future, it would make sense to add a separate option that matches the MSVC `/external:Wn` option to control such warnings. The MSVC behavior described above implies that (system) paths present in the `INCLUDE` and `EXTERNAL_INCLUDE` environment variables do not suppress matching user paths specified via `/I`. This contrasts with GCC's behavior of suppressing user paths that match a system path regardless of how each is specified. Since the `clang-cl` driver maps paths from the `INCLUDE` and `EXTERNAL_INCLUDE` environment variable to `-internal-isystem`, matching MSVC behavior requires suppressing that aspect of the GCC behavior. With this change, system paths will no longer suppress user paths when the `-fms-compatibility` option is explicitly or implicitly enabled. This will affect header search path ordering for options like `-isystem` when duplicate user paths are present. Should motivation arise for preserving such suppression of user paths when compiling with `-fms-compatibility` enabled, it would make sense to introduce a new option for the `clang-cl` driver to map paths in these environment variabless to that would match MSVC behavior without impacting other system path options.
1 parent 680901e commit 346c969

File tree

16 files changed

+1019
-127
lines changed

16 files changed

+1019
-127
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,44 @@ Windows Support
681681
When `-fms-compatibility-version=18.00` or prior is set on the command line this Microsoft extension is still
682682
allowed as VS2013 and prior allow it.
683683

684+
- Clang now matches MSVC behavior regarding the handling of duplicate header
685+
search paths when running in Microsoft compatibility mode. Historically,
686+
Clang has mimicked gcc behavior in which user search paths are ordered before
687+
system search paths, user search paths that duplicate a (later) system search
688+
path are ignored, and search paths that duplicate an earlier search path of
689+
the same user/system kind are ignored. This ordering is not compatible with
690+
the ordering that MSVC uses when paths are duplicated across ``/I`` options
691+
and the ``INCLUDE`` environment variable.
692+
693+
The order that MSVC uses and that Clang now replicates when the
694+
``-fms-compatibility`` option is enabled follows.
695+
696+
- Paths specified by the ``/I`` and ``/external:I`` options are processed in
697+
the order that they appear. Paths specified by ``/I`` that duplicate a path
698+
specified by ``/external:I`` are ignored regardless of the order of the
699+
options. Paths specified by ``/I`` that duplicate a path from a prior ``/I``
700+
option are ignored. Paths specified by ``/external:I`` that duplicate a
701+
path from a later ``/external:I`` option are ignored.
702+
703+
- Paths specified by ``/external:env`` are processed in the order that they
704+
appear. Paths that duplicate a path from a ``/I`` or ``/external:I`` option
705+
are ignored regardless of the order of the options. Paths that duplicate a
706+
path from a prior ``/external:env`` option or an earlier path from the same
707+
``/external:env`` option are ignored.
708+
709+
- Paths specified by the ``INCLUDE`` environment variable are processed in
710+
the order they appear. Paths that duplicate a path from a ``/I``,
711+
``/external:I``, or ``/external:env`` option are ignored. Paths that
712+
duplicate an earlier path in the ``INCLUDE`` environment variable are
713+
ignored.
714+
715+
- Paths specified by the ``EXTERNAL_INCLUDE`` environment variable are
716+
processed in the order they appear. Paths that duplicate a path from a
717+
``/I``, ``/external:I``, or ``/external:env`` option are ignored. Paths that
718+
duplicate a path from the ``INCLUDE`` environment variable are ignored.
719+
Paths that duplicate an earlier path in the ``EXTERNAL_INCLUDE``
720+
environment variable are ignored.
721+
684722
LoongArch Support
685723
^^^^^^^^^^^^^^^^^
686724

clang/include/clang/Driver/Options.td

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4579,6 +4579,15 @@ def iapinotes_modules : JoinedOrSeparate<["-"], "iapinotes-modules">, Group<clan
45794579
def idirafter : JoinedOrSeparate<["-"], "idirafter">, Group<clang_i_Group>,
45804580
Visibility<[ClangOption, CC1Option]>,
45814581
HelpText<"Add directory to AFTER include search path">;
4582+
def iexternal : Separate<["-"], "iexternal">, Group<clang_i_Group>,
4583+
Visibility<[ClangOption, CC1Option]>,
4584+
HelpText<"Add directory to include search path with warnings suppressed">, MetaVarName<"<dir>">;
4585+
def iexternal_after : Separate<["-"], "iexternal-after">, Group<clang_i_Group>,
4586+
Visibility<[ClangOption, CC1Option]>,
4587+
HelpText<"Add directory to include search path with warnings suppressed">, MetaVarName<"<dir>">;
4588+
def iexternal_env_EQ : Joined<["-"], "iexternal-env=">, Group<clang_i_Group>,
4589+
Visibility<[ClangOption]>,
4590+
HelpText<"Add dirs in env var <var> to include search path with warnings suppressed">, MetaVarName<"<var>">;
45824591
def iframework : JoinedOrSeparate<["-"], "iframework">, Group<clang_i_Group>,
45834592
Visibility<[ClangOption, CC1Option]>,
45844593
HelpText<"Add directory to SYSTEM framework search path">;
@@ -8460,9 +8469,12 @@ def _SLASH_diagnostics_classic : CLFlag<"diagnostics:classic">,
84608469
def _SLASH_D : CLJoinedOrSeparate<"D", [CLOption, DXCOption]>,
84618470
HelpText<"Define macro">, MetaVarName<"<macro[=value]>">, Alias<D>;
84628471
def _SLASH_E : CLFlag<"E">, HelpText<"Preprocess to stdout">, Alias<E>;
8463-
def _SLASH_external_COLON_I : CLJoinedOrSeparate<"external:I">, Alias<isystem>,
8472+
def _SLASH_external_COLON_I : CLJoinedOrSeparate<"external:I">, Alias<iexternal>,
84648473
HelpText<"Add directory to include search path with warnings suppressed">,
84658474
MetaVarName<"<dir>">;
8475+
def _SLASH_external_env : CLJoined<"external:env:">, Alias<iexternal_env_EQ>,
8476+
HelpText<"Add dirs in env var <var> to include search path with warnings suppressed">,
8477+
MetaVarName<"<var>">;
84668478
def _SLASH_fp_contract : CLFlag<"fp:contract">, HelpText<"">, Alias<ffp_contract>, AliasArgs<["on"]>;
84678479
def _SLASH_fp_except : CLFlag<"fp:except">, HelpText<"">, Alias<ffp_exception_behavior_EQ>, AliasArgs<["strict"]>;
84688480
def _SLASH_fp_except_ : CLFlag<"fp:except-">, HelpText<"">, Alias<ffp_exception_behavior_EQ>, AliasArgs<["ignore"]>;
@@ -8692,9 +8704,6 @@ def _SLASH_volatile_Group : OptionGroup<"</volatile group>">,
86928704
def _SLASH_EH : CLJoined<"EH">, HelpText<"Set exception handling model">;
86938705
def _SLASH_EP : CLFlag<"EP">,
86948706
HelpText<"Disable linemarker output and preprocess to stdout">;
8695-
def _SLASH_external_env : CLJoined<"external:env:">,
8696-
HelpText<"Add dirs in env var <var> to include search path with warnings suppressed">,
8697-
MetaVarName<"<var>">;
86988707
def _SLASH_FA : CLJoined<"FA">,
86998708
HelpText<"Output assembly code file during compilation">;
87008709
def _SLASH_Fa : CLJoined<"Fa">,

clang/include/clang/Driver/ToolChain.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ class ToolChain {
224224
/// \return The subdirectory path if it exists.
225225
std::optional<std::string> getTargetSubDirPath(StringRef BaseDir) const;
226226

227+
public:
227228
/// \name Utilities for implementing subclasses.
228229
///@{
229230
static void addSystemInclude(const llvm::opt::ArgList &DriverArgs,
@@ -239,12 +240,20 @@ class ToolChain {
239240
static void addSystemIncludes(const llvm::opt::ArgList &DriverArgs,
240241
llvm::opt::ArgStringList &CC1Args,
241242
ArrayRef<StringRef> Paths);
243+
static bool addSystemIncludesFromEnv(const llvm::opt::ArgList &DriverArgs,
244+
llvm::opt::ArgStringList &CC1Args,
245+
StringRef Var);
246+
static void addExternalAfterIncludes(const llvm::opt::ArgList &DriverArgs,
247+
llvm::opt::ArgStringList &CC1Args,
248+
ArrayRef<StringRef> Paths);
249+
static bool addExternalIncludesFromEnv(const llvm::opt::ArgList &DriverArgs,
250+
llvm::opt::ArgStringList &CC1Args,
251+
StringRef Var);
242252

243253
static std::string concat(StringRef Path, const Twine &A, const Twine &B = "",
244254
const Twine &C = "", const Twine &D = "");
245255
///@}
246256

247-
public:
248257
virtual ~ToolChain();
249258

250259
// Accessors

clang/include/clang/Lex/HeaderSearchOptions.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ 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. This group is intended to match the semantics of
43+
/// the MSVC /external:I option.
44+
External,
45+
46+
/// Like External, but searched after other external directories but before
47+
/// system directories. This group is intended to match the semantics of the
48+
/// MSVC /external:env option.
49+
ExternalAfter,
50+
4151
/// Like Angled, but marks system directories.
4252
System,
4353

clang/lib/Driver/Driver.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1296,7 +1296,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
12961296
if (VFS->setCurrentWorkingDirectory(WD->getValue()))
12971297
Diag(diag::err_drv_unable_to_set_working_directory) << WD->getValue();
12981298

1299-
// Check for missing include directories.
1299+
// Check for missing include directories. Diagnostics should not be issued
1300+
// for directories specified with -iexternal, -iexternal-env=, or
1301+
// -iexternal-after since those options may be used to specify partial paths.
13001302
if (!Diags.isIgnored(diag::warn_missing_include_dirs, SourceLocation())) {
13011303
for (auto IncludeDir : Args.getAllArgValues(options::OPT_I_Group)) {
13021304
if (!VFS->exists(IncludeDir))

clang/lib/Driver/ToolChain.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,51 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs,
12671267
}
12681268
}
12691269

1270+
/// Utility function to add a list of ';' delimited directories specified in
1271+
/// an environment variable to the system include path list for CC1. Returns
1272+
/// true if the variable is set and not empty.
1273+
/*static*/ bool ToolChain::addSystemIncludesFromEnv(const ArgList &DriverArgs,
1274+
ArgStringList &CC1Args,
1275+
StringRef Var) {
1276+
if (auto Val = llvm::sys::Process::GetEnv(Var)) {
1277+
SmallVector<StringRef, 8> Dirs;
1278+
StringRef(*Val).split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
1279+
if (!Dirs.empty()) {
1280+
addSystemIncludes(DriverArgs, CC1Args, Dirs);
1281+
return true;
1282+
}
1283+
}
1284+
return false;
1285+
}
1286+
1287+
/// Utility function to add a list of directories to the end of the external
1288+
/// include path list for CC1.
1289+
/*static*/ void ToolChain::addExternalAfterIncludes(const ArgList &DriverArgs,
1290+
ArgStringList &CC1Args,
1291+
ArrayRef<StringRef> Paths) {
1292+
for (const auto &Path : Paths) {
1293+
CC1Args.push_back("-iexternal-after");
1294+
CC1Args.push_back(DriverArgs.MakeArgString(Path));
1295+
}
1296+
}
1297+
1298+
/// Utility function to add a list of ';' delimited directories specified in
1299+
/// an environment variable to the external include path list for CC1. Returns
1300+
/// true if the variable is set and not empty.
1301+
/*static*/ bool ToolChain::addExternalIncludesFromEnv(const ArgList &DriverArgs,
1302+
ArgStringList &CC1Args,
1303+
StringRef Var) {
1304+
if (auto Val = llvm::sys::Process::GetEnv(Var)) {
1305+
SmallVector<StringRef, 8> Dirs;
1306+
StringRef(*Val).split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
1307+
if (!Dirs.empty()) {
1308+
addExternalAfterIncludes(DriverArgs, CC1Args, Dirs);
1309+
return true;
1310+
}
1311+
}
1312+
return false;
1313+
}
1314+
12701315
/*static*/ std::string ToolChain::concat(StringRef Path, const Twine &A,
12711316
const Twine &B, const Twine &C,
12721317
const Twine &D) {

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,13 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
11961196
} else if (A->getOption().matches(options::OPT_ibuiltininc)) {
11971197
// This is used only by the driver. No need to pass to cc1.
11981198
continue;
1199+
} else if (A->getOption().matches(options::OPT_iexternal)) {
1200+
// This option has to retain relative order with other -I options.
1201+
continue;
1202+
} else if (A->getOption().matches(options::OPT_iexternal_env_EQ)) {
1203+
A->claim();
1204+
ToolChain::addExternalIncludesFromEnv(Args, CmdArgs, A->getValue());
1205+
continue;
11991206
}
12001207

12011208
// Not translated, render as usual.
@@ -1206,7 +1213,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
12061213
Args.addAllArgs(CmdArgs,
12071214
{options::OPT_D, options::OPT_U, options::OPT_I_Group,
12081215
options::OPT_F, options::OPT_index_header_map,
1209-
options::OPT_embed_dir_EQ});
1216+
options::OPT_iexternal, options::OPT_embed_dir_EQ});
12101217

12111218
// Add -Wp, and -Xpreprocessor if using the preprocessor.
12121219

@@ -8663,7 +8670,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
86638670
(void)Args.hasArg(options::OPT_force__cpusubtype__ALL);
86648671

86658672
// Pass along any -I options so we get proper .include search paths.
8666-
Args.AddAllArgs(CmdArgs, options::OPT_I_Group);
8673+
Args.addAllArgs(CmdArgs, {options::OPT_I_Group, options::OPT_iexternal});
86678674

86688675
// Pass along any --embed-dir or similar options so we get proper embed paths.
86698676
Args.AddAllArgs(CmdArgs, options::OPT_embed_dir_EQ);

clang/lib/Driver/ToolChains/MSVC.cpp

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -648,24 +648,6 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
648648
for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc))
649649
addSystemInclude(DriverArgs, CC1Args, Path);
650650

651-
auto AddSystemIncludesFromEnv = [&](StringRef Var) -> bool {
652-
if (auto Val = llvm::sys::Process::GetEnv(Var)) {
653-
SmallVector<StringRef, 8> Dirs;
654-
StringRef(*Val).split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
655-
if (!Dirs.empty()) {
656-
addSystemIncludes(DriverArgs, CC1Args, Dirs);
657-
return true;
658-
}
659-
}
660-
return false;
661-
};
662-
663-
// Add %INCLUDE%-like dirs via /external:env: flags.
664-
for (const auto &Var :
665-
DriverArgs.getAllArgValues(options::OPT__SLASH_external_env)) {
666-
AddSystemIncludesFromEnv(Var);
667-
}
668-
669651
// Add DIA SDK include if requested.
670652
if (const Arg *A = DriverArgs.getLastArg(options::OPT__SLASH_diasdkdir,
671653
options::OPT__SLASH_winsysroot)) {
@@ -682,12 +664,14 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
682664
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
683665
return;
684666

685-
// Honor %INCLUDE% and %EXTERNAL_INCLUDE%. It should have essential search
686-
// paths set by vcvarsall.bat. Skip if the user expressly set a vctoolsdir.
667+
// Add paths from the INCLUDE and EXTERNAL_INCLUDE environment variables if
668+
// neither a vctoolsdir or winsysroot directory has been explicitly specified.
669+
// If any paths are present in these environment variables, then skip adding
670+
// additional system directories.
687671
if (!DriverArgs.getLastArg(options::OPT__SLASH_vctoolsdir,
688672
options::OPT__SLASH_winsysroot)) {
689-
bool Found = AddSystemIncludesFromEnv("INCLUDE");
690-
Found |= AddSystemIncludesFromEnv("EXTERNAL_INCLUDE");
673+
bool Found = addSystemIncludesFromEnv(DriverArgs, CC1Args, "INCLUDE");
674+
Found |= addSystemIncludesFromEnv(DriverArgs, CC1Args, "EXTERNAL_INCLUDE");
691675
if (Found)
692676
return;
693677
}

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3190,8 +3190,11 @@ static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
31903190
auto It = Opts.UserEntries.begin();
31913191
auto End = Opts.UserEntries.end();
31923192

3193-
// Add -I..., -F..., and -index-header-map options in order.
3194-
for (; It < End && Matches(*It, {frontend::IndexHeaderMap, frontend::Angled},
3193+
// Add the -I..., -F..., -index-header-map, and -iexternal options
3194+
// in order.
3195+
for (; It < End && Matches(*It,
3196+
{frontend::IndexHeaderMap, frontend::Angled,
3197+
frontend::External},
31953198
std::nullopt, true);
31963199
++It) {
31973200
OptSpecifier Opt = [It, Matches]() {
@@ -3203,13 +3206,20 @@ static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
32033206
return OPT_F;
32043207
if (Matches(*It, frontend::Angled, false, true))
32053208
return OPT_I;
3209+
if (Matches(*It, frontend::External, false, true))
3210+
return OPT_iexternal;
32063211
llvm_unreachable("Unexpected HeaderSearchOptions::Entry.");
32073212
}();
32083213

32093214
if (It->Group == frontend::IndexHeaderMap)
32103215
GenerateArg(Consumer, OPT_index_header_map);
32113216
GenerateArg(Consumer, Opt, It->Path);
3212-
};
3217+
}
3218+
3219+
// Add the paths for the -iexternal-env= and -iexternal-after options in
3220+
// order.
3221+
for (; It < End && Matches(*It, {frontend::ExternalAfter}, false, true); ++It)
3222+
GenerateArg(Consumer, OPT_iexternal_after, It->Path);
32133223

32143224
// Note: some paths that came from "[-iprefix=xx] -iwithprefixbefore=yy" may
32153225
// have already been generated as "-I[xx]yy". If that's the case, their
@@ -3319,8 +3329,6 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
33193329
llvm::CachedHashString(MacroDef.split('=').first));
33203330
}
33213331

3322-
// Add -I..., -F..., and -index-header-map options in order.
3323-
bool IsIndexHeaderMap = false;
33243332
bool IsSysrootSpecified =
33253333
Args.hasArg(OPT__sysroot_EQ) || Args.hasArg(OPT_isysroot);
33263334

@@ -3339,22 +3347,32 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
33393347
return A->getValue();
33403348
};
33413349

3342-
for (const auto *A : Args.filtered(OPT_I, OPT_F, OPT_index_header_map)) {
3350+
// Add the -I..., -F..., -index-header-map, and -iexternal options in order.
3351+
bool IsIndexHeaderMap = false;
3352+
for (const auto *A :
3353+
Args.filtered(OPT_I, OPT_F, OPT_index_header_map, OPT_iexternal)) {
3354+
frontend::IncludeDirGroup Group =
3355+
IsIndexHeaderMap ? frontend::IndexHeaderMap : frontend::Angled;
3356+
33433357
if (A->getOption().matches(OPT_index_header_map)) {
33443358
// -index-header-map applies to the next -I or -F.
33453359
IsIndexHeaderMap = true;
33463360
continue;
33473361
}
3348-
3349-
frontend::IncludeDirGroup Group =
3350-
IsIndexHeaderMap ? frontend::IndexHeaderMap : frontend::Angled;
3362+
if (A->getOption().matches(OPT_iexternal))
3363+
Group = frontend::External;
33513364

33523365
bool IsFramework = A->getOption().matches(OPT_F);
33533366
Opts.AddPath(PrefixHeaderPath(A, IsFramework), Group, IsFramework,
33543367
/*IgnoreSysroot*/ true);
33553368
IsIndexHeaderMap = false;
33563369
}
33573370

3371+
// Add the -iexternal-env= and -iexternal-after options in order.
3372+
for (const auto *A : Args.filtered(OPT_iexternal_after))
3373+
Opts.AddPath(A->getValue(), frontend::ExternalAfter,
3374+
/*IsFramework=*/false, /*IgnoreSysRoot=*/true);
3375+
33583376
// Add -iprefix/-iwithprefix/-iwithprefixbefore options.
33593377
StringRef Prefix = ""; // FIXME: This isn't the correct default prefix.
33603378
for (const auto *A :

0 commit comments

Comments
 (0)