@@ -1015,7 +1015,17 @@ namespace clang {
1015
1015
1016
1016
// / \brief The active module.
1017
1017
Module *ActiveModule;
1018
-
1018
+
1019
+ // / \brief Whether a module uses the 'requires excluded' hack to mark its
1020
+ // / contents as 'textual'.
1021
+ // /
1022
+ // / On older Darwin SDK versions, 'requires excluded' is used to mark the
1023
+ // / contents of the Darwin.C.excluded (assert.h) and Tcl.Private modules as
1024
+ // / non-modular headers. For backwards compatibility, we continue to
1025
+ // / support this idiom for just these modules, and map the headers to
1026
+ // / 'textual' to match the original intent.
1027
+ llvm::SmallPtrSet<Module *, 2 > UsesRequiresExcludedHack;
1028
+
1019
1029
// / \brief Consume the current token and return its location.
1020
1030
SourceLocation consumeToken ();
1021
1031
@@ -1570,6 +1580,38 @@ void ModuleMapParser::parseExternModuleDecl() {
1570
1580
: File->getDir (), ExternLoc);
1571
1581
}
1572
1582
1583
+ // / Whether to add the requirement \p Feature to the module \p M.
1584
+ // /
1585
+ // / This preserves backwards compatibility for two hacks in the Darwin system
1586
+ // / module map files:
1587
+ // /
1588
+ // / 1. The use of 'requires excluded' to make headers non-modular, which
1589
+ // / should really be mapped to 'textual' now that we have this feature. We
1590
+ // / drop the 'excluded' requirement, and set \p IsRequiresExcludedHack to
1591
+ // / true. Later, this bit will be used to map all the headers inside this
1592
+ // / module to 'textual'.
1593
+ // /
1594
+ // / This affects Darwin.C.excluded (for assert.h) and Tcl.Private.
1595
+ // /
1596
+ // / 2. Removes a bogus cplusplus requirement from IOKit.avc. This requirement
1597
+ // / was never correct and causes issues now that we check it, so drop it.
1598
+ static bool shouldAddRequirement (Module *M, StringRef Feature,
1599
+ bool &IsRequiresExcludedHack) {
1600
+ static const StringRef DarwinCExcluded[] = {" Darwin" , " C" , " excluded" };
1601
+ static const StringRef TclPrivate[] = {" Tcl" , " Private" };
1602
+ static const StringRef IOKitAVC[] = {" IOKit" , " avc" };
1603
+
1604
+ if (Feature == " excluded" && (M->fullModuleNameIs (DarwinCExcluded) ||
1605
+ M->fullModuleNameIs (TclPrivate))) {
1606
+ IsRequiresExcludedHack = true ;
1607
+ return false ;
1608
+ } else if (Feature == " cplusplus" && M->fullModuleNameIs (IOKitAVC)) {
1609
+ return false ;
1610
+ }
1611
+
1612
+ return true ;
1613
+ }
1614
+
1573
1615
// / \brief Parse a requires declaration.
1574
1616
// /
1575
1617
// / requires-declaration:
@@ -1605,9 +1647,18 @@ void ModuleMapParser::parseRequiresDecl() {
1605
1647
std::string Feature = Tok.getString ();
1606
1648
consumeToken ();
1607
1649
1608
- // Add this feature.
1609
- ActiveModule->addRequirement (Feature, RequiredState,
1610
- Map.LangOpts , *Map.Target );
1650
+ bool IsRequiresExcludedHack = false ;
1651
+ bool ShouldAddRequirement =
1652
+ shouldAddRequirement (ActiveModule, Feature, IsRequiresExcludedHack);
1653
+
1654
+ if (IsRequiresExcludedHack)
1655
+ UsesRequiresExcludedHack.insert (ActiveModule);
1656
+
1657
+ if (ShouldAddRequirement) {
1658
+ // Add this feature.
1659
+ ActiveModule->addRequirement (Feature, RequiredState, Map.LangOpts ,
1660
+ *Map.Target );
1661
+ }
1611
1662
1612
1663
if (!Tok.is (MMToken::Comma))
1613
1664
break ;
@@ -1657,9 +1708,16 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
1657
1708
consumeToken ();
1658
1709
}
1659
1710
}
1711
+
1660
1712
if (LeadingToken == MMToken::TextualKeyword)
1661
1713
Role = ModuleMap::ModuleHeaderRole (Role | ModuleMap::TextualHeader);
1662
1714
1715
+ if (UsesRequiresExcludedHack.count (ActiveModule)) {
1716
+ // Mark this header 'textual' (see doc comment for
1717
+ // Module::UsesRequiresExcludedHack).
1718
+ Role = ModuleMap::ModuleHeaderRole (Role | ModuleMap::TextualHeader);
1719
+ }
1720
+
1663
1721
if (LeadingToken != MMToken::HeaderKeyword) {
1664
1722
if (!Tok.is (MMToken::HeaderKeyword)) {
1665
1723
Diags.Report (Tok.getLocation (), diag::err_mmap_expected_header)
@@ -1838,14 +1896,40 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
1838
1896
HadError = true ;
1839
1897
return ;
1840
1898
}
1841
-
1899
+
1900
+ if (UsesRequiresExcludedHack.count (ActiveModule)) {
1901
+ // Mark this header 'textual' (see doc comment for
1902
+ // ModuleMapParser::UsesRequiresExcludedHack). Although iterating over the
1903
+ // directory is relatively expensive, in practice this only applies to the
1904
+ // uncommonly used Tcl module on Darwin platforms.
1905
+ std::error_code EC;
1906
+ SmallVector<Module::Header, 6 > Headers;
1907
+ for (llvm::sys::fs::recursive_directory_iterator I (Dir->getName (), EC), E;
1908
+ I != E && !EC; I.increment (EC)) {
1909
+ if (const FileEntry *FE = SourceMgr.getFileManager ().getFile (I->path ())) {
1910
+
1911
+ Module::Header Header = {I->path (), FE};
1912
+ Headers.push_back (std::move (Header));
1913
+ }
1914
+ }
1915
+
1916
+ // Sort header paths so that the pcm doesn't depend on iteration order.
1917
+ llvm::array_pod_sort (Headers.begin (), Headers.end (),
1918
+ [](const Module::Header *A, const Module::Header *B) {
1919
+ return A->NameAsWritten .compare (B->NameAsWritten );
1920
+ });
1921
+ for (auto &Header : Headers)
1922
+ Map.addHeader (ActiveModule, std::move (Header), ModuleMap::TextualHeader);
1923
+ return ;
1924
+ }
1925
+
1842
1926
if (Module *OwningModule = Map.UmbrellaDirs [Dir]) {
1843
1927
Diags.Report (UmbrellaLoc, diag::err_mmap_umbrella_clash)
1844
1928
<< OwningModule->getFullModuleName ();
1845
1929
HadError = true ;
1846
1930
return ;
1847
- }
1848
-
1931
+ }
1932
+
1849
1933
// Record this umbrella directory.
1850
1934
Map.setUmbrellaDir (ActiveModule, Dir, DirName);
1851
1935
}
0 commit comments