@@ -1314,6 +1314,23 @@ OptionalFileEntryRef HeaderSearch::LookupSubframeworkHeader(
1314
1314
// File Info Management.
1315
1315
// ===----------------------------------------------------------------------===//
1316
1316
1317
+ static void mergeHeaderFileInfoModuleBits (HeaderFileInfo &HFI,
1318
+ bool isModuleHeader,
1319
+ bool isTextualModuleHeader) {
1320
+ assert ((!isModuleHeader || !isTextualModuleHeader) &&
1321
+ " A header can't build with a module and be textual at the same time" );
1322
+ HFI.isModuleHeader |= isModuleHeader;
1323
+ if (HFI.isModuleHeader )
1324
+ HFI.isTextualModuleHeader = false ;
1325
+ else
1326
+ HFI.isTextualModuleHeader |= isTextualModuleHeader;
1327
+ }
1328
+
1329
+ void HeaderFileInfo::mergeModuleMembership (ModuleMap::ModuleHeaderRole Role) {
1330
+ mergeHeaderFileInfoModuleBits (*this , ModuleMap::isModular (Role),
1331
+ (Role & ModuleMap::TextualHeader));
1332
+ }
1333
+
1317
1334
// / Merge the header file info provided by \p OtherHFI into the current
1318
1335
// / header file info (\p HFI)
1319
1336
static void mergeHeaderFileInfo (HeaderFileInfo &HFI,
@@ -1322,7 +1339,8 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
1322
1339
1323
1340
HFI.isImport |= OtherHFI.isImport ;
1324
1341
HFI.isPragmaOnce |= OtherHFI.isPragmaOnce ;
1325
- HFI.isModuleHeader |= OtherHFI.isModuleHeader ;
1342
+ mergeHeaderFileInfoModuleBits (HFI, OtherHFI.isModuleHeader ,
1343
+ OtherHFI.isTextualModuleHeader );
1326
1344
1327
1345
if (!HFI.ControllingMacro && !HFI.ControllingMacroID ) {
1328
1346
HFI.ControllingMacro = OtherHFI.ControllingMacro ;
@@ -1411,94 +1429,146 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) const {
1411
1429
void HeaderSearch::MarkFileModuleHeader (const FileEntry *FE,
1412
1430
ModuleMap::ModuleHeaderRole Role,
1413
1431
bool isCompilingModuleHeader) {
1414
- bool isModularHeader = ModuleMap::isModular (Role);
1415
-
1416
1432
// Don't mark the file info as non-external if there's nothing to change.
1417
1433
if (!isCompilingModuleHeader) {
1418
- if (!isModularHeader )
1434
+ if ((Role & ModuleMap::ExcludedHeader) )
1419
1435
return ;
1420
1436
auto *HFI = getExistingFileInfo (FE);
1421
1437
if (HFI && HFI->isModuleHeader )
1422
1438
return ;
1423
1439
}
1424
1440
1425
1441
auto &HFI = getFileInfo (FE);
1426
- HFI.isModuleHeader |= isModularHeader ;
1442
+ HFI.mergeModuleMembership (Role) ;
1427
1443
HFI.isCompilingModuleHeader |= isCompilingModuleHeader;
1428
1444
}
1429
1445
1430
1446
bool HeaderSearch::ShouldEnterIncludeFile (Preprocessor &PP,
1431
1447
const FileEntry *File, bool isImport,
1432
1448
bool ModulesEnabled, Module *M,
1433
1449
bool &IsFirstIncludeOfFile) {
1434
- ++NumIncluded; // Count # of attempted #includes.
1435
-
1450
+ // An include file should be entered if either:
1451
+ // 1. This is the first include of the file.
1452
+ // 2. This file can be included multiple times, that is it's not an
1453
+ // "include-once" file.
1454
+ //
1455
+ // Include-once is controlled by these preprocessor directives.
1456
+ //
1457
+ // #pragma once
1458
+ // This directive is in the include file, and marks it as an include-once
1459
+ // file.
1460
+ //
1461
+ // #import <file>
1462
+ // This directive is in the includer, and indicates that the include file
1463
+ // should only be entered if this is the first include.
1464
+ ++NumIncluded;
1436
1465
IsFirstIncludeOfFile = false ;
1437
-
1438
- // Get information about this file.
1439
1466
HeaderFileInfo &FileInfo = getFileInfo (File);
1440
1467
1441
- // FIXME: this is a workaround for the lack of proper modules-aware support
1442
- // for #import / #pragma once
1443
- auto TryEnterImported = [&]() -> bool {
1444
- if (!ModulesEnabled)
1468
+ auto MaybeReenterImportedFile = [&]() -> bool {
1469
+ // Modules add a wrinkle though: what's included isn't necessarily visible.
1470
+ // Consider this module.
1471
+ // module Example {
1472
+ // module A { header "a.h" export * }
1473
+ // module B { header "b.h" export * }
1474
+ // }
1475
+ // b.h includes c.h. The main file includes a.h, which will trigger a module
1476
+ // build of Example, and c.h will be included. However, c.h isn't visible to
1477
+ // the main file. Normally this is fine, the main file can just include c.h
1478
+ // if it needs it. If c.h is in a module, the include will translate into a
1479
+ // module import, this function will be skipped, and everything will work as
1480
+ // expected. However, if c.h is not in a module (or is `textual`), then this
1481
+ // function will run. If c.h is include-once, it will not be entered from
1482
+ // the main file and it will still not be visible.
1483
+
1484
+ // If modules aren't enabled then there's no visibility issue. Always
1485
+ // respect `#pragma once`.
1486
+ if (!ModulesEnabled || FileInfo.isPragmaOnce )
1445
1487
return false ;
1488
+
1446
1489
// Ensure FileInfo bits are up to date.
1447
1490
ModMap.resolveHeaderDirectives (File);
1448
- // Modules with builtins are special; multiple modules use builtins as
1449
- // modular headers, example:
1450
- //
1451
- // module stddef { header "stddef.h" export * }
1452
- //
1453
- // After module map parsing, this expands to:
1454
- //
1455
- // module stddef {
1456
- // header "/path_to_builtin_dirs/stddef.h"
1457
- // textual "stddef.h"
1458
- // }
1491
+
1492
+ // This brings up a subtlety of #import - it's not a very good indicator of
1493
+ // include-once. Developers are often unaware of the difference between
1494
+ // #include and #import, and tend to use one or the other indiscrimiately.
1495
+ // In order to support #include on include-once headers that lack macro
1496
+ // guards and `#pragma once` (which is the vast majority of Objective-C
1497
+ // headers), if a file is ever included with #import, it's marked as
1498
+ // isImport in the HeaderFileInfo and treated as include-once. This allows
1499
+ // #include to work in Objective-C.
1500
+ // #include <Foundation/Foundation.h>
1501
+ // #include <Foundation/NSString.h>
1502
+ // Foundation.h has an #import of NSString.h, and so the second #include is
1503
+ // skipped even though NSString.h has no `#pragma once` and no macro guard.
1459
1504
//
1460
- // It's common that libc++ and system modules will both define such
1461
- // submodules. Make sure cached results for a builtin header won't
1462
- // prevent other builtin modules from potentially entering the builtin
1463
- // header. Note that builtins are header guarded and the decision to
1464
- // actually enter them is postponed to the controlling macros logic below.
1465
- bool TryEnterHdr = false ;
1466
- if (FileInfo.isCompilingModuleHeader && FileInfo.isModuleHeader )
1467
- TryEnterHdr = ModMap.isBuiltinHeader (File);
1468
-
1469
- // Textual headers can be #imported from different modules. Since ObjC
1470
- // headers find in the wild might rely only on #import and do not contain
1471
- // controlling macros, be conservative and only try to enter textual headers
1472
- // if such macro is present.
1473
- if (FileInfo.isCompilingModuleHeader && !FileInfo.isModuleHeader &&
1474
- FileInfo.getControllingMacro (ExternalLookup))
1475
- TryEnterHdr = true ;
1476
- return TryEnterHdr;
1505
+ // However, this helpfulness causes problems with modules. If c.h is not an
1506
+ // include-once file, but something included it with #import anyway (as is
1507
+ // typical in Objective-C code), this include will be skipped and c.h will
1508
+ // not be visible. Consider it not include-once if it is a `textual` header
1509
+ // in a module.
1510
+ if (FileInfo.isTextualModuleHeader )
1511
+ return true ;
1512
+
1513
+ if (FileInfo.isCompilingModuleHeader ) {
1514
+ // It's safer to re-enter a file whose module is being built because its
1515
+ // declarations will still be scoped to a single module.
1516
+ if (FileInfo.isModuleHeader ) {
1517
+ // Headers marked as "builtin" are covered by the system module maps
1518
+ // rather than the builtin ones. Some versions of the Darwin module fail
1519
+ // to mark stdarg.h and stddef.h as textual. Attempt to re-enter these
1520
+ // files while building their module to allow them to function properly.
1521
+ if (ModMap.isBuiltinHeader (File))
1522
+ return true ;
1523
+ } else {
1524
+ // Files that are excluded from their module can potentially be
1525
+ // re-entered from their own module. This might cause redeclaration
1526
+ // errors if another module saw this file first, but there's a
1527
+ // reasonable chance that its module will build first. However if
1528
+ // there's no controlling macro, then trust the #import and assume this
1529
+ // really is an include-once file.
1530
+ if (FileInfo.getControllingMacro (ExternalLookup))
1531
+ return true ;
1532
+ }
1533
+ }
1534
+ // If the include file has a macro guard, then it might still not be
1535
+ // re-entered if the controlling macro is visibly defined. e.g. another
1536
+ // header in the module being built included this file and local submodule
1537
+ // visibility is not enabled.
1538
+
1539
+ // It might be tempting to re-enter the include-once file if it's not
1540
+ // visible in an attempt to make it visible. However this will still cause
1541
+ // redeclaration errors against the known-but-not-visible declarations. The
1542
+ // include file not being visible will most likely cause "undefined x"
1543
+ // errors, but at least there's a slim chance of compilation succeeding.
1544
+ return false ;
1477
1545
};
1478
1546
1479
- // If this is a #import directive, check that we have not already imported
1480
- // this header.
1481
1547
if (isImport) {
1482
- // If this has already been imported, don't import it again.
1548
+ // As discussed above, record that this file was ever `#import`ed, and treat
1549
+ // it as an include-once file from here out.
1483
1550
FileInfo.isImport = true ;
1484
-
1485
- // Has this already been #import'ed or #include'd?
1486
- if (PP.alreadyIncluded (File) && !TryEnterImported ())
1551
+ if (PP.alreadyIncluded (File) && !MaybeReenterImportedFile ())
1487
1552
return false ;
1488
1553
} else {
1489
- // Otherwise, if this is a #include of a file that was previously #import'd
1490
- // or if this is the second #include of a #pragma once file, ignore it.
1491
- if ((FileInfo.isPragmaOnce || FileInfo.isImport ) && !TryEnterImported ())
1554
+ // isPragmaOnce and isImport are only set after the file has been included
1555
+ // at least once. If either are set then this is a repeat #include of an
1556
+ // include-once file.
1557
+ if (FileInfo.isPragmaOnce ||
1558
+ (FileInfo.isImport && !MaybeReenterImportedFile ()))
1492
1559
return false ;
1493
1560
}
1494
1561
1495
- // Next, check to see if the file is wrapped with #ifndef guards. If so, and
1496
- // if the macro that guards it is defined, we know the #include has no effect.
1497
- if (const IdentifierInfo *ControllingMacro
1498
- = FileInfo.getControllingMacro (ExternalLookup)) {
1562
+ // As a final optimization, check for a macro guard and skip entering the file
1563
+ // if the controlling macro is defined. The macro guard will effectively erase
1564
+ // the file's contents, and the include would have no effect other than to
1565
+ // waste time opening and reading a file.
1566
+ if (const IdentifierInfo *ControllingMacro =
1567
+ FileInfo.getControllingMacro (ExternalLookup)) {
1499
1568
// If the header corresponds to a module, check whether the macro is already
1500
- // defined in that module rather than checking in the current set of visible
1501
- // modules.
1569
+ // defined in that module rather than checking all visible modules. This is
1570
+ // mainly to cover corner cases where the same controlling macro is used in
1571
+ // different files in multiple modules.
1502
1572
if (M ? PP.isMacroDefinedInLocalModule (ControllingMacro, M)
1503
1573
: PP.isMacroDefined (ControllingMacro)) {
1504
1574
++NumMultiIncludeFileOptzn;
@@ -1507,7 +1577,6 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
1507
1577
}
1508
1578
1509
1579
IsFirstIncludeOfFile = PP.markIncluded (File);
1510
-
1511
1580
return true ;
1512
1581
}
1513
1582
0 commit comments