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