@@ -366,8 +366,8 @@ void InitHeaderSearch::AddDefaultIncludePaths(
366366}
367367
368368// / If there are duplicate directory entries in the specified search list,
369- // / remove the later (dead) ones. Returns the number of non-system headers
370- // / removed, which is used to update NumAngled .
369+ // / identify and remove the ones to be ignored and issue a diagnostic.
370+ // / Returns the number of non-system search paths emoved .
371371static unsigned RemoveDuplicates (const LangOptions &Lang,
372372 std::vector<DirectoryLookupInfo> &SearchList,
373373 unsigned First, bool Verbose) {
@@ -377,41 +377,43 @@ static unsigned RemoveDuplicates(const LangOptions &Lang,
377377 unsigned NonSystemRemoved = 0 ;
378378 for (unsigned i = First; i != SearchList.size (); ++i) {
379379 unsigned DirToRemove = i;
380+ bool NonSystemDirRemoved = false ;
380381
381382 const DirectoryLookup &CurEntry = SearchList[i].Lookup ;
382383
384+ // If the current entry is for a previously unseen location, cache it and
385+ // continue with the next entry.
383386 if (CurEntry.isNormalDir ()) {
384- // If this isn't the first time we've seen this dir, remove it.
385387 if (SeenDirs.insert (CurEntry.getDir ()).second )
386388 continue ;
387389 } else if (CurEntry.isFramework ()) {
388- // If this isn't the first time we've seen this framework dir, remove it.
389390 if (SeenFrameworkDirs.insert (CurEntry.getFrameworkDir ()).second )
390391 continue ;
391392 } else {
392393 assert (CurEntry.isHeaderMap () && " Not a headermap or normal dir?" );
393- // If this isn't the first time we've seen this headermap, remove it.
394394 if (SeenHeaderMaps.insert (CurEntry.getHeaderMap ()).second )
395395 continue ;
396396 }
397397
398- // When not in MSVC compatibility mode, if we have a normal
399- // #include dir/framework/headermap that is shadowed later in the chain by
400- // a system include location, we actually want to ignore the user's request
401- // and drop the user dir... keeping the system dir. This is weird, but
402- // required to emulate GCC's search path correctly.
398+ // Pruning of duplicate search locations is intended to emulate the behavior
399+ // exhibited by GCC (by default) or MSVC (in Microsoft compatibility mode)
400+ // to ensure that #include and #include_next directives produce the same
401+ // results as these other compilers.
403402 //
404- // Since dupes of system dirs are rare, just rescan to find the original
405- // that we're nuking instead of using a DenseMap.
406- if (!Lang.MSVCCompat && CurEntry.getDirCharacteristic () != SrcMgr::C_User) {
407- // Find the dir that this is the same of.
403+ // GCC and MSVC both prune duplicate user search locations that follow a
404+ // previous matching user search location. Both compilers also prune user
405+ // search locations that are also present as system search locations
406+ // regardless of the order in which they appear. The compilers differ with
407+ // respect to pruning system search locations that duplicate a previous
408+ // system search location; GCC preserves the first such occurences while
409+ // MSVC preserves the last one.
410+ if (CurEntry.getDirCharacteristic () != SrcMgr::C_User) {
411+ // Find the matching search entry.
408412 unsigned FirstDir;
409- for (FirstDir = First;; ++FirstDir) {
410- assert (FirstDir != i && " Didn't find dupe?" );
411-
413+ for (FirstDir = First; FirstDir < i; ++FirstDir) {
412414 const DirectoryLookup &SearchEntry = SearchList[FirstDir].Lookup ;
413415
414- // If these are different lookup types, then they can't be the dupe .
416+ // Different lookup types are not considered duplicate entries .
415417 if (SearchEntry.getLookupType () != CurEntry.getLookupType ())
416418 continue ;
417419
@@ -428,21 +430,34 @@ static unsigned RemoveDuplicates(const LangOptions &Lang,
428430 if (isSame)
429431 break ;
430432 }
433+ assert (FirstDir < i && " Expected duplicate search location not found" );
431434
432- // If the first dir in the search path is a non-system dir, zap it
433- // instead of the system one.
434- if (SearchList[FirstDir]. Lookup . getDirCharacteristic () == SrcMgr::C_User)
435+ if (Lang. MSVCCompat ) {
436+ // In Microsoft compatibility mode, a later system search location entry
437+ // suppresses a previous user or system search location.
435438 DirToRemove = FirstDir;
439+ if (SearchList[FirstDir].Lookup .getDirCharacteristic () ==
440+ SrcMgr::C_User)
441+ NonSystemDirRemoved = true ;
442+ } else {
443+ // In GCC compatibility mode, a later system search location entry
444+ // suppresses a previous user search location.
445+ if (SearchList[FirstDir].Lookup .getDirCharacteristic () ==
446+ SrcMgr::C_User) {
447+ DirToRemove = FirstDir;
448+ NonSystemDirRemoved = true ;
449+ }
450+ }
436451 }
437452
438453 if (Verbose) {
439454 llvm::errs () << " ignoring duplicate directory \" "
440455 << CurEntry.getName () << " \"\n " ;
441- if (DirToRemove != i )
456+ if (NonSystemDirRemoved )
442457 llvm::errs () << " as it is a non-system directory that duplicates "
443458 << " a system directory\n " ;
444459 }
445- if (DirToRemove != i )
460+ if (NonSystemDirRemoved )
446461 ++NonSystemRemoved;
447462
448463 // This is reached if the current entry is a duplicate. Remove the
@@ -490,7 +505,8 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
490505 unsigned NumQuoted = SearchList.size ();
491506
492507 for (auto &Include : IncludePath)
493- if (Include.Group == Angled || Include.Group == IndexHeaderMap)
508+ if (Include.Group == Angled || Include.Group == IndexHeaderMap ||
509+ Include.Group == External)
494510 SearchList.push_back (Include);
495511
496512 RemoveDuplicates (Lang, SearchList, NumQuoted, Verbose);
0 commit comments