diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index bec001bf8e353..a11e320b84de9 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -389,6 +389,49 @@ Android Support Windows Support ^^^^^^^^^^^^^^^ +- Clang now matches MSVC behavior regarding the handling of duplicate header + search paths when run via the ``clang-cl`` driver (by default) or with the + ``-fheader-search=microsoft`` option otherwise. Historically, Clang has + mimicked GCC behavior in which user search paths are ordered before system + search paths, user search paths that duplicate a (later) system search + path are ignored, and search paths that duplicate an earlier search path of + the same user/system kind are ignored. This ordering is not compatible with + the ordering that MSVC uses when paths are duplicated across ``/I`` options + and the ``INCLUDE`` environment variable. + + The order that MSVC uses and that Clang now replicates when the + ``-fheader-search=microsoft`` option is enabled follows. + + - 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. + + - 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. + + - 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. + + - 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. + + The ``-fheader-search=gcc`` option can be used to opt in to GCC duplicate + header search path handling (which remains the default behavior for the GCC + compatible drivers). + LoongArch Support ^^^^^^^^^^^^^^^^^ diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 0e85c8109fd5e..9bc67e2d416af 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -5418,12 +5418,26 @@ follows: 2. Consult the environment. - TODO: This is not yet implemented. + - `/external:env:[VARIABLE]` - This will consult the environment variables: + This command line option specifies a user identified environment variable + which is treated as a path delimited (`;`) list of system header paths. - - `WindowsSdkDir` - - `UCRTVersion` + - `INCLUDE` + + This environment variable is treated as a path delimited (`;`) list of + system header paths. + + - `EXTERNAL_INCLUDE` + + This environment variable is treated as a path delimited (`;`) list of + system header paths. + + The following environment variables will be consulted and used to form paths + to validate and load content from as appropriate: + + - `WindowsSdkDir` + - `UCRTVersion` 3. Fallback to the registry. @@ -5435,6 +5449,8 @@ The Visual C++ Toolset has a slightly more elaborate mechanism for detection. 1. Consult the command line. + Anything the user specifies is always given precedence. + - `/winsysroot:` The `/winsysroot:` is used as an equivalent to `-sysroot` on Unix @@ -5452,21 +5468,30 @@ The Visual C++ Toolset has a slightly more elaborate mechanism for detection. 2. Consult the environment. - - `/external:[VARIABLE]` + - `/external:env:[VARIABLE]` + + This command line option specifies a user identified environment variable + which is treated as a path delimited (`;`) list of external header search + paths. Additionally, any header search path provided by other means that + has a prefix that matches one of these paths is treated as an external + header search path. + + - `INCLUDE` - This specifies a user identified environment variable which is treated as - a path delimiter (`;`) separated list of paths to map into `-imsvc` - arguments which are treated as `-isystem`. + This environment variable is treated as a path delimited (`;`) list of + header search paths. - - `INCLUDE` and `EXTERNAL_INCLUDE` + - `EXTERNAL_INCLUDE` - The path delimiter (`;`) separated list of paths will be mapped to - `-imsvc` arguments which are treated as `-isystem`. + This environment variable is treated as a path delimited (`;`) list of + external header search paths. Additionally, any header search path + provided by other means that has a prefix that matches one of these paths + is treated as an external header search path. - `LIB` (indirectly) The linker `link.exe` or `lld-link.exe` will honour the environment - variable `LIB` which is a path delimiter (`;`) set of paths to consult for + variable `LIB` which is a path delimited (`;`) set of paths to consult for the import libraries to use when linking the final target. The following environment variables will be consulted and used to form paths diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 49e917a6a0786..77553ac0f8587 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4811,6 +4811,19 @@ def iapinotes_modules : JoinedOrSeparate<["-"], "iapinotes-modules">, Group, Group, Visibility<[ClangOption, CC1Option]>, HelpText<"Add directory to AFTER include search path">; +def iexternal : Separate<["-"], "iexternal">, Group, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Add directory to include search path with warnings suppressed">, MetaVarName<"">; +def iexternal_system : Separate<["-"], "iexternal-system">, Group, + Visibility<[CC1Option]>, + HelpText<"Add directory to include search path with warnings suppressed">, MetaVarName<"">; +def iexternal_env_EQ : Joined<["-"], "iexternal-env=">, Group, + Visibility<[ClangOption]>, + HelpText<"Add dirs in env var to include search path with warnings suppressed">, MetaVarName<"">; +def iexternal_anglebrackets : Flag<["-"], "iexternal-anglebrackets">, Group, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Treat all #include paths enclosed in angle brackets as including a system header">, + MarshallingInfoFlag>; def iframework : JoinedOrSeparate<["-"], "iframework">, Group, Visibility<[ClangOption, CC1Option]>, HelpText<"Add directory to SYSTEM framework search path">; @@ -4853,6 +4866,10 @@ def isysroot : JoinedOrSeparate<["-"], "isysroot">, Group, def isystem : JoinedOrSeparate<["-"], "isystem">, Group, Visibility<[ClangOption, CC1Option]>, HelpText<"Add directory to SYSTEM include search path">, MetaVarName<"">; +def isystem_env_EQ : Joined<["-"], "isystem-env=">, Group, + MetaVarName<"">, + Visibility<[ClangOption]>, + HelpText<"Add directoires in env var to SYSTEM include search path">; def isystem_after : JoinedOrSeparate<["-"], "isystem-after">, Group, Flags<[NoXarchOption]>, MetaVarName<"">, HelpText<"Add directory to end of the SYSTEM include search path">; @@ -8620,6 +8637,17 @@ def fexperimental_max_bitint_width_EQ: // Header Search Options //===----------------------------------------------------------------------===// +let Visibility = [ClangOption, CC1Option, CLOption] in { + +def fheader_search : Joined<["-"], "fheader-search=">, Group, + HelpText<"Specify the method used to resolve included header files">, + Values<"gcc,microsoft">, + NormalizedValuesScope<"clang::HeaderSearchMode">, + NormalizedValues<["GCC", "Microsoft"]>, + MarshallingInfoEnum, "GCC">; + +} // let Visibility = [ClangOption, CC1Option, CLOption] + let Visibility = [CC1Option] in { def nostdsysteminc : Flag<["-"], "nostdsysteminc">, @@ -8653,6 +8681,12 @@ def internal_isystem : Separate<["-"], "internal-isystem">, HelpText<"Add directory to the internal system include search path; these " "are assumed to not be user-provided and are used to model system " "and standard headers' paths.">; +def internal_iexternal_system : Separate<["-"], "internal-iexternal-system">, + MetaVarName<"">, + HelpText<"Add directory to the internal system include search path with " + "external directory prefix semantics; these are assumed to not be " + "user-provided and are used to model system and standard headers' " + "paths.">; def internal_externc_isystem : Separate<["-"], "internal-externc-isystem">, MetaVarName<"">, HelpText<"Add directory to the internal system include search path with " @@ -8906,9 +8940,14 @@ def _SLASH_diagnostics_classic : CLFlag<"diagnostics:classic">, def _SLASH_D : CLJoinedOrSeparate<"D", [CLOption, DXCOption]>, HelpText<"Define macro">, MetaVarName<"">, Alias; def _SLASH_E : CLFlag<"E">, HelpText<"Preprocess to stdout">, Alias; -def _SLASH_external_COLON_I : CLJoinedOrSeparate<"external:I">, Alias, +def _SLASH_external_COLON_I : CLJoinedOrSeparate<"external:I">, Alias, HelpText<"Add directory to include search path with warnings suppressed">, MetaVarName<"">; +def _SLASH_external_env : CLJoined<"external:env:">, Alias, + HelpText<"Add dirs in env var to include search path with warnings suppressed">, + MetaVarName<"">; +def _SLASH_external_anglebrackets : CLFlag<"external:anglebrackets">, Alias, + HelpText<"Treat all #include paths enclosed in angle brackets as including a system header">; def _SLASH_fp_contract : CLFlag<"fp:contract">, HelpText<"">, Alias, AliasArgs<["on"]>; def _SLASH_fp_except : CLFlag<"fp:except">, HelpText<"">, Alias, AliasArgs<["strict"]>; def _SLASH_fp_except_ : CLFlag<"fp:except-">, HelpText<"">, Alias, AliasArgs<["ignore"]>; @@ -9148,9 +9187,6 @@ def _SLASH_d2epilogunwindrequirev2 : CLFlag<"d2epilogunwindrequirev2">, def _SLASH_EH : CLJoined<"EH">, HelpText<"Set exception handling model">; def _SLASH_EP : CLFlag<"EP">, HelpText<"Disable linemarker output and preprocess to stdout">; -def _SLASH_external_env : CLJoined<"external:env:">, - HelpText<"Add dirs in env var to include search path with warnings suppressed">, - MetaVarName<"">; def _SLASH_FA : CLJoined<"FA">, HelpText<"Output assembly code file during compilation">; def _SLASH_Fa : CLJoined<"Fa">, diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 1425714d34110..1f61c3bd7c25c 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -219,6 +219,7 @@ class ToolChain { /// \return The subdirectory path if it exists. std::optional getTargetSubDirPath(StringRef BaseDir) const; +public: /// \name Utilities for implementing subclasses. ///@{ static void addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs, @@ -236,16 +237,28 @@ class ToolChain { ArrayRef Paths); static void addSystemIncludes(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, - ArrayRef Paths); + ArrayRef Paths, + bool Internal = true); + static bool addSystemIncludesFromEnv(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef Var, bool Internal = true); + static void addExternalSystemIncludes(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + ArrayRef Paths, + bool Internal = true); + static bool + addExternalSystemIncludesFromEnv(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef Var, bool Internal = true); static std::string concat(StringRef Path, const Twine &A, const Twine &B = "", const Twine &C = "", const Twine &D = ""); ///@} -public: static void addSystemInclude(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, - const Twine &Path); + const Twine &Path, bool Internal = true); + virtual ~ToolChain(); // Accessors diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h index 2e0c8bec8bd8c..42e7f57e4f3df 100644 --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -276,6 +276,15 @@ class HeaderSearch { /// a system header. std::vector> SystemHeaderPrefixes; + /// External directories are user specified directories that are to be treated + /// like system directories for the purposes of warning suppression. A header + /// file that has a path that matches one of these prefixes is promoted to a + /// system header regardless of which header search path was used to resolve + /// the \#include directive. llvm::sys::path::remove_dots() is used to + /// normalize these paths by removing "." and ".." path components and + /// duplicate path separators. Trailing path separators are retained. + llvm::StringSet ExternalDirectoryPrefixes; + /// The hash used for module cache paths. std::string ModuleHash; @@ -401,6 +410,9 @@ class HeaderSearch { SearchDirsUsage.push_back(false); } + /// Add an additional external directory prefix path. + bool AddExternalDirectoryPrefix(StringRef Path); + /// Set the list of system header prefixes. void SetSystemHeaderPrefixes(ArrayRef> P) { SystemHeaderPrefixes.assign(P.begin(), P.end()); diff --git a/clang/include/clang/Lex/HeaderSearchOptions.h b/clang/include/clang/Lex/HeaderSearchOptions.h index 2f33c0749f02a..839d7f34aa4c2 100644 --- a/clang/include/clang/Lex/HeaderSearchOptions.h +++ b/clang/include/clang/Lex/HeaderSearchOptions.h @@ -35,9 +35,19 @@ enum IncludeDirGroup { /// Paths for '\#include <>' added by '-I'. Angled, + /// Like Angled, but marks the directory as an external directory prefix. + /// This group is intended to match the semantics of the MSVC /external:I + /// option. + External, + /// Like Angled, but marks system directories. System, + /// Like System, but marks the directory as an external directory prefix. + /// This group is intended to match the semantics of the MSVC + /// /external:env option. + ExternalSystem, + /// Like System, but headers are implicitly wrapped in extern "C". ExternCSystem, @@ -59,6 +69,11 @@ enum IncludeDirGroup { } // namespace frontend +/// HeaderSearchMode - The method used to resolve included headers to files. +/// This controls the order in which include paths are searched and how +/// duplicate search paths are handled. +enum class HeaderSearchMode { GCC, Microsoft }; + /// HeaderSearchOptions - Helper class for storing options related to the /// initialization of the HeaderSearch object. class HeaderSearchOptions { @@ -93,6 +108,9 @@ class HeaderSearchOptions { : Prefix(Prefix), IsSystemHeader(IsSystemHeader) {} }; + /// The header search mode to use. + HeaderSearchMode Mode = HeaderSearchMode::GCC; + /// If non-empty, the directory to use as a "virtual system root" for include /// paths. std::string Sysroot; @@ -207,6 +225,11 @@ class HeaderSearchOptions { LLVM_PREFERRED_TYPE(bool) unsigned Verbose : 1; + /// Whether header files specified in angle brackets should be treated as + /// system headers. + LLVM_PREFERRED_TYPE(bool) + unsigned AngleBracketsImpliesSystemHeader : 1; + /// If true, skip verifying input files used by modules if the /// module was already verified during this build session (see /// \c BuildSessionTimestamp). @@ -289,6 +312,7 @@ class HeaderSearchOptions { ModuleFileHomeIsCwd(false), EnablePrebuiltImplicitModules(false), UseBuiltinIncludes(true), UseStandardSystemIncludes(true), UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false), + AngleBracketsImpliesSystemHeader(false), ModulesValidateOncePerBuildSession(false), ModulesValidateSystemHeaders(false), ModulesForceValidateUserHeaders(true), diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index f110dbab3e5a5..5229f807791b2 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1534,7 +1534,10 @@ Compilation *Driver::BuildCompilation(ArrayRef ArgList) { if (VFS->setCurrentWorkingDirectory(WD->getValue())) Diag(diag::err_drv_unable_to_set_working_directory) << WD->getValue(); - // Check for missing include directories. + // Check for missing include directories. Diagnostics should not be issued + // for directories specified with -iexternal, -iexternal-env=, or + // -iexternal-system since those options may be used to specify external + // directory prefixes that don't necessarily match an existing path. if (!Diags.isIgnored(diag::warn_missing_include_dirs, SourceLocation())) { for (auto IncludeDir : Args.getAllArgValues(options::OPT_I_Group)) { if (!VFS->exists(IncludeDir)) diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 49c89ab0c037f..d031b05e76b18 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -1435,8 +1435,11 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs, /// Utility function to add a system include directory to CC1 arguments. /*static*/ void ToolChain::addSystemInclude(const ArgList &DriverArgs, ArgStringList &CC1Args, - const Twine &Path) { - CC1Args.push_back("-internal-isystem"); + const Twine &Path, bool Internal) { + if (Internal) + CC1Args.push_back("-internal-isystem"); + else + CC1Args.push_back("-isystem"); CC1Args.push_back(DriverArgs.MakeArgString(Path)); } @@ -1453,13 +1456,70 @@ void ToolChain::addSystemFrameworkIncludes(const ArgList &DriverArgs, /// Utility function to add a list of system include directories to CC1. void ToolChain::addSystemIncludes(const ArgList &DriverArgs, ArgStringList &CC1Args, - ArrayRef Paths) { + ArrayRef Paths, + bool Internal) { for (const auto &Path : Paths) { - CC1Args.push_back("-internal-isystem"); + if (Internal) + CC1Args.push_back("-internal-isystem"); + else + CC1Args.push_back("-isystem"); CC1Args.push_back(DriverArgs.MakeArgString(Path)); } } +/// Utility function to add a list of environment path separator delimited +/// directories specified in an environment variable to the system include +/// path list for CC1. Returns true if the variable is set and not empty. +/*static*/ bool ToolChain::addSystemIncludesFromEnv(const ArgList &DriverArgs, + ArgStringList &CC1Args, + StringRef Var, + bool Internal) { + if (auto Val = llvm::sys::Process::GetEnv(Var)) { + SmallVector Dirs; + StringRef(*Val).split(Dirs, llvm::sys::EnvPathSeparator, /*MaxSplit=*/-1, + /*KeepEmpty=*/false); + if (!Dirs.empty()) { + addSystemIncludes(DriverArgs, CC1Args, Dirs, Internal); + return true; + } + } + return false; +} + +/// Utility function to add a list of directories to the end of the external +/// include path list for CC1. +/*static*/ void ToolChain::addExternalSystemIncludes(const ArgList &DriverArgs, + ArgStringList &CC1Args, + ArrayRef Paths, + bool Internal) { + for (const auto &Path : Paths) { + if (Internal) + CC1Args.push_back("-internal-iexternal-system"); + else + CC1Args.push_back("-iexternal-system"); + CC1Args.push_back(DriverArgs.MakeArgString(Path)); + } +} + +/// Utility function to add a list of environment path separator delimited +/// directories specified in an environment variable to the external include +/// path list for CC1. Returns true if the variable is set and not empty. +/*static*/ bool +ToolChain::addExternalSystemIncludesFromEnv(const ArgList &DriverArgs, + ArgStringList &CC1Args, + StringRef Var, bool Internal) { + if (auto Val = llvm::sys::Process::GetEnv(Var)) { + SmallVector Dirs; + StringRef(*Val).split(Dirs, llvm::sys::EnvPathSeparator, /*MaxSplit=*/-1, + /*KeepEmpty=*/false); + if (!Dirs.empty()) { + addExternalSystemIncludes(DriverArgs, CC1Args, Dirs, Internal); + return true; + } + } + return false; +} + std::string ToolChain::concat(StringRef Path, const Twine &A, const Twine &B, const Twine &C, const Twine &D) { SmallString<128> Result(Path); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 21e45c6b56bbb..1369449410772 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1038,6 +1038,19 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, } else if (A->getOption().matches(options::OPT_ibuiltininc)) { // This is used only by the driver. No need to pass to cc1. continue; + } else if (A->getOption().matches(options::OPT_iexternal)) { + // This option has to retain relative order with other -I options. + continue; + } else if (A->getOption().matches(options::OPT_isystem_env_EQ)) { + A->claim(); + ToolChain::addSystemIncludesFromEnv(Args, CmdArgs, A->getValue(), + /*Internal*/ false); + continue; + } else if (A->getOption().matches(options::OPT_iexternal_env_EQ)) { + A->claim(); + ToolChain::addExternalSystemIncludesFromEnv(Args, CmdArgs, A->getValue(), + /*Internal*/ false); + continue; } // Not translated, render as usual. @@ -1045,9 +1058,9 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, A->render(Args, CmdArgs); } - Args.addAllArgs(CmdArgs, - {options::OPT_D, options::OPT_U, options::OPT_I_Group, - options::OPT_F, options::OPT_embed_dir_EQ}); + Args.addAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, + options::OPT_I_Group, options::OPT_F, + options::OPT_iexternal, options::OPT_embed_dir_EQ}); // Add -Wp, and -Xpreprocessor if using the preprocessor. @@ -8271,6 +8284,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, ProcessVSRuntimeLibrary(getToolChain(), Args, CmdArgs); + if (!Args.hasArg(options::OPT_fheader_search)) + CmdArgs.push_back("-fheader-search=microsoft"); + if (Arg *ShowIncludes = Args.getLastArg(options::OPT__SLASH_showIncludes, options::OPT__SLASH_showIncludes_user)) { @@ -8593,7 +8609,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, (void)Args.hasArg(options::OPT_force__cpusubtype__ALL); // Pass along any -I options so we get proper .include search paths. - Args.AddAllArgs(CmdArgs, options::OPT_I_Group); + Args.addAllArgs(CmdArgs, {options::OPT_I_Group, options::OPT_iexternal}); // Pass along any --embed-dir or similar options so we get proper embed paths. Args.AddAllArgs(CmdArgs, options::OPT_embed_dir_EQ); diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index bb469ff095cd4..42bddf21348a5 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -661,24 +661,6 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc)) addSystemInclude(DriverArgs, CC1Args, Path); - auto AddSystemIncludesFromEnv = [&](StringRef Var) -> bool { - if (auto Val = llvm::sys::Process::GetEnv(Var)) { - SmallVector Dirs; - StringRef(*Val).split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false); - if (!Dirs.empty()) { - addSystemIncludes(DriverArgs, CC1Args, Dirs); - return true; - } - } - return false; - }; - - // Add %INCLUDE%-like dirs via /external:env: flags. - for (const auto &Var : - DriverArgs.getAllArgValues(options::OPT__SLASH_external_env)) { - AddSystemIncludesFromEnv(Var); - } - // Add DIA SDK include if requested. if (const Arg *A = DriverArgs.getLastArg(options::OPT__SLASH_diasdkdir, options::OPT__SLASH_winsysroot)) { @@ -695,15 +677,17 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (DriverArgs.hasArg(options::OPT_nostdlibinc)) return; - // Honor %INCLUDE% and %EXTERNAL_INCLUDE%. It should have essential search - // paths set by vcvarsall.bat. Skip if the user expressly set any of the - // Windows SDK or VC Tools options. + // Add paths from the INCLUDE and EXTERNAL_INCLUDE environment variables if + // neither VC Tools nor Windows SDK options have been explicitly specified. + // If any paths are present in these environment variables, then + // skip adding additional system directories. if (!DriverArgs.hasArg( options::OPT__SLASH_vctoolsdir, options::OPT__SLASH_vctoolsversion, options::OPT__SLASH_winsysroot, options::OPT__SLASH_winsdkdir, options::OPT__SLASH_winsdkversion)) { - bool Found = AddSystemIncludesFromEnv("INCLUDE"); - Found |= AddSystemIncludesFromEnv("EXTERNAL_INCLUDE"); + bool Found = addSystemIncludesFromEnv(DriverArgs, CC1Args, "INCLUDE"); + Found |= addExternalSystemIncludesFromEnv(DriverArgs, CC1Args, + "EXTERNAL_INCLUDE"); if (Found) return; } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 8411d00cc7812..2d124167e1a30 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3339,14 +3339,17 @@ static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts, auto It = Opts.UserEntries.begin(); auto End = Opts.UserEntries.end(); - // Add -I... and -F... options in order. - for (; It < End && Matches(*It, {frontend::Angled}, std::nullopt, true); + // Add the -I..., -F..., and -iexternal options in order. + for (; It < End && Matches(*It, {frontend::Angled, frontend::External}, + std::nullopt, true); ++It) { OptSpecifier Opt = [It, Matches]() { if (Matches(*It, frontend::Angled, true, true)) return OPT_F; if (Matches(*It, frontend::Angled, false, true)) return OPT_I; + if (Matches(*It, frontend::External, false, true)) + return OPT_iexternal; llvm_unreachable("Unexpected HeaderSearchOptions::Entry."); }(); @@ -3372,10 +3375,16 @@ static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts, GenerateArg(Consumer, OPT_idirafter, It->Path); for (; It < End && Matches(*It, {frontend::Quoted}, false, true); ++It) GenerateArg(Consumer, OPT_iquote, It->Path); - for (; It < End && Matches(*It, {frontend::System}, false, std::nullopt); - ++It) - GenerateArg(Consumer, It->IgnoreSysRoot ? OPT_isystem : OPT_iwithsysroot, - It->Path); + for (; It < End && Matches(*It, {frontend::System, frontend::ExternalSystem}, + false, std::nullopt); + ++It) { + OptSpecifier Opt = OPT_isystem; + if (It->Group == frontend::ExternalSystem) + Opt = OPT_iexternal_system; + else if (!It->IgnoreSysRoot) + Opt = OPT_iwithsysroot; + GenerateArg(Consumer, Opt, It->Path); + } for (; It < End && Matches(*It, {frontend::System}, true, true); ++It) GenerateArg(Consumer, OPT_iframework, It->Path); for (; It < End && Matches(*It, {frontend::System}, true, false); ++It) @@ -3395,12 +3404,16 @@ static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts, // Note: Some paths that came from "-internal-isystem" arguments may have // already been generated as "-isystem". If that's the case, their position on // command line was such that this has no semantic impact on include paths. - for (; It < End && - Matches(*It, {frontend::System, frontend::ExternCSystem}, false, true); + for (; It < End && Matches(*It, + {frontend::System, frontend::ExternalSystem, + frontend::ExternCSystem}, + false, true); ++It) { - OptSpecifier Opt = It->Group == frontend::System - ? OPT_internal_isystem - : OPT_internal_externc_isystem; + OptSpecifier Opt = OPT_internal_isystem; + if (It->Group == frontend::ExternalSystem) + Opt = OPT_internal_iexternal_system; + else if (It->Group == frontend::ExternCSystem) + Opt = OPT_internal_externc_isystem; GenerateArg(Consumer, Opt, It->Path); } for (; It < End && Matches(*It, {frontend::System}, true, true); ++It) @@ -3463,7 +3476,6 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, llvm::CachedHashString(MacroDef.split('=').first)); } - // Add -I... and -F... options in order. bool IsSysrootSpecified = Args.hasArg(OPT__sysroot_EQ) || Args.hasArg(OPT_isysroot); @@ -3482,10 +3494,14 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, return A->getValue(); }; - for (const auto *A : Args.filtered(OPT_I, OPT_F)) { + // Add the -I..., -F..., and -iexternal options in order. + for (const auto *A : Args.filtered(OPT_I, OPT_F, OPT_iexternal)) { + frontend::IncludeDirGroup Group = frontend::Angled; + if (A->getOption().matches(OPT_iexternal)) + Group = frontend::External; bool IsFramework = A->getOption().matches(OPT_F); - Opts.AddPath(PrefixHeaderPath(A, IsFramework), frontend::Angled, - IsFramework, /*IgnoreSysroot=*/true); + Opts.AddPath(PrefixHeaderPath(A, IsFramework), Group, IsFramework, + /*IgnoreSysroot=*/true); } // Add -iprefix/-iwithprefix/-iwithprefixbefore options. @@ -3505,13 +3521,17 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, for (const auto *A : Args.filtered(OPT_iquote)) Opts.AddPath(PrefixHeaderPath(A), frontend::Quoted, false, true); - for (const auto *A : Args.filtered(OPT_isystem, OPT_iwithsysroot)) { - if (A->getOption().matches(OPT_iwithsysroot)) { - Opts.AddPath(A->getValue(), frontend::System, false, - /*IgnoreSysRoot=*/false); - continue; - } - Opts.AddPath(PrefixHeaderPath(A), frontend::System, false, true); + for (const auto *A : + Args.filtered(OPT_isystem, OPT_iwithsysroot, OPT_iexternal_system)) { + if (A->getOption().matches(OPT_iexternal_system)) + Opts.AddPath(A->getValue(), frontend::ExternalSystem, + /*IsFramework=*/false, /*IgnoreSysRoot=*/true); + else if (A->getOption().matches(OPT_iwithsysroot)) + Opts.AddPath(A->getValue(), frontend::System, + /*IsFramework=*/false, /*IgnoreSysRoot=*/false); + else + Opts.AddPath(PrefixHeaderPath(A), frontend::System, + /*IsFramework=*/false, /*IgnoreSysRoot=*/true); } for (const auto *A : Args.filtered(OPT_iframework)) Opts.AddPath(A->getValue(), frontend::System, true, true); @@ -3531,9 +3551,12 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, // Add the internal paths from a driver that detects standard include paths. for (const auto *A : - Args.filtered(OPT_internal_isystem, OPT_internal_externc_isystem)) { + Args.filtered(OPT_internal_isystem, OPT_internal_iexternal_system, + OPT_internal_externc_isystem)) { frontend::IncludeDirGroup Group = frontend::System; - if (A->getOption().matches(OPT_internal_externc_isystem)) + if (A->getOption().matches(OPT_internal_iexternal_system)) + Group = frontend::ExternalSystem; + else if (A->getOption().matches(OPT_internal_externc_isystem)) Group = frontend::ExternCSystem; Opts.AddPath(A->getValue(), Group, false, true); } diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index ea2391f6812cf..94c988814f68d 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -127,6 +127,21 @@ void HeaderSearch::AddSearchPath(const DirectoryLookup &dir, bool isAngled) { SystemDirIdx++; } +bool HeaderSearch::AddExternalDirectoryPrefix(StringRef Path) { + // Canonicalize the file path while preserving a trailing path separator. + bool HasTrailingPathSep = llvm::sys::path::is_separator(Path.back()); + SmallString<256> RealPath; + SmallString<256> NormalizedPath = Path; + if (llvm::sys::path::remove_dots(NormalizedPath, /*remove_dot_dot*/ true)) { + // Restore the trailing path separator if necessary. + if (HasTrailingPathSep && + !llvm::sys::path::is_separator(NormalizedPath.back())) + NormalizedPath += llvm::sys::path::get_separator(); + } + ExternalDirectoryPrefixes.insert(NormalizedPath); + return true; +} + std::vector HeaderSearch::computeUserEntryUsage() const { std::vector UserEntryUsage(HSOpts.UserEntries.size()); for (unsigned I = 0, E = SearchDirsUsage.size(); I < E; ++I) { @@ -1122,6 +1137,51 @@ OptionalFileEntryRef HeaderSearch::LookupFile( } } + // If the file is not already recognized as a system header, check if it + // was included in angle brackets and whether the file characteristic + // should be promoted. + if (HFI.DirInfo == SrcMgr::C_User && isAngled && + HSOpts.AngleBracketsImpliesSystemHeader) + HFI.DirInfo = SrcMgr::C_System; + + // If the file is not already recognized as a system header, check if it + // matches an external directory prefix and override the file characteristic + // accordingly. + if (HFI.DirInfo == SrcMgr::C_User && !ExternalDirectoryPrefixes.empty()) { + // An external directory prefix is not required to match an existing + // directory on disk; the final path component may match the start of + // multiple file or directory entries. A string comparison is therefore + // required to determine if a prefix matches. External directory prefixes + // are normalized, so the header file path must be likewise normalized. + SmallString<256> NormalizedPath = File->getName(); + llvm::sys::path::remove_dots(NormalizedPath, /*remove_dot_dot*/ true); + for (const auto &ExtDir : ExternalDirectoryPrefixes) { + SmallString<256> HeaderPath = NormalizedPath; + SmallString<256> ExternalPath = ExtDir.getKey(); + if (llvm::sys::path::is_absolute(HeaderPath) != + llvm::sys::path::is_absolute(ExternalPath)) { + // One of the paths is absolute and the other isn't. Make them both + // absolute so that they can be compared. If this fails, then the + // paths are not comparable. + if (llvm::sys::fs::make_absolute(HeaderPath)) + continue; + if (llvm::sys::fs::make_absolute(ExternalPath)) + continue; + } + // llvm::sys::path::replace_path_prefix() is used to test for a prefix + // match since it will handle case insensitivity and alternate path + // separator matching. Note that this operation is destructive to + // NormalizedPath if the prefix matches. + if (llvm::sys::path::replace_path_prefix(HeaderPath, ExternalPath, + "")) { + // The external directory prefix is a match; override the file + // characteristic and break out of the loop. + HFI.DirInfo = SrcMgr::C_System; + break; + } + } + } + if (checkMSVCHeaderSearch(Diags, MSFE, &File->getFileEntry(), IncludeLoc)) { if (SuggestedModule) *SuggestedModule = MSSuggestedModule; diff --git a/clang/lib/Lex/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp index 3e5f947a82cc3..fd53ab9c3124d 100644 --- a/clang/lib/Lex/InitHeaderSearch.cpp +++ b/clang/lib/Lex/InitHeaderSearch.cpp @@ -141,9 +141,16 @@ bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, } else if (Group == ExternCSystem) { Type = SrcMgr::C_ExternCSystem; } else { + // Group in External, ExternalSystem, System, (Obj)C(XX)System, After. Type = SrcMgr::C_System; } + // Register external directory prefixes. Note that a non-existent external + // directory prefix is still used for header file prefix matching purposes + // despite not contributing to the include path. + if (Group == External || Group == ExternalSystem) + Headers.AddExternalDirectoryPrefix(MappedPathStr); + // If the directory exists, add it. if (auto DE = FM.getOptionalDirectoryRef(MappedPathStr)) { IncludePath.emplace_back(Group, DirectoryLookup(*DE, Type, isFramework), @@ -270,90 +277,108 @@ void InitHeaderSearch::AddDefaultIncludePaths( AddDefaultCIncludePaths(triple, HSOpts); } -/// If there are duplicate directory entries in the specified search list, -/// remove the later (dead) ones. Returns the number of non-system headers -/// removed, which is used to update NumAngled. -static unsigned RemoveDuplicates(std::vector &SearchList, - unsigned First, bool Verbose) { +/// Remove duplicate paths from a partitioned search list with a diagnostic +/// issued if Verbose is true. Partitioning is at the discretion of the +/// caller and may be used to, for example, indicate a division between user +/// and system search paths. If partitioning is not needed, then call with +/// Part1Begin equal to Part2Begin. The return value is the number of items +/// removed from the first partition. +static unsigned RemoveDuplicates(const HeaderSearchOptions &HSOpts, + std::vector &SearchList, + unsigned Part1Begin, unsigned Part2Begin, + bool Verbose) { llvm::SmallPtrSet SeenDirs; llvm::SmallPtrSet SeenFrameworkDirs; llvm::SmallPtrSet SeenHeaderMaps; - unsigned NonSystemRemoved = 0; - for (unsigned i = First; i != SearchList.size(); ++i) { - unsigned DirToRemove = i; - + unsigned NumPart1DirsRemoved = 0; + for (unsigned i = Part1Begin; i != SearchList.size(); ++i) { + IncludeDirGroup CurGroup = SearchList[i].Group; const DirectoryLookup &CurEntry = SearchList[i].Lookup; + SrcMgr::CharacteristicKind CurSrcKind = CurEntry.getDirCharacteristic(); + // If the current entry is for a previously unseen location, cache it and + // continue with the next entry. if (CurEntry.isNormalDir()) { - // If this isn't the first time we've seen this dir, remove it. if (SeenDirs.insert(CurEntry.getDir()).second) continue; } else if (CurEntry.isFramework()) { - // If this isn't the first time we've seen this framework dir, remove it. if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir()).second) continue; } else { assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?"); - // If this isn't the first time we've seen this headermap, remove it. if (SeenHeaderMaps.insert(CurEntry.getHeaderMap()).second) continue; } - // If we have a normal #include dir/framework/headermap that is shadowed - // later in the chain by a system include location, we actually want to - // ignore the user's request and drop the user dir... keeping the system - // dir. This is weird, but required to emulate GCC's search path correctly. - // - // Since dupes of system dirs are rare, just rescan to find the original - // that we're nuking instead of using a DenseMap. - if (CurEntry.getDirCharacteristic() != SrcMgr::C_User) { - // Find the dir that this is the same of. - unsigned FirstDir; - for (FirstDir = First;; ++FirstDir) { - assert(FirstDir != i && "Didn't find dupe?"); - - const DirectoryLookup &SearchEntry = SearchList[FirstDir].Lookup; - - // If these are different lookup types, then they can't be the dupe. - if (SearchEntry.getLookupType() != CurEntry.getLookupType()) - continue; - - bool isSame; - if (CurEntry.isNormalDir()) - isSame = SearchEntry.getDir() == CurEntry.getDir(); - else if (CurEntry.isFramework()) - isSame = SearchEntry.getFrameworkDir() == CurEntry.getFrameworkDir(); - else { - assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?"); - isSame = SearchEntry.getHeaderMap() == CurEntry.getHeaderMap(); - } - - if (isSame) - break; + // Find the previous matching search entry. + unsigned PrevIndex; + for (PrevIndex = Part1Begin; PrevIndex < i; ++PrevIndex) { + const DirectoryLookup &SearchEntry = SearchList[PrevIndex].Lookup; + + // Different lookup types are not considered duplicate entries. + if (SearchEntry.getLookupType() != CurEntry.getLookupType()) + continue; + + bool isSame; + if (CurEntry.isNormalDir()) + isSame = SearchEntry.getDir() == CurEntry.getDir(); + else if (CurEntry.isFramework()) + isSame = SearchEntry.getFrameworkDir() == CurEntry.getFrameworkDir(); + else { + assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?"); + isSame = SearchEntry.getHeaderMap() == CurEntry.getHeaderMap(); } - // If the first dir in the search path is a non-system dir, zap it - // instead of the system one. - if (SearchList[FirstDir].Lookup.getDirCharacteristic() == SrcMgr::C_User) - DirToRemove = FirstDir; + if (isSame) + break; } + assert(PrevIndex < i && "Expected duplicate search location not found"); + const DirectoryLookup &PrevEntry = SearchList[PrevIndex].Lookup; + SrcMgr::CharacteristicKind PrevSrcKind = PrevEntry.getDirCharacteristic(); + // By default, a search path that follows a previous matching search path + // is removed. Exceptions exist for paths from the External include group + // and for user paths that match a later system path. + unsigned DirToRemove = i; + if (CurGroup == frontend::External) { + // A path that matches a later path specified by -iexternal is always + // suppressed. + DirToRemove = PrevIndex; + } else if (HSOpts.Mode != HeaderSearchMode::Microsoft && + PrevSrcKind == SrcMgr::C_User && CurSrcKind != SrcMgr::C_User) { + // When not in Microsoft compatibility mode, a user path that matches + // a later system path is suppressed. + DirToRemove = PrevIndex; + } + + // If requested, issue a diagnostic about the ignored directory. if (Verbose) { + bool NonSystemDirRemoved = false; + if (DirToRemove == i) + NonSystemDirRemoved = + PrevSrcKind != SrcMgr::C_User && CurSrcKind == SrcMgr::C_User; + else + NonSystemDirRemoved = + PrevSrcKind == SrcMgr::C_User && CurSrcKind != SrcMgr::C_User; + llvm::errs() << "ignoring duplicate directory \"" << CurEntry.getName() << "\"\n"; - if (DirToRemove != i) + if (NonSystemDirRemoved) llvm::errs() << " as it is a non-system directory that duplicates " << "a system directory\n"; } - if (DirToRemove != i) - ++NonSystemRemoved; - // This is reached if the current entry is a duplicate. Remove the - // DirToRemove (usually the current dir). + // Remove the duplicate entry from the search list. SearchList.erase(SearchList.begin()+DirToRemove); --i; + + // Adjust the partition boundaries if necessary. + if (DirToRemove < Part2Begin) { + ++NumPart1DirsRemoved; + --Part2Begin; + } } - return NonSystemRemoved; + return NumPart1DirsRemoved; } /// Extract DirectoryLookups from DirectoryLookupInfos. @@ -379,46 +404,57 @@ mapToUserEntries(const std::vector &Infos) { } void InitHeaderSearch::Realize(const LangOptions &Lang) { + const HeaderSearchOptions &HSOpts = Headers.getHeaderSearchOpts(); + // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList. std::vector SearchList; SearchList.reserve(IncludePath.size()); - // Quoted arguments go first. + // Add search paths for quoted inclusion first. for (auto &Include : IncludePath) if (Include.Group == Quoted) SearchList.push_back(Include); + // Remove duplicate search paths within the quoted inclusion list. + RemoveDuplicates(HSOpts, SearchList, 0, 0, Verbose); + unsigned EndQuoted = SearchList.size(); - // Deduplicate and remember index. - RemoveDuplicates(SearchList, 0, Verbose); - unsigned NumQuoted = SearchList.size(); - + // Add search paths for angled inclusion next. Note that user paths and + // external paths may be interleaved; though external paths are treated like + // system paths, they are not reordered to the end of the search list. for (auto &Include : IncludePath) - if (Include.Group == Angled) + if (Include.Group == Angled || Include.Group == External) SearchList.push_back(Include); + // Remove duplicate search paths within the angled inclusion list. + // This may leave paths duplicated across the quoted and angled inclusion + // sections. + RemoveDuplicates(HSOpts, SearchList, EndQuoted, EndQuoted, Verbose); + unsigned EndAngled = SearchList.size(); - RemoveDuplicates(SearchList, NumQuoted, Verbose); - unsigned NumAngled = SearchList.size(); - + // Add search paths for system paths next. for (auto &Include : IncludePath) - if (Include.Group == System || Include.Group == ExternCSystem || + if (Include.Group == System || Include.Group == ExternalSystem || + Include.Group == ExternCSystem || (!Lang.ObjC && !Lang.CPlusPlus && Include.Group == CSystem) || (/*FIXME !Lang.ObjC && */ Lang.CPlusPlus && Include.Group == CXXSystem) || (Lang.ObjC && !Lang.CPlusPlus && Include.Group == ObjCSystem) || (Lang.ObjC && Lang.CPlusPlus && Include.Group == ObjCXXSystem)) SearchList.push_back(Include); - + // Add search paths for system paths to be searched after other system paths. for (auto &Include : IncludePath) if (Include.Group == After) SearchList.push_back(Include); - // Remove duplicates across both the Angled and System directories. GCC does - // this and failing to remove duplicates across these two groups breaks - // #include_next. - unsigned NonSystemRemoved = RemoveDuplicates(SearchList, NumQuoted, Verbose); - NumAngled -= NonSystemRemoved; + // Remove duplicate search paths across both the angled inclusion list and + // the system search paths. This duplicate removal is necessary to ensure + // that header lookup in #include_next directives doesn't resolve to the + // same file. This may result in earlier user paths being removed, and thus + // requires updating the EndAngled index. + unsigned NonSystemRemoved = + RemoveDuplicates(HSOpts, SearchList, EndQuoted, EndAngled, Verbose); + EndAngled -= NonSystemRemoved; - Headers.SetSearchPaths(extractLookups(SearchList), NumQuoted, NumAngled, + Headers.SetSearchPaths(extractLookups(SearchList), EndQuoted, EndAngled, mapToUserEntries(SearchList)); Headers.SetSystemHeaderPrefixes(SystemHeaderPrefixes); @@ -427,7 +463,7 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { if (Verbose) { llvm::errs() << "#include \"...\" search starts here:\n"; for (unsigned i = 0, e = SearchList.size(); i != e; ++i) { - if (i == NumQuoted) + if (i == EndQuoted) llvm::errs() << "#include <...> search starts here:\n"; StringRef Name = SearchList[i].Lookup.getName(); const char *Suffix; diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 9d01b8d99e227..68ab7f440e83d 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -25,6 +25,7 @@ #include "clang/Basic/TokenKinds.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/MacroInfo.h" @@ -1029,7 +1030,9 @@ OptionalFileEntryRef Preprocessor::LookupFile( // MSVC searches the current include stack from top to bottom for // headers included by quoted include directives. // See: http://msdn.microsoft.com/en-us/library/36k2cdd4.aspx - if (LangOpts.MSVCCompat && !isAngled) { + if (getHeaderSearchInfo().getHeaderSearchOpts().Mode == + HeaderSearchMode::Microsoft && + !isAngled) { for (IncludeStackInfo &ISEntry : llvm::reverse(IncludeMacroStack)) { if (IsFileLexer(ISEntry)) if ((FileEnt = ISEntry.ThePPLexer->getFileEntry())) diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 9b0e699b1a829..7bd1acbfee59d 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6567,8 +6567,8 @@ bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record, ASTReaderListener &Listener) { HeaderSearchOptions HSOpts; unsigned Idx = 0; + HSOpts.Mode = static_cast(Record[Idx++]); HSOpts.Sysroot = ReadString(Record, Idx); - HSOpts.ResourceDir = ReadString(Record, Idx); HSOpts.ModuleCachePath = ReadString(Record, Idx); HSOpts.ModuleUserBuildPath = ReadString(Record, Idx); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 8e219e54bf251..2b71ab55c8bae 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -1710,6 +1710,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, StringRef isysroot) { const HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); + Record.push_back(static_cast(HSOpts.Mode)); AddString(HSOpts.Sysroot, Record); AddString(HSOpts.ResourceDir, Record); AddString(HSOpts.ModuleCachePath, Record); diff --git a/clang/test/Driver/cl-include.c b/clang/test/Driver/cl-include.c index d041698c7fd3b..e1335acca0cce 100644 --- a/clang/test/Driver/cl-include.c +++ b/clang/test/Driver/cl-include.c @@ -8,41 +8,43 @@ // NOBUILTIN-NOT: "-internal-isystem" "{{.*lib.*clang.*include}}" // RUN: env INCLUDE=/my/system/inc env EXTERNAL_INCLUDE=/my/system/inc2 %clang_cl -### -- %s 2>&1 | FileCheck %s --check-prefix=STDINC +// STDINC: "-internal-isystem" "{{.*lib.*clang.*include}}" // STDINC: "-internal-isystem" "/my/system/inc" -// STDINC: "-internal-isystem" "/my/system/inc2" +// STDINC: "-internal-iexternal-system" "/my/system/inc2" // -nostdinc suppresses all of %INCLUDE%, clang resource dirs, and -imsvc dirs. -// RUN: env INCLUDE=/my/system/inc env EXTERNAL_INCLUDE=/my/system/inc2 %clang_cl -nostdinc -imsvc /my/other/inc -### -- %s 2>&1 | FileCheck %s --check-prefix=NOSTDINC +// RUN: env INCLUDE=/my/system/inc1 env EXTERNAL_INCLUDE=/my/system/inc2 %clang_cl -nostdinc -imsvc /my/other/inc -### -- %s 2>&1 | FileCheck %s --check-prefix=NOSTDINC // NOSTDINC: argument unused{{.*}}-imsvc -// NOSTDINC-NOT: "-internal-isystem" "/my/system/inc" -// NOSTDINC-NOT: "-internal-isystem" "/my/system/inc2" // NOSTDINC-NOT: "-internal-isystem" "{{.*lib.*clang.*include}}" -// NOSTDINC-NOT: "-internal-isystem" "/my/other/inc" +// NOSTDINC-NOT: "/my/other/inc" +// NOSTDINC-NOT: "/my/system/inc1" +// NOSTDINC-NOT: "/my/system/inc2" // /X suppresses %INCLUDE% and %EXTERNAL_INCLUDE% but not clang resource dirs, -imsvc dirs, or /external: flags. -// RUN: env INCLUDE=/my/system/inc env EXTERNAL_INCLUDE=/my/system/inc2 env FOO=/my/other/inc2 %clang_cl /X -imsvc /my/other/inc /external:env:FOO -### -- %s 2>&1 | FileCheck %s --check-prefix=SLASHX +// RUN: env INCLUDE=/my/system/inc1 env EXTERNAL_INCLUDE=/my/system/inc2 env FOO=/my/other/inc2 %clang_cl /X -imsvc /my/other/inc /external:env:FOO -### -- %s 2>&1 | FileCheck %s --check-prefix=SLASHX // SLASHX-NOT: "argument unused{{.*}}-imsvc" -// SLASHX-NOT: "-internal-isystem" "/my/system/inc" -// SLASHX-NOT: "-internal-isystem" "/my/system/inc2" +// SLASHX-NOT: "/my/system/inc1" +// SLASHX-NOT: "/my/system/inc2" +// SLASHX: "-iexternal-system" "/my/other/inc2" // SLASHX: "-internal-isystem" "{{.*lib.*clang.*include}}" // SLASHX: "-internal-isystem" "/my/other/inc" -// SLASHX: "-internal-isystem" "/my/other/inc2" -// /winsysroot suppresses %EXTERNAL_INCLUDE% but not -imsvc dirs or /external: flags. -// RUN: env env EXTERNAL_INCLUDE=/my/system/inc env FOO=/my/other/inc2 %clang_cl /winsysroot /foo -imsvc /my/other/inc /external:env:FOO -### -- %s 2>&1 | FileCheck %s --check-prefix=SYSROOT +// /winsysroot suppresses %INCLUDE% and %EXTERNAL_INCLUDE% but not -imsvc dirs or /external: flags. +// RUN: env INCLUDE=/my/system/inc1 env EXTERNAL_INCLUDE=/my/system/inc2 env FOO=/my/other/inc2 %clang_cl /winsysroot /foo -imsvc /my/other/inc /external:env:FOO -### -- %s 2>&1 | FileCheck %s --check-prefix=SYSROOT // SYSROOT-NOT: "argument unused{{.*}}-imsvc" // SYSROOT-NOT: "argument unused{{.*}}/external:" -// SYSROOT-NOT: "/my/system/inc" +// SYSROOT-NOT: "/my/system/inc1" +// SYSROOT-NOT: "/my/system/inc2" +// SYSROOT: "-iexternal-system" "/my/other/inc2" // SYSROOT: "-internal-isystem" "/my/other/inc" -// SYSROOT: "-internal-isystem" "/my/other/inc2" // SYSROOT: "-internal-isystem" "/foo{{.*}}" -// RUN: env "FOO=/dir1;/dir2" env "BAR=/dir3" %clang_cl /external:env:FOO /external:env:BAR -### -- %s 2>&1 | FileCheck %s --check-prefix=EXTERNAL_ENV -// EXTERNAL_ENV: "-internal-isystem" "/dir1" -// EXTERNAL_ENV: "-internal-isystem" "/dir2" -// EXTERNAL_ENV: "-internal-isystem" "/dir3" +// RUN: env "FOO=/dir1%{pathsep}/dir2" env "BAR=/dir3" %clang_cl /external:env:FOO /external:env:BAR -### -- %s 2>&1 | FileCheck %s --check-prefix=EXTERNAL_ENV +// EXTERNAL_ENV: "-iexternal-system" "/dir1" +// EXTERNAL_ENV: "-iexternal-system" "/dir2" +// EXTERNAL_ENV: "-iexternal-system" "/dir3" // /winsdkversion suppresses %INCLUDE% and %EXTERNAL_INCLUDE% // RUN:env INCLUDE=/my/system/inc env EXTERNAL_INCLUDE=/my/system/inc2 %clang_cl /winsdkversion 99.99.9999.9 -### -- %s 2>&1 | FileCheck %s --check-prefix=SDKVERSION // SDKVERSION-NOT: "-internal-isystem" "/my/system/inc" -// SDKVERSION-NOT: "-internal-isystem" "/my/system/inc2" +// SDKVERSION-NOT: "-iexternal-system" "/my/system/inc2" diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c index e9708688a6e3d..80a9522c84ab5 100644 --- a/clang/test/Driver/cl-options.c +++ b/clang/test/Driver/cl-options.c @@ -40,7 +40,11 @@ // RUN: %clang_cl /external:Ipath -### -- %s 2>&1 | FileCheck -check-prefix=EXTERNAL_I %s // RUN: %clang_cl /external:I path -### -- %s 2>&1 | FileCheck -check-prefix=EXTERNAL_I %s -// EXTERNAL_I: "-isystem" "path" +// EXTERNAL_I: "-iexternal" "path" + +// RUN: env EXTPATH="path1%{pathsep}path2" %clang_cl /external:env:EXTPATH -### -- %s 2>&1 | FileCheck -check-prefix=EXTERNAL_ENV %s +// EXTERNAL_ENV: "-iexternal-system" "path1" +// EXTERNAL_ENV: "-iexternal-system" "path2" // RUN: %clang_cl /fp:fast /fp:except -### -- %s 2>&1 | FileCheck -check-prefix=fpexcept %s // fpexcept-NOT: -funsafe-math-optimizations @@ -451,7 +455,6 @@ // RUN: /experimental:preprocessor \ // RUN: /exportHeader /headerName:foo \ // RUN: /external:anglebrackets \ -// RUN: /external:env:var \ // RUN: /external:W0 \ // RUN: /external:W1 \ // RUN: /external:W2 \ diff --git a/clang/test/Driver/header-search-duplicates.c b/clang/test/Driver/header-search-duplicates.c new file mode 100644 index 0000000000000..9a96566e331ca --- /dev/null +++ b/clang/test/Driver/header-search-duplicates.c @@ -0,0 +1,369 @@ +// Test that pruning of header search paths emulates GCC behavior when not in +// Microsoft compatibility mode. +// See microsoft-header-search-duplicates.c for Microsoft compatible behavior. + +// RUN: rm -rf %t +// RUN: split-file %s %t + +// This test uses the -nostdinc option to suppress default search paths to +// ease testing. + +// Header search paths are categorized into the following general groups. +// - Quoted: Search paths that are only used to resolve inclusion of header +// files specified with quoted inclusion ('#include "X"'). Paths nominated +// by the '-iquoted' option are added to this group. +// - Angled: Search paths used to resolve inclusion of header files specified +// with angled inclusion ('#include ') or quoted inclusion if a match +// was not found in the Quoted group. Paths nominated by the '-I', +// '-iexternal', '-iexternal-env=', and '-iwithprefixbefore' options are +// added to this group. +// - System: Search paths used to resolve inclusion of a header file for which +// a match is not found in the Quoted or Angled groups. Paths nominated by +// the '-dirafter', '-isystem', '-isystem-after', '-iwithprefix', and +// related language specific options are added to this group. +// Duplicate search paths are identified and processed as follows: +// 1) Paths in the Quoted group that duplicate a previous path in the Quoted +// group are removed. +// 2) Paths in the Angled group that are duplicated by an external path +// (as nominated by the '-iexternal' or '-iexternal-env=' options) in the +// Angled group (regardless of the relative order of the paths) or by a +// path in the System group are removed +// 3) Paths in the Angled or System groups that duplicate a previous path in +// the Angled or System group are removed. + + +// Test 1: Validate ordering and duplicate elimination in the Quoted group. +// This test exhibits a behavioral difference between GCC and Clang. GCC +// removes the last path in the quoted group if it matches the first path +// in the angled group. Clang does not. The difference is observable via +// '#include_next' as this test demonstrates. Clang's behavior makes use of +// '#include_next' across the Quoted and Angled groups reliable regardless +// of whether there is an intervening search path present at the start of +// the Angled group. +// +// RUN: %clang \ +// RUN: -target x86_64-unknown-linux-gnu -v -fsyntax-only \ +// RUN: -nostdinc \ +// RUN: -iquote %t/test1/include/x \ +// RUN: -iquote %t/test1/include/y \ +// RUN: -iquote %t/test1/include/x \ +// RUN: -iquote %t/test1/include/z \ +// RUN: -I%t/test1/include/z \ +// RUN: -I%t/test1/include/y \ +// RUN: %t/test1/t.c 2>&1 | FileCheck -DPWD=%t %t/test1/t.c + +#--- test1/t.c +#include "a.h" +#include "b.h" +#include "c.h" + +// CHECK: ignoring duplicate directory "[[PWD]]/test1/include/x" +// CHECK-NEXT: #include "..." search starts here: +// CHECK-NEXT: [[PWD]]/test1/include/x +// CHECK-NEXT: [[PWD]]/test1/include/y +// CHECK-NEXT: [[PWD]]/test1/include/z +// CHECK-NEXT: #include <...> search starts here: +// CHECK-NEXT: [[PWD]]/test1/include/z +// CHECK-NEXT: [[PWD]]/test1/include/y +// CHECK-NEXT: End of search list. + +#--- test1/include/x/a.h + +#--- test1/include/y/a.h +#error 'test1/include/y/a.h' should not have been included! + +#--- test1/include/y/b.h +#if !defined(Y_B_DEFINED) +#define Y_B_DEFINED +#include_next +#endif + +#--- test1/include/z/a.h +#error 'test1/include/z/a.h' should not have been included! + +#--- test1/include/z/b.h +#if !defined(Y_B_DEFINED) +#error 'Y_B_DEFINED' is not defined in test1/include/z/b.h! +#endif + +#--- test1/include/z/c.h +#if !defined(Z_C_DEFINED) +#define Z_C_DEFINED +#include_next +#endif + + +// Test 2: Validate ordering and duplicate elimination in the Angled group. +// +// RUN: %clang \ +// RUN: -target x86_64-unknown-linux-gnu -v -fsyntax-only \ +// RUN: -nostdinc \ +// RUN: -iprefix %t/ \ +// RUN: -I%t/test2/include/v \ +// RUN: -iwithprefixbefore test2/include/y \ +// RUN: -I%t/test2/include/u \ +// RUN: -iexternal %t/test2/include/v \ +// RUN: -iwithprefixbefore test2/include/z \ +// RUN: -iexternal %t/test2/include/w \ +// RUN: -I%t/test2/include/x \ +// RUN: -iexternal %t/test2/include/y \ +// RUN: -iwithprefixbefore test2/include/x \ +// RUN: %t/test2/t.c 2>&1 | FileCheck -DPWD=%t %t/test2/t.c + +#--- test2/t.c +#include +#include +#include +#include +#include +#include + +// CHECK: ignoring duplicate directory "[[PWD]]/test2/include/v" +// CHECK-NEXT: as it is a non-system directory that duplicates a system directory +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test2/include/y" +// CHECK-NEXT: as it is a non-system directory that duplicates a system directory +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test2/include/x" +// CHECK-NEXT: #include "..." search starts here: +// CHECK-NEXT: #include <...> search starts here: +// CHECK-NEXT: [[PWD]]/test2/include/u +// CHECK-NEXT: [[PWD]]/test2/include/v +// CHECK-NEXT: [[PWD]]/test2/include/w +// CHECK-NEXT: [[PWD]]/test2/include/x +// CHECK-NEXT: [[PWD]]/test2/include/y +// CHECK-NEXT: [[PWD]]/test2/include/z +// CHECK-NEXT: End of search list. + +#--- test2/include/u/a.h + +#--- test2/include/v/a.h +#error 'test2/include/v/a.h' should not have been included! + +#--- test2/include/v/b.h + +#--- test2/include/w/a.h +#error 'test2/include/w/a.h' should not have been included! + +#--- test2/include/w/b.h +#error 'test2/include/w/b.h' should not have been included! + +#--- test2/include/w/c.h + +#--- test2/include/x/a.h +#error 'test2/include/x/a.h' should not have been included! + +#--- test2/include/x/b.h +#error 'test2/include/x/b.h' should not have been included! + +#--- test2/include/x/c.h +#error 'test2/include/x/c.h' should not have been included! + +#--- test2/include/x/d.h + +#--- test2/include/y/a.h +#error 'test2/include/y/a.h' should not have been included! + +#--- test2/include/y/b.h +#error 'test2/include/y/b.h' should not have been included! + +#--- test2/include/y/c.h +#error 'test2/include/y/c.h' should not have been included! + +#--- test2/include/y/d.h +#error 'test2/include/y/d.h' should not have been included! + +#--- test2/include/y/e.h + +#--- test2/include/z/a.h +#error 'test2/include/z/a.h' should not have been included! + +#--- test2/include/z/b.h +#error 'test2/include/z/b.h' should not have been included! + +#--- test2/include/z/c.h +#error 'test2/include/z/c.h' should not have been included! + +#--- test2/include/z/d.h +#error 'test2/include/z/d.h' should not have been included! + +#--- test2/include/z/e.h +#error 'test2/include/z/e.h' should not have been included! + +#--- test2/include/y/f.h + + +// Test 3: Validate ordering and duplicate elimination across the Angled and +// System groups. +// +// RUN: %clang \ +// RUN: -target x86_64-unknown-linux-gnu -v -fsyntax-only \ +// RUN: -nostdinc \ +// RUN: -I%t/test3/include/y \ +// RUN: -iexternal %t/test3/include/u \ +// RUN: -I%t/test3/include/v \ +// RUN: -isystem %t/test3/include/y \ +// RUN: -iexternal %t/test3/include/w \ +// RUN: -isystem %t/test3/include/z \ +// RUN: -I%t/test3/include/x \ +// RUN: -isystem %t/test3/include/u \ +// RUN: -iexternal %t/test3/include/x \ +// RUN: %t/test3/t.c 2>&1 | FileCheck -DPWD=%t %t/test3/t.c + +#--- test3/t.c +#include +#include +#include +#include +#include +#include + +// CHECK: ignoring duplicate directory "[[PWD]]/test3/include/x" +// CHECK-NEXT: as it is a non-system directory that duplicates a system directory +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test3/include/y" +// CHECK-NEXT: as it is a non-system directory that duplicates a system directory +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test3/include/u" +// CHECK-NEXT: #include "..." search starts here: +// CHECK-NEXT: #include <...> search starts here: +// CHECK-NEXT: [[PWD]]/test3/include/u +// CHECK-NEXT: [[PWD]]/test3/include/v +// CHECK-NEXT: [[PWD]]/test3/include/w +// CHECK-NEXT: [[PWD]]/test3/include/x +// CHECK-NEXT: [[PWD]]/test3/include/y +// CHECK-NEXT: [[PWD]]/test3/include/z +// CHECK-NEXT: End of search list. + +#--- test3/include/u/a.h + +#--- test3/include/v/a.h +#error 'test3/include/v/a.h' should not have been included! + +#--- test3/include/v/b.h + +#--- test3/include/w/a.h +#error 'test3/include/w/a.h' should not have been included! + +#--- test3/include/w/b.h +#error 'test3/include/w/b.h' should not have been included! + +#--- test3/include/w/c.h + +#--- test3/include/x/a.h +#error 'test3/include/x/a.h' should not have been included! + +#--- test3/include/x/b.h +#error 'test3/include/x/b.h' should not have been included! + +#--- test3/include/x/c.h +#error 'test3/include/x/c.h' should not have been included! + +#--- test3/include/x/d.h + +#--- test3/include/y/a.h +#error 'test3/include/y/a.h' should not have been included! + +#--- test3/include/y/b.h +#error 'test3/include/y/b.h' should not have been included! + +#--- test3/include/y/c.h +#error 'test3/include/y/c.h' should not have been included! + +#--- test3/include/y/d.h +#error 'test3/include/y/d.h' should not have been included! + +#--- test3/include/y/e.h + +#--- test3/include/z/a.h +#error 'test3/include/z/a.h' should not have been included! + +#--- test3/include/z/b.h +#error 'test3/include/z/b.h' should not have been included! + +#--- test3/include/z/c.h +#error 'test3/include/z/c.h' should not have been included! + +#--- test3/include/z/d.h +#error 'test3/include/z/d.h' should not have been included! + +#--- test3/include/z/e.h +#error 'test3/include/z/e.h' should not have been included! + +#--- test3/include/z/f.h + + +// Test 4: Validate ordering and duplicate elimination across the Angled and +// System groups. +// +// RUN: env EXTRA_INCLUDE="%t/test4/include/w" \ +// RUN: %clang \ +// RUN: -target x86_64-unknown-linux-gnu -v -fsyntax-only \ +// RUN: -nostdinc \ +// RUN: -I%t/test4/include/z \ +// RUN: -iexternal %t/test4/include/v \ +// RUN: -iexternal-env=EXTRA_INCLUDE \ +// RUN: -isystem %t/test4/include/x \ +// RUN: -isystem %t/test4/include/y \ +// RUN: -isystem %t/test4/include/x \ +// RUN: -isystem %t/test4/include/w \ +// RUN: -isystem %t/test4/include/v \ +// RUN: -isystem %t/test4/include/z \ +// RUN: %t/test4/t.c 2>&1 | FileCheck -DPWD=%t %t/test4/t.c + +#--- test4/t.c +#include +#include +#include +#include +#include + +// CHECK: ignoring duplicate directory "[[PWD]]/test4/include/x" +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test4/include/w" +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test4/include/v" +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test4/include/z" +// CHECK-NEXT: as it is a non-system directory that duplicates a system directory +// CHECK-NEXT: #include "..." search starts here: +// CHECK-NEXT: #include <...> search starts here: +// CHECK-NEXT: [[PWD]]/test4/include/v +// CHECK-NEXT: [[PWD]]/test4/include/w +// CHECK-NEXT: [[PWD]]/test4/include/x +// CHECK-NEXT: [[PWD]]/test4/include/y +// CHECK-NEXT: [[PWD]]/test4/include/z +// CHECK-NEXT: End of search list. + +#--- test4/include/v/a.h + +#--- test4/include/w/a.h +#error 'test4/include/w/a.h' should not have been included! + +#--- test4/include/w/b.h + +#--- test4/include/x/a.h +#error 'test4/include/x/a.h' should not have been included! + +#--- test4/include/x/b.h +#error 'test4/include/x/b.h' should not have been included! + +#--- test4/include/x/c.h + +#--- test4/include/y/a.h +#error 'test4/include/y/a.h' should not have been included! + +#--- test4/include/y/b.h +#error 'test4/include/y/b.h' should not have been included! + +#--- test4/include/y/c.h +#error 'test4/include/y/c.h' should not have been included! + +#--- test4/include/y/d.h + +#--- test4/include/z/a.h +#error 'test4/include/z/a.h' should not have been included! + +#--- test4/include/z/b.h +#error 'test4/include/z/b.h' should not have been included! + +#--- test4/include/z/c.h +#error 'test4/include/z/c.h' should not have been included! + +#--- test4/include/z/d.h +#error 'test4/include/z/d.h' should not have been included! + +#--- test4/include/z/e.h diff --git a/clang/test/Driver/microsoft-header-search-duplicates.c b/clang/test/Driver/microsoft-header-search-duplicates.c new file mode 100644 index 0000000000000..3a6d5fadd066d --- /dev/null +++ b/clang/test/Driver/microsoft-header-search-duplicates.c @@ -0,0 +1,644 @@ +// Test that pruning of header search paths emulates MSVC behavior when in +// Microsoft compatibility mode. See header-search-duplicates.c for GCC +// compatible behavior. + +// This test uses the '-nobuiltininc', '-nostdinc', and '/X ('-nostdlibinc') +// options to suppress implicit header search paths to ease testing. + +// Header search paths are processed as follows: +// 1) Paths specified by the '/I' and '/external:I' options are processed in +// order. +// 1.1) Paths specified by '/I' that duplicate a path specified by +// '/external:I' are ignored regardless of the option order. +// 1.2) Paths specified by '/I' that duplicate a prior '/I' option are +// ignored. +// 1.3) Paths specified by '/external:I' that duplicate a later +// '/external:I' option are ignored. +// 2) Paths specified by the '/external:env' options are processed in order. +// Paths that duplicate a path from step 1, a prior '/external:env' option, +// or a prior path from the current '/external:env' option are ignored. +// 3) Paths specified by the 'INCLUDE' environment variable are processed in +// order. Paths that duplicate a path from step 1, step 2, or an earlier +// path in the 'INCLUDE' environment variable are ignored. +// 4) Paths specified by the 'EXTERNAL_INCLUDE' environment variable are +// processed in order. Paths that duplicate a path from step 1, step 2, +// step 3, or an earlier path in the 'EXTERNAL_INCLUDE' environment +// variable are ignored. + +// RUN: rm -rf %t +// RUN: split-file %s %t + + +// Test 1: Validate ordering and duplicate elimination for /I. +// +// RUN: %clang \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -fheader-search=microsoft \ +// RUN: -nostdinc \ +// RUN: -I%t/test1/include/y \ +// RUN: -I%t/test1/include/z \ +// RUN: -I%t/test1/include/y \ +// RUN: %t/test1/t.c 2>&1 | FileCheck -DPWD=%t %t/test1/t.c +// RUN: %clang_cl \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -nobuiltininc /X \ +// RUN: /I%t/test1/include/y \ +// RUN: /I%t/test1/include/z \ +// RUN: /I%t/test1/include/y \ +// RUN: %t/test1/t.c 2>&1 | FileCheck -DPWD=%t %t/test1/t.c + +#--- test1/t.c +#include +#include + +// CHECK: ignoring duplicate directory "[[PWD]]/test1/include/y" +// CHECK-NEXT: #include "..." search starts here: +// CHECK-NEXT: #include <...> search starts here: +// CHECK-NEXT: [[PWD]]/test1/include/y +// CHECK-NEXT: [[PWD]]/test1/include/z +// CHECK-NEXT: End of search list. + +#--- test1/include/y/a.h + +#--- test1/include/z/a.h +#error 'test1/include/z/a.h' should not have been included! + +#--- test1/include/z/b.h + + +// Test 2: Validate ordering and duplicate elimination for /external:I. +// +// RUN: %clang \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -fheader-search=microsoft \ +// RUN: -nostdinc \ +// RUN: -iexternal %t/test2/include/z \ +// RUN: -iexternal %t/test2/include/y \ +// RUN: -iexternal %t/test2/include/z \ +// RUN: %t/test2/t.c 2>&1 | FileCheck -DPWD=%t %t/test2/t.c +// RUN: %clang_cl \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -nobuiltininc /X \ +// RUN: /external:I %t/test2/include/z \ +// RUN: /external:I %t/test2/include/y \ +// RUN: /external:I %t/test2/include/z \ +// RUN: %t/test2/t.c 2>&1 | FileCheck -DPWD=%t %t/test2/t.c + +#--- test2/t.c +#include +#include + +// CHECK: ignoring duplicate directory "[[PWD]]/test2/include/z" +// CHECK-NEXT: #include "..." search starts here: +// CHECK-NEXT: #include <...> search starts here: +// CHECK-NEXT: [[PWD]]/test2/include/y +// CHECK-NEXT: [[PWD]]/test2/include/z +// CHECK-NEXT: End of search list. + +#--- test2/include/y/a.h + +#--- test2/include/z/a.h +#error 'test2/include/z/a.h' should not have been included! + +#--- test2/include/z/b.h + + +// Test 3: Validate ordering and duplicate elimination for /I vs /external:I. +// +// RUN: %clang \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -fheader-search=microsoft \ +// RUN: -nostdinc \ +// RUN: -iexternal %t/test3/include/w \ +// RUN: -I%t/test3/include/z \ +// RUN: -I%t/test3/include/x \ +// RUN: -I%t/test3/include/w \ +// RUN: -iexternal %t/test3/include/y \ +// RUN: -iexternal %t/test3/include/z \ +// RUN: %t/test3/t.c 2>&1 | FileCheck -DPWD=%t %t/test3/t.c +// RUN: %clang_cl \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -nobuiltininc /X \ +// RUN: /external:I %t/test3/include/w \ +// RUN: /I%t/test3/include/z \ +// RUN: /I%t/test3/include/x \ +// RUN: /I%t/test3/include/w \ +// RUN: /external:I %t/test3/include/y \ +// RUN: /external:I %t/test3/include/z \ +// RUN: %t/test3/t.c 2>&1 | FileCheck -DPWD=%t %t/test3/t.c + +#--- test3/t.c +#include +#include +#include +#include + +// CHECK: ignoring duplicate directory "[[PWD]]/test3/include/w" +// CHECK-NEXT: as it is a non-system directory that duplicates a system directory +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test3/include/z" +// CHECK-NEXT: as it is a non-system directory that duplicates a system directory +// CHECK-NEXT: #include "..." search starts here: +// CHECK-NEXT: #include <...> search starts here: +// CHECK-NEXT: [[PWD]]/test3/include/w +// CHECK-NEXT: [[PWD]]/test3/include/x +// CHECK-NEXT: [[PWD]]/test3/include/y +// CHECK-NEXT: [[PWD]]/test3/include/z +// CHECK-NEXT: End of search list. + +#--- test3/include/w/a.h + +#--- test3/include/x/a.h +#error 'test3/include/x/a.h' should not have been included! + +#--- test3/include/x/b.h + +#--- test3/include/y/a.h +#error 'test3/include/y/a.h' should not have been included! + +#--- test3/include/y/b.h +#error 'test3/include/y/b.h' should not have been included! + +#--- test3/include/y/c.h + +#--- test3/include/z/a.h +#error 'test3/include/z/a.h' should not have been included! + +#--- test3/include/z/b.h +#error 'test3/include/z/b.h' should not have been included! + +#--- test3/include/z/c.h +#error 'test3/include/z/c.h' should not have been included! + +#--- test3/include/z/d.h + + +// Test 4: Validate ordering and duplicate elimination for /external:env. +// +// RUN: env EXTRA_INCLUDE1="%t/test4/include/y" \ +// RUN: env EXTRA_INCLUDE2="%t/test4/include/z%{pathsep}%t/test4/include/y%{pathsep}%t/test4/include/x%{pathsep}%t/test4/include/w" \ +// RUN: %clang \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -fheader-search=microsoft \ +// RUN: -nostdinc \ +// RUN: -I%t/test4/include/w \ +// RUN: -iexternal %t/test4/include/x \ +// RUN: -iexternal-env=EXTRA_INCLUDE1 \ +// RUN: -iexternal-env=EXTRA_INCLUDE2 \ +// RUN: %t/test4/t.c 2>&1 | FileCheck -DPWD=%t %t/test4/t.c +// RUN: env EXTRA_INCLUDE1="%t/test4/include/y" \ +// RUN: env EXTRA_INCLUDE2="%t/test4/include/z%{pathsep}%t/test4/include/y%{pathsep}%t/test4/include/x%{pathsep}%t/test4/include/w" \ +// RUN: %clang_cl \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -nobuiltininc /X \ +// RUN: /I%t/test4/include/w \ +// RUN: /external:I %t/test4/include/x \ +// RUN: /external:env:EXTRA_INCLUDE1 \ +// RUN: /external:env:EXTRA_INCLUDE2 \ +// RUN: %t/test4/t.c 2>&1 | FileCheck -DPWD=%t %t/test4/t.c + +#--- test4/t.c +#include +#include +#include +#include + +// CHECK: ignoring duplicate directory "[[PWD]]/test4/include/y" +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test4/include/x" +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test4/include/w" +// CHECK-NEXT: #include "..." search starts here: +// CHECK-NEXT: #include <...> search starts here: +// CHECK-NEXT: [[PWD]]/test4/include/w +// CHECK-NEXT: [[PWD]]/test4/include/x +// CHECK-NEXT: [[PWD]]/test4/include/y +// CHECK-NEXT: [[PWD]]/test4/include/z +// CHECK-NEXT: End of search list. + +#--- test4/include/w/a.h + +#--- test4/include/x/a.h +#error 'test4/include/x/a.h' should not have been included! + +#--- test4/include/x/b.h + +#--- test4/include/y/a.h +#error 'test4/include/y/a.h' should not have been included! + +#--- test4/include/y/b.h +#error 'test4/include/y/b.h' should not have been included! + +#--- test4/include/y/c.h + +#--- test4/include/z/a.h +#error 'test4/include/z/a.h' should not have been included! + +#--- test4/include/z/b.h +#error 'test4/include/z/b.h' should not have been included! + +#--- test4/include/z/c.h +#error 'test4/include/z/c.h' should not have been included! + +#--- test4/include/z/d.h + + +// Test 5: Validate ordering and duplicate elimination for the INCLUDE and +// EXTERNAL_INCLUDE environment variables. +// +// RUN: env EXTRA_INCLUDE="%t/test5/include/w" \ +// RUN: env INCLUDE="%t/test5/include/x%{pathsep}%t/test5/include/y%{pathsep}%t/test5/include/w%{pathsep}%t/test5/include/v%{pathsep}%t/test5/include/u" \ +// RUN: env EXTERNAL_INCLUDE="%t/test5/include/z%{pathsep}%t/test5/include/y%{pathsep}%t/test5/include/w%{pathsep}%t/test5/include/v%{pathsep}%t/test5/include/u" \ +// RUN: %clang \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -fheader-search=microsoft \ +// RUN: -nostdinc \ +// RUN: -I%t/test5/include/u \ +// RUN: -iexternal %t/test5/include/v \ +// RUN: -iexternal-env=EXTRA_INCLUDE \ +// RUN: -isystem-env=INCLUDE \ +// RUN: -iexternal-env=EXTERNAL_INCLUDE \ +// RUN: %t/test5/t.c 2>&1 | FileCheck -DPWD=%t %t/test5/t.c +// RUN: env EXTRA_INCLUDE="%t/test5/include/w" \ +// RUN: env INCLUDE="%t/test5/include/x%{pathsep}%t/test5/include/y%{pathsep}%t/test5/include/w%{pathsep}%t/test5/include/v%{pathsep}%t/test5/include/u" \ +// RUN: env EXTERNAL_INCLUDE="%t/test5/include/z%{pathsep}%t/test5/include/y%{pathsep}%t/test5/include/w%{pathsep}%t/test5/include/v%{pathsep}%t/test5/include/u" \ +// RUN: %clang_cl \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -nobuiltininc \ +// RUN: /I%t/test5/include/u \ +// RUN: /external:I %t/test5/include/v \ +// RUN: /external:env:EXTRA_INCLUDE \ +// RUN: %t/test5/t.c 2>&1 | FileCheck -DPWD=%t %t/test5/t.c + +#--- test5/t.c +#include +#include +#include +#include +#include +#include + +// CHECK: ignoring duplicate directory "[[PWD]]/test5/include/w" +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test5/include/v" +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test5/include/u" +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test5/include/y" +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test5/include/w" +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test5/include/v" +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test5/include/u" +// CHECK-NEXT: #include "..." search starts here: +// CHECK-NEXT: #include <...> search starts here: +// CHECK-NEXT: [[PWD]]/test5/include/u +// CHECK-NEXT: [[PWD]]/test5/include/v +// CHECK-NEXT: [[PWD]]/test5/include/w +// CHECK-NEXT: [[PWD]]/test5/include/x +// CHECK-NEXT: [[PWD]]/test5/include/y +// CHECK-NEXT: [[PWD]]/test5/include/z +// CHECK-NEXT: End of search list. + +#--- test5/include/u/a.h + +#--- test5/include/v/a.h +#error 'test5/include/v/a.h' should not have been included! + +#--- test5/include/v/b.h + +#--- test5/include/w/a.h +#error 'test5/include/w/a.h' should not have been included! + +#--- test5/include/w/b.h +#error 'test5/include/w/b.h' should not have been included! + +#--- test5/include/w/c.h + +#--- test5/include/x/a.h +#error 'test5/include/x/a.h' should not have been included! + +#--- test5/include/x/b.h +#error 'test5/include/x/b.h' should not have been included! + +#--- test5/include/x/c.h +#error 'test5/include/x/c.h' should not have been included! + +#--- test5/include/x/d.h + +#--- test5/include/y/a.h +#error 'test5/include/y/a.h' should not have been included! + +#--- test5/include/y/b.h +#error 'test5/include/y/b.h' should not have been included! + +#--- test5/include/y/c.h +#error 'test5/include/y/c.h' should not have been included! + +#--- test5/include/y/d.h +#error 'test5/include/y/d.h' should not have been included! + +#--- test5/include/y/e.h + +#--- test5/include/z/a.h +#error 'test5/include/z/a.h' should not have been included! + +#--- test5/include/z/b.h +#error 'test5/include/z/b.h' should not have been included! + +#--- test5/include/z/c.h +#error 'test5/include/z/c.h' should not have been included! + +#--- test5/include/z/d.h +#error 'test5/include/z/d.h' should not have been included! + +#--- test5/include/z/e.h +#error 'test5/include/z/e.h' should not have been included! + +#--- test5/include/z/f.h + + +// Test 6: Validate that warning suppression is goverened by external include +// path matching regardless of include path order. +// +// RUN: env EXTRA_INCLUDE="%t/test6/include/x" \ +// RUN: env INCLUDE="%t/test6/include/y" \ +// RUN: env EXTERNAL_INCLUDE="%t/test6/include/z" \ +// RUN: %clang \ +// RUN: -Xclang -verify \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -fheader-search=microsoft \ +// RUN: -nostdinc \ +// RUN: -Wall \ +// RUN: -Wno-system-headers \ +// RUN: -I%t/test6/include/v \ +// RUN: -I%t/test6/include/w \ +// RUN: -iexternal %t/test6/include/w \ +// RUN: -I%t/test6/include/x \ +// RUN: -I%t/test6/include/y \ +// RUN: -I%t/test6/include/z \ +// RUN: -iexternal-env=EXTRA_INCLUDE \ +// RUN: -isystem-env=INCLUDE \ +// RUN: -iexternal-env=EXTERNAL_INCLUDE \ +// RUN: %t/test6/t.c 2>&1 | FileCheck -DPWD=%t %t/test6/t.c +// RUN: env EXTRA_INCLUDE="%t/test6/include/x" \ +// RUN: env INCLUDE="%t/test6/include/y" \ +// RUN: env EXTERNAL_INCLUDE="%t/test6/include/z" \ +// RUN: %clang_cl \ +// RUN: -Xclang -verify \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -nobuiltininc \ +// RUN: /W4 \ +// RUN: /external:W0 \ +// RUN: /I%t/test6/include/v \ +// RUN: /I%t/test6/include/w \ +// RUN: /external:I %t/test6/include/w \ +// RUN: /I%t/test6/include/x \ +// RUN: /I%t/test6/include/y \ +// RUN: /I%t/test6/include/z \ +// RUN: /external:env:EXTRA_INCLUDE \ +// RUN: %t/test6/t.c 2>&1 | FileCheck -DPWD=%t %t/test6/t.c + +#--- test6/t.c +#include +#include +#include +#include +#include + +// CHECK: ignoring duplicate directory "[[PWD]]/test6/include/w" +// CHECK-NEXT: as it is a non-system directory that duplicates a system directory +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test6/include/x" +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test6/include/y" +// CHECK-NEXT: ignoring duplicate directory "[[PWD]]/test6/include/z" +// CHECK-NEXT: #include "..." search starts here: +// CHECK-NEXT: #include <...> search starts here: +// CHECK-NEXT: [[PWD]]/test6/include/v +// CHECK-NEXT: [[PWD]]/test6/include/w +// CHECK-NEXT: [[PWD]]/test6/include/x +// CHECK-NEXT: [[PWD]]/test6/include/y +// CHECK-NEXT: [[PWD]]/test6/include/z +// CHECK-NEXT: End of search list. +// CHECK-NOT: diagnostics seen but not expected +// CHECK-NOT: diagnostics expected but not seen + +#--- test6/include/v/a.h +// expected-warning@+1 {{shift count >= width of type}} +int va = 1 << 1024; + +#--- test6/include/w/a.h +#error 'test6/include/w/a.h' should not have been included! + +#--- test6/include/w/b.h +int wb = 1 << 1024; // Warning should be suppressed. + +#--- test6/include/x/a.h +#error 'test6/include/x/a.h' should not have been included! + +#--- test6/include/x/b.h +#error 'test6/include/x/b.h' should not have been included! + +#--- test6/include/x/c.h +int xc = 1 << 1024; // Warning should be suppressed. + +#--- test6/include/y/a.h +#error 'test6/include/y/a.h' should not have been included! + +#--- test6/include/y/b.h +#error 'test6/include/y/b.h' should not have been included! + +#--- test6/include/y/c.h +#error 'test6/include/y/c.h' should not have been included! + +#--- test6/include/y/d.h +// expected-warning@+1 {{shift count >= width of type}} +int yd = 1 << 1024; // Warning should NOT be suppressed. + +#--- test6/include/z/a.h +#error 'test6/include/z/a.h' should not have been included! + +#--- test6/include/z/b.h +#error 'test6/include/z/b.h' should not have been included! + +#--- test6/include/z/c.h +#error 'test6/include/z/c.h' should not have been included! + +#--- test6/include/z/d.h +#error 'test6/include/z/d.h' should not have been included! + +#--- test6/include/z/e.h +int ze = 1 << 1024; // Warning should be suppressed. + + +// Test 7: Validate that warning suppression for a header file included via a +// -I specified path is goverened by an external include path that is a partial +// match for the resolved header file path (even if the #include directive would +// not have matched relative to the external path). Note that partial matching +// includes matching portions of the final path component even if the paths +// would otherwise select distinct files or directories. +// +// RUN: %clang \ +// RUN: -Xclang -verify \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -fheader-search=microsoft \ +// RUN: -nostdinc \ +// RUN: -Wall \ +// RUN: -Wno-system-headers \ +// RUN: -I%t/test7/include/w \ +// RUN: -I%t/test7/include/x \ +// RUN: -I%t/test7/include/y \ +// RUN: -I%t/test7/include/z \ +// RUN: -iexternal %t/test7/include/x/foo \ +// RUN: -iexternal %t/test7/include/y/fo \ +// RUN: -iexternal %t/test7/include/z/f \ +// RUN: %t/test7/t.c 2>&1 | FileCheck -DPWD=%t %t/test7/t.c +// RUN: %clang_cl \ +// RUN: -Xclang -verify \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -nobuiltininc /X \ +// RUN: /W4 \ +// RUN: /external:W0 \ +// RUN: /I%t/test7/include/w \ +// RUN: /I%t/test7/include/x \ +// RUN: /I%t/test7/include/y \ +// RUN: /I%t/test7/include/z \ +// RUN: /external:I %t/test7/include/x/foo \ +// RUN: /external:I %t/test7/include/y/fo \ +// RUN: /external:I %t/test7/include/z/f \ +// RUN: %t/test7/t.c 2>&1 | FileCheck -DPWD=%t %t/test7/t.c + +#--- test7/t.c +#include +#include +#include +#include + +// CHECK: #include "..." search starts here: +// CHECK-NEXT: #include <...> search starts here: +// CHECK-NEXT: [[PWD]]/test7/include/w +// CHECK-NEXT: [[PWD]]/test7/include/x +// CHECK-NEXT: [[PWD]]/test7/include/y +// CHECK-NEXT: [[PWD]]/test7/include/z +// CHECK-NEXT: [[PWD]]/test7/include/x/foo +// CHECK-NEXT: [[PWD]]/test7/include/y/fo +// CHECK-NEXT: End of search list. +// CHECK-NOT: diagnostics seen but not expected +// CHECK-NOT: diagnostics expected but not seen + +#--- test7/include/w/foo/a.h +// expected-warning@+1 {{shift count >= width of type}} +int wa = 1 << 1024; + +#--- test7/include/x/foo/a.h +#error 'test7/include/x/foo/a.h' should not have been included! + +#--- test7/include/x/foo/b.h +int xb = 1 << 1024; // Warning should be suppressed. + +#--- test7/include/y/foo/a.h +#error 'test7/include/y/foo/a.h' should not have been included! + +#--- test7/include/y/foo/b.h +#error 'test7/include/y/foo/b.h' should not have been included! + +#--- test7/include/y/fo/unused + +#--- test7/include/y/foo/c.h +int yc = 1 << 1024; // Warning should be suppressed. + +#--- test7/include/z/foo/a.h +#error 'test7/include/z/foo/a.h' should not have been included! + +#--- test7/include/z/foo/b.h +#error 'test7/include/z/foo/b.h' should not have been included! + +#--- test7/include/z/foo/c.h +#error 'test7/include/z/foo/c.h' should not have been included! + +#--- test7/include/z/foo/d.h +int zd = 1 << 1024; // Warning should be suppressed. + + +// Test 8: Validate that an external directory path with a trailing path +// separator is not considered a partial match for an include path where +// the path component before the trailing path separator is a prefix match +// for a longer name. +// +// RUN: %clang \ +// RUN: -Xclang -verify \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -fheader-search=microsoft \ +// RUN: -nostdinc \ +// RUN: -Wall \ +// RUN: -Wno-system-headers \ +// RUN: -I%t/test8/include/y \ +// RUN: -I%t/test8/include/z \ +// RUN: -iexternal %t/test8/include/z/fo/ \ +// RUN: %t/test8/t.c 2>&1 | FileCheck -DPWD=%t %t/test8/t.c +// RUN: %clang_cl \ +// RUN: -Xclang -verify \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -nobuiltininc /X \ +// RUN: /W4 \ +// RUN: /external:W0 \ +// RUN: /I%t/test8/include/y \ +// RUN: /I%t/test8/include/z \ +// RUN: /external:I %t/test8/include/z/fo/ \ +// RUN: %t/test8/t.c 2>&1 | FileCheck -DPWD=%t %t/test8/t.c + +#--- test8/t.c +#include +#include + +// CHECK: #include "..." search starts here: +// CHECK-NEXT: #include <...> search starts here: +// CHECK-NEXT: [[PWD]]/test8/include/y +// CHECK-NEXT: [[PWD]]/test8/include/z +// CHECK-NEXT: End of search list. +// CHECK-NOT: diagnostics seen but not expected +// CHECK-NOT: diagnostics expected but not seen + +#--- test8/include/y/foo/a.h +// expected-warning@+1 {{shift count >= width of type}} +int wa = 1 << 1024; + +#--- test8/include/z/foo/a.h +#error 'test8/include/z/foo/a.h' should not have been included! + +#--- test8/include/z/foo/b.h +// expected-warning@+1 {{shift count >= width of type}} +int zd = 1 << 1024; // Warning should NOT be suppressed. + + +// Test 9: Validate that warnings are suppressed for a header file specified +// in angle brackets (as opposed to double quotes) in a #include directive +// when the MSVC /external:anglebrackets option is enabled. +// +// RUN: %clang \ +// RUN: -Xclang -verify \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -nostdinc \ +// RUN: -Wall \ +// RUN: -Wno-system-headers \ +// RUN: -iexternal-anglebrackets \ +// RUN: -I%t/test9/include/z \ +// RUN: %t/test9/t.c 2>&1 | FileCheck -DPWD=%t %t/test9/t.c +// RUN: %clang_cl \ +// RUN: -Xclang -verify \ +// RUN: -target x86_64-pc-windows -v -fsyntax-only \ +// RUN: -nobuiltininc /X \ +// RUN: /W4 \ +// RUN: /external:W0 \ +// RUN: /external:anglebrackets \ +// RUN: /I%t/test9/include/z \ +// RUN: %t/test9/t.c 2>&1 | FileCheck -DPWD=%t %t/test9/t.c + +#--- test9/t.c +#include "a.h" +#include + +// CHECK: #include "..." search starts here: +// CHECK-NEXT: #include <...> search starts here: +// CHECK-NEXT: [[PWD]]/test9/include/z +// CHECK-NEXT: End of search list. +// CHECK-NOT: diagnostics seen but not expected +// CHECK-NOT: diagnostics expected but not seen + +#--- test9/include/z/a.h +// expected-warning@+1 {{shift count >= width of type}} +int za = 1 << 1024; + +#--- test9/include/z/b.h +int zb = 1 << 1024; // Warning should be suppressed. diff --git a/clang/test/Frontend/external-include-diags-junction-windows.c b/clang/test/Frontend/external-include-diags-junction-windows.c new file mode 100644 index 0000000000000..e39ecb1cc78db --- /dev/null +++ b/clang/test/Frontend/external-include-diags-junction-windows.c @@ -0,0 +1,73 @@ +// Test that diagnostics are appropriately suppressed for included header +// files that match an external include directory prefix. These tests +// validate external path directory prefix matching in the presence of +// junction points. Paths with partial path component matching are used +// as external include directory prefixes so that they do not nominate +// additional include paths. + +// REQUIRES: system-windows +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cmd /c mklink /J %t\inc1\foo %t\inc2\foo + +// Test 1: Validate path matching with consistent redirection through a +// junction point. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t\inc1\foo \ +// RUN: -iexternal %t\inc1\foo\b \ +// RUN: %t\should-not-warn.c + +// Test 2: Validate path matching with mismatched redirection through a +// junction point. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t\inc1\foo \ +// RUN: -iexternal %t\inc2\fo \ +// RUN: %t\should-warn.c +// RUN: %clang_cc1 \ +// RUN: -triple x86_64-unknown-linux-gnu -fsyntax-only -verify \ +// RUN: -Wall -Wno-system-headers \ +// RUN: -I%t\inc2\foo \ +// RUN: -iexternal %t\inc1\fo \ +// RUN: %t\should-warn.c + +// Test 3: Validate path matching with mismatched redirection through a +// junction point with path normalization removal of unnecessary ".." path +// components. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t\inc1\foo\..\foo \ +// RUN: -iexternal %t\inc1\fo \ +// RUN: %t\should-not-warn.c +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t\inc1\foo \ +// RUN: -iexternal %t\inc1\foo\..\fo \ +// RUN: %t\should-not-warn.c + +#--- should-not-warn.c +#include +// Validate that a warning is actually issued for test code intended to +// solicit a warning and that suppression of such a warning in an included +// header file does not affect warnings issued for other files. +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- should-warn.c +#include +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- inc1/unused.txt +Unused file used to ensure directory creation. + +#--- inc2/foo/bar/should-not-warn.h +int h = 1 << 1024; // Warning should be suppressed. + +#--- inc2/foo/bar/should-warn.h +// expected-warning@+1 {{shift count >= width of type}} +int h = 1 << 1024; // Warning should not be suppressed. diff --git a/clang/test/Frontend/external-include-diags-normalized-windows.c b/clang/test/Frontend/external-include-diags-normalized-windows.c new file mode 100644 index 0000000000000..f3a6d7006a266 --- /dev/null +++ b/clang/test/Frontend/external-include-diags-normalized-windows.c @@ -0,0 +1,35 @@ +// Test that diagnostics are appropriately suppressed for included header +// files that match an external include directory prefix. These tests +// validate external path directory prefix matching in the presence of +// mismatched path separators. Paths with partial path component matching +// are used as external include directory prefixes so that they do not +// nominate additional include paths. + +// REQUIRES: system-windows +// RUN: rm -rf %t +// RUN: split-file %s %t + +// Test 1: Validate path matching for mismatched presence of "/" and +// "\" path separators. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc/foo \ +// RUN: -iexternal %t/inc\fo \ +// RUN: %t/should-not-warn.c +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc\foo \ +// RUN: -iexternal %t/inc/fo \ +// RUN: %t/should-not-warn.c + +#--- should-not-warn.c +#include +// Validate that a warning is actually issued for test code intended to +// solicit a warning and that suppression of such a warning in an included +// header file does not affect warnings issued for other files. +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- inc/foo/bar/should-not-warn.h +int h = 1 << 1024; // Warning should be suppressed. diff --git a/clang/test/Frontend/external-include-diags-normalized.c b/clang/test/Frontend/external-include-diags-normalized.c new file mode 100644 index 0000000000000..d82476a450d3c --- /dev/null +++ b/clang/test/Frontend/external-include-diags-normalized.c @@ -0,0 +1,74 @@ +// Test that diagnostics are appropriately suppressed for included header +// files that match an external include directory prefix. These tests +// validate external path directory prefix matching in the presence of +// mismatched duplicate path separators and "." and ".." path components. +// Paths with partial path component matching are used as external include +// directory prefixes so that they do not nominate additional include paths. + +// RUN: rm -rf %t +// RUN: split-file %s %t + +// Test 1: Validate path matching for mismatched presence of "." path +// components. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc/./foo \ +// RUN: -iexternal %t/inc/fo \ +// RUN: %t/should-not-warn.c +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc/foo \ +// RUN: -iexternal %t/inc/./fo \ +// RUN: %t/should-not-warn.c + +// Test 2: Validate path matching for mismatched presence of ".." path +// components. Note that path normalization of an include path will not +// remove ".." path components for a non-existent parent path. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc/foo \ +// RUN: -iexternal %t/inc/no-such-dir/../fo \ +// RUN: %t/should-not-warn.c + +// Test 3: Validate path matching for mismatched duplication of path +// separators. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc//foo \ +// RUN: -iexternal %t/inc/fo \ +// RUN: %t/should-not-warn.c +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc/foo \ +// RUN: -iexternal %t/inc//fo \ +// RUN: %t/should-not-warn.c + +// Test 4: Validate path matching for mismatched relative and +// absolute paths. +// +// RUN: pushd %t +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -Iinc/foo \ +// RUN: -iexternal %t/inc/fo \ +// RUN: %t/should-not-warn.c +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc/foo \ +// RUN: -iexternal inc/fo \ +// RUN: %t/should-not-warn.c +// RUN: popd + +#--- should-not-warn.c +#include +// Validate that a warning is actually issued for test code intended to +// solicit a warning and that suppression of such a warning in an included +// header file does not affect warnings issued for other files. +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- inc/foo/bar/should-not-warn.h +int h = 1 << 1024; // Warning should be suppressed. diff --git a/clang/test/Frontend/external-include-diags-space.c b/clang/test/Frontend/external-include-diags-space.c new file mode 100644 index 0000000000000..d3911894a9b21 --- /dev/null +++ b/clang/test/Frontend/external-include-diags-space.c @@ -0,0 +1,47 @@ +// Test that diagnostics are appropriately suppressed for included header +// files that match an external include directory prefix. These tests +// validate external path directory prefix matching in the presence of +// path components that contain space characters. Paths with partial path +// component matching are used as external include directory prefixes so +// that they do not nominate additional include paths. + +// RUN: rm -rf %t +// RUN: split-file %s %t + +// Test 1: Validate path matching for directories that contain spaces. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I"%t/inc/dir with spaces" \ +// RUN: -iexternal "%t/inc/dir with" \ +// RUN: %t/dir-with-spaces.c + +// Test 2: Validate path matching for files that contain spaces. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc/foo \ +// RUN: -iexternal "%t/inc/foo/bar/should not" \ +// RUN: %t/file-with-spaces.c + +#--- dir-with-spaces.c +#include +// Validate that a warning is actually issued for test code intended to +// solicit a warning and that suppression of such a warning in an included +// header file does not affect warnings issued for other files. +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- inc/dir with spaces/bar/should-not-warn.h +int h = 1 << 1024; // Warning should be suppressed. + +#--- file-with-spaces.c +#include +// Validate that a warning is actually issued for test code intended to +// solicit a warning and that suppression of such a warning in an included +// header file does not affect warnings issued for other files. +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- inc/foo/bar/should not warn.h +int h = 1 << 1024; // Warning should be suppressed. diff --git a/clang/test/Frontend/external-include-diags-symlink-dir-windows.c b/clang/test/Frontend/external-include-diags-symlink-dir-windows.c new file mode 100644 index 0000000000000..486711447bc65 --- /dev/null +++ b/clang/test/Frontend/external-include-diags-symlink-dir-windows.c @@ -0,0 +1,91 @@ +// Test that diagnostics are appropriately suppressed for included header +// files that match an external include directory prefix. These tests +// validate external path directory prefix matching in the presence of +// directory symbolic links. Paths with partial path component matching +// are used as external include directory prefixes so that they do not +// nominate additional include paths. + +// REQUIRES: system-windows +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cmd /c mklink /D %t\inc1\foo ..\inc2\foo +// RUN: cmd /c mklink /D %t\inc1\goo\baz . + +// Test 1: Validate path matching with consistent redirection through a +// symbolic link. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t\inc1\foo \ +// RUN: -iexternal %t\inc1\foo\b \ +// RUN: %t\should-not-warn.c + +// Test 2: Validate path matching with mismatched redirection through a +// symbolic link. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t\inc1\foo \ +// RUN: -iexternal %t\inc2\fo \ +// RUN: %t\should-warn.c +// RUN: %clang_cc1 \ +// RUN: -triple x86_64-unknown-linux-gnu -fsyntax-only -verify \ +// RUN: -Wall -Wno-system-headers \ +// RUN: -I%t\inc2\foo \ +// RUN: -iexternal %t\inc1\fo \ +// RUN: %t\should-warn.c + +// Test 3: Validate path matching with mismatched redirection through a +// symbolic link with path normalization removal of unnecessary ".." path +// components. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t\inc1\foo\..\foo \ +// RUN: -iexternal %t\inc1\fo \ +// RUN: %t\should-not-warn.c +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t\inc1\foo \ +// RUN: -iexternal %t\inc1\foo\..\fo \ +// RUN: %t\should-not-warn.c + +// Test 4: Validate path matching with mismatched redirection through a +// symbolic link for which removal of ".." path components is not possible. +// The first case below is disabled because MSVC does not follow the +// symbolic link and ".." path component to arrive at a directory where +// "foo" is present and thus fails to resolve the header file. +// +// XXX: %clang_cc1 \ +// XXX: -fsyntax-only -verify -Wall -Wno-system-headers \ +// XXX: -I%t\inc1\goo\baz\..\foo \ +// XXX: -iexternal %t\inc2\fo \ +// XXX: %t\should-warn.c +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t\inc2\foo \ +// RUN: -iexternal %t\inc1\goo\baz\..\fo \ +// RUN: %t\should-warn.c + +#--- should-not-warn.c +#include +// Validate that a warning is actually issued for test code intended to +// solicit a warning and that suppression of such a warning in an included +// header file does not affect warnings issued for other files. +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- should-warn.c +#include +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- inc1/goo/unused.txt +Unused file used to ensure directory creation. + +#--- inc2/foo/bar/should-not-warn.h +int h = 1 << 1024; // Warning should be suppressed. + +#--- inc2/foo/bar/should-warn.h +// expected-warning@+1 {{shift count >= width of type}} +int h = 1 << 1024; // Warning should not be suppressed. diff --git a/clang/test/Frontend/external-include-diags-symlink-dir.c b/clang/test/Frontend/external-include-diags-symlink-dir.c new file mode 100644 index 0000000000000..f1b1f4bfaa785 --- /dev/null +++ b/clang/test/Frontend/external-include-diags-symlink-dir.c @@ -0,0 +1,88 @@ +// Test that diagnostics are appropriately suppressed for included header +// files that match an external include directory prefix. These tests +// validate external path directory prefix matching in the presence of +// directory symbolic links. Paths with partial path component matching +// are used as external include directory prefixes so that they do not +// nominate additional include paths. + +// REQUIRES: !system-windows +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: ln -sf ../inc2/foo %t/inc1/foo +// RUN: ln -sf . %t/inc1/goo/baz + +// Test 1: Validate path matching with consistent redirection through a +// symbolic link. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc1/foo \ +// RUN: -iexternal %t/inc1/foo/b \ +// RUN: %t/should-not-warn.c + +// Test 2: Validate path matching with mismatched redirection through a +// symbolic link. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc1/foo \ +// RUN: -iexternal %t/inc2/fo \ +// RUN: %t/should-warn.c +// RUN: %clang_cc1 \ +// RUN: -triple x86_64-unknown-linux-gnu -fsyntax-only -verify \ +// RUN: -Wall -Wno-system-headers \ +// RUN: -I%t/inc2/foo \ +// RUN: -iexternal %t/inc1/fo \ +// RUN: %t/should-warn.c + +// Test 3: Validate path matching with mismatched redirection through a +// symbolic link with path normalization removal of unnecessary ".." path +// components. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc1/foo/../foo \ +// RUN: -iexternal %t/inc1/fo \ +// RUN: %t/should-not-warn.c +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc1/foo \ +// RUN: -iexternal %t/inc1/foo/../fo \ +// RUN: %t/should-not-warn.c + +// Test 4: Validate path matching with mismatched redirection through a +// symbolic link for which removal of ".." path components is not possible. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc1/goo/baz/../foo \ +// RUN: -iexternal %t/inc2/fo \ +// RUN: %t/should-warn.c +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc2/foo \ +// RUN: -iexternal %t/inc1/goo/baz/../fo \ +// RUN: %t/should-warn.c + +#--- should-not-warn.c +#include +// Validate that a warning is actually issued for test code intended to +// solicit a warning and that suppression of such a warning in an included +// header file does not affect warnings issued for other files. +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- should-warn.c +#include +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- inc1/goo/unused.txt +Unused file used to ensure directory creation. + +#--- inc2/foo/bar/should-not-warn.h +int h = 1 << 1024; // Warning should be suppressed. + +#--- inc2/foo/bar/should-warn.h +// expected-warning@+1 {{shift count >= width of type}} +int h = 1 << 1024; // Warning should not be suppressed. diff --git a/clang/test/Frontend/external-include-diags-symlink-file-windows.c b/clang/test/Frontend/external-include-diags-symlink-file-windows.c new file mode 100644 index 0000000000000..4238c62a2e04a --- /dev/null +++ b/clang/test/Frontend/external-include-diags-symlink-file-windows.c @@ -0,0 +1,58 @@ +// Test that diagnostics are appropriately suppressed for included header +// files that match an external include directory prefix. These tests +// validate external path directory prefix matching in the presence of +// file symbolic links. Paths with partial path component matching are +// used as external include directory prefixes so that they do not nominate +// additional include paths. + +// REQUIRES: system-windows +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cmd /c mklink %t\inc1\foo\bar\should-warn.h ..\..\..\inc2\foo\bar\should-warn.h +// RUN: cmd /c mklink %t\inc1\foo\bar\should-not-warn.h ..\..\..\inc2\foo\bar\should-not-warn.h + +// Test 1: Validate path matching with consistent redirection through a +// symbolic link. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t\inc1\foo \ +// RUN: -iexternal %t\inc1\foo\bar\sh \ +// RUN: %t\should-not-warn.c + +// Test 2: Validate path matching with mismatched redirection through a +// symbolic link. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t\inc1\foo \ +// RUN: -iexternal %t\inc2\fo \ +// RUN: %t\should-warn.c +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t\inc2\foo \ +// RUN: -iexternal %t\inc1\fo \ +// RUN: %t\should-warn.c + +#--- should-not-warn.c +#include +// Validate that a warning is actually issued for test code intended to +// solicit a warning and that suppression of such a warning in an included +// header file does not affect warnings issued for other files. +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- should-warn.c +#include +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- inc1/foo/bar/unused.txt +Unused file used to ensure directory creation. + +#--- inc2/foo/bar/should-not-warn.h +int h = 1 << 1024; // Warning should be suppressed. + +#--- inc2/foo/bar/should-warn.h +// expected-warning@+1 {{shift count >= width of type}} +int h = 1 << 1024; // Warning should not be suppressed. diff --git a/clang/test/Frontend/external-include-diags-symlink-file.c b/clang/test/Frontend/external-include-diags-symlink-file.c new file mode 100644 index 0000000000000..6d21985866fc4 --- /dev/null +++ b/clang/test/Frontend/external-include-diags-symlink-file.c @@ -0,0 +1,58 @@ +// Test that diagnostics are appropriately suppressed for included header +// files that match an external include directory prefix. These tests +// validate external path directory prefix matching in the presence of +// file symbolic links. Paths with partial path component matching are +// used as external include directory prefixes so that they do not nominate +// additional include paths. + +// REQUIRES: !system-windows +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: ln -sf ../../../inc2/foo/bar/should-warn.h %t/inc1/foo/bar/should-warn.h +// RUN: ln -sf ../../../inc2/foo/bar/should-not-warn.h %t/inc1/foo/bar/should-not-warn.h + +// Test 1: Validate path matching with consistent redirection through a +// symbolic link. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc1/foo \ +// RUN: -iexternal %t/inc1/foo/bar/sh \ +// RUN: %t/should-not-warn.c + +// Test 2: Validate path matching with mismatched redirection through a +// symbolic link. +// +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc1/foo \ +// RUN: -iexternal %t/inc2/fo \ +// RUN: %t/should-warn.c +// RUN: %clang_cc1 \ +// RUN: -fsyntax-only -verify -Wall -Wno-system-headers \ +// RUN: -I%t/inc2/foo \ +// RUN: -iexternal %t/inc1/fo \ +// RUN: %t/should-warn.c + +#--- should-not-warn.c +#include +// Validate that a warning is actually issued for test code intended to +// solicit a warning and that suppression of such a warning in an included +// header file does not affect warnings issued for other files. +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- should-warn.c +#include +// expected-warning@+1 {{shift count >= width of type}} +int x = 1 << 1024; // Warning should not be suppressed. + +#--- inc1/foo/bar/unused.txt +Unused file used to ensure directory creation. + +#--- inc2/foo/bar/should-not-warn.h +int h = 1 << 1024; // Warning should be suppressed. + +#--- inc2/foo/bar/should-warn.h +// expected-warning@+1 {{shift count >= width of type}} +int h = 1 << 1024; // Warning should not be suppressed. diff --git a/clang/test/Preprocessor/microsoft-header-search-fail.c b/clang/test/Preprocessor/microsoft-header-search-fail.c index c377cb11d658a..9f8927974de93 100644 --- a/clang/test/Preprocessor/microsoft-header-search-fail.c +++ b/clang/test/Preprocessor/microsoft-header-search-fail.c @@ -1,7 +1,7 @@ // RUN: rm -rf %t // RUN: split-file %s %t -// RUN: %clang_cc1 -Eonly -fms-compatibility %t/test.c -I %t/include -verify +// RUN: %clang_cc1 -Eonly -fheader-search=microsoft %t/test.c -I %t/include -verify //--- test.c #include "x/header.h" diff --git a/clang/test/Preprocessor/microsoft-header-search.c b/clang/test/Preprocessor/microsoft-header-search.c index 875bffe8793b8..15fef1b0d184b 100644 --- a/clang/test/Preprocessor/microsoft-header-search.c +++ b/clang/test/Preprocessor/microsoft-header-search.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -I%S/Inputs/microsoft-header-search %s -fms-compatibility -verify +// RUN: %clang_cc1 -I%S/Inputs/microsoft-header-search %s -fheader-search=microsoft -verify // expected-warning@Inputs/microsoft-header-search/a/findme.h:3 {{findme.h successfully included using Microsoft header search rules}} // expected-warning@Inputs/microsoft-header-search/a/b/include3.h:3 {{#include resolved using non-portable Microsoft search rules as}} diff --git a/llvm/include/llvm/Option/ArgList.h b/llvm/include/llvm/Option/ArgList.h index 313164bc29689..bbaed97ba4711 100644 --- a/llvm/include/llvm/Option/ArgList.h +++ b/llvm/include/llvm/Option/ArgList.h @@ -290,7 +290,12 @@ class ArgList { /// getAllArgValues - Get the values of all instances of the given argument /// as strings. - LLVM_ABI std::vector getAllArgValues(OptSpecifier Id) const; + template + std::vector getAllArgValues(OptSpecifiers... Ids) const { + SmallVector Values; + AddAllArgValues(Values, Ids...); + return std::vector(Values.begin(), Values.end()); + } /// @} /// @name Translation Utilities diff --git a/llvm/lib/Option/ArgList.cpp b/llvm/lib/Option/ArgList.cpp index c4188b3b12112..8a40819905dbd 100644 --- a/llvm/lib/Option/ArgList.cpp +++ b/llvm/lib/Option/ArgList.cpp @@ -94,12 +94,6 @@ StringRef ArgList::getLastArgValue(OptSpecifier Id, StringRef Default) const { return Default; } -std::vector ArgList::getAllArgValues(OptSpecifier Id) const { - SmallVector Values; - AddAllArgValues(Values, Id); - return std::vector(Values.begin(), Values.end()); -} - void ArgList::addOptInFlag(ArgStringList &Output, OptSpecifier Pos, OptSpecifier Neg) const { if (Arg *A = getLastArg(Pos, Neg))