Skip to content

Commit 5997c15

Browse files
author
git apple-llvm automerger
committed
Merge commit '20efc70c8212' from swift/release/6.0 into stable/20230725
2 parents 18f4f9b + 20efc70 commit 5997c15

File tree

7 files changed

+200
-63
lines changed

7 files changed

+200
-63
lines changed

clang/include/clang/Lex/HeaderSearch.h

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,17 @@ struct HeaderFileInfo {
7474
/// and has not changed since.
7575
unsigned External : 1;
7676

77-
/// Whether this header is part of a module.
77+
/// Whether this header is part of and built with a module. i.e. it is listed
78+
/// in a module map, and is not `excluded` or `textual`. (same meaning as
79+
/// `ModuleMap::isModular()`).
7880
unsigned isModuleHeader : 1;
7981

80-
/// Whether this header is part of the module that we are building.
82+
/// Whether this header is a `textual header` in a module.
83+
unsigned isTextualModuleHeader : 1;
84+
85+
/// Whether this header is part of the module that we are building, even if it
86+
/// doesn't build with the module. i.e. this will include `excluded` and
87+
/// `textual` headers as well as normal headers.
8188
unsigned isCompilingModuleHeader : 1;
8289

8390
/// Whether this structure is considered to already have been
@@ -119,13 +126,20 @@ struct HeaderFileInfo {
119126

120127
HeaderFileInfo()
121128
: isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User),
122-
External(false), isModuleHeader(false), isCompilingModuleHeader(false),
123-
Resolved(false), IndexHeaderMapHeader(false), IsValid(false) {}
129+
External(false), isModuleHeader(false), isTextualModuleHeader(false),
130+
isCompilingModuleHeader(false), Resolved(false),
131+
IndexHeaderMapHeader(false), IsValid(false) {}
124132

125133
/// Retrieve the controlling macro for this header file, if
126134
/// any.
127135
const IdentifierInfo *
128136
getControllingMacro(ExternalPreprocessorSource *External);
137+
138+
/// Update the module membership bits based on the header role.
139+
///
140+
/// isModuleHeader will potentially be set, but not cleared.
141+
/// isTextualModuleHeader will be set or cleared based on the role update.
142+
void mergeModuleMembership(ModuleMap::ModuleHeaderRole Role);
129143
};
130144

131145
/// An external source of header file information, which may supply
@@ -516,6 +530,9 @@ class HeaderSearch {
516530
///
517531
/// \return false if \#including the file will have no effect or true
518532
/// if we should include it.
533+
///
534+
/// \param M The module to which `File` belongs (this should usually be the
535+
/// SuggestedModule returned by LookupFile/LookupSubframeworkHeader)
519536
bool ShouldEnterIncludeFile(Preprocessor &PP, const FileEntry *File,
520537
bool isImport, bool ModulesEnabled, Module *M,
521538
bool &IsFirstIncludeOfFile);

clang/lib/Lex/HeaderSearch.cpp

Lines changed: 126 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,23 @@ OptionalFileEntryRef HeaderSearch::LookupSubframeworkHeader(
13141314
// File Info Management.
13151315
//===----------------------------------------------------------------------===//
13161316

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+
13171334
/// Merge the header file info provided by \p OtherHFI into the current
13181335
/// header file info (\p HFI)
13191336
static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
@@ -1322,7 +1339,8 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
13221339

13231340
HFI.isImport |= OtherHFI.isImport;
13241341
HFI.isPragmaOnce |= OtherHFI.isPragmaOnce;
1325-
HFI.isModuleHeader |= OtherHFI.isModuleHeader;
1342+
mergeHeaderFileInfoModuleBits(HFI, OtherHFI.isModuleHeader,
1343+
OtherHFI.isTextualModuleHeader);
13261344

13271345
if (!HFI.ControllingMacro && !HFI.ControllingMacroID) {
13281346
HFI.ControllingMacro = OtherHFI.ControllingMacro;
@@ -1411,94 +1429,146 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) const {
14111429
void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE,
14121430
ModuleMap::ModuleHeaderRole Role,
14131431
bool isCompilingModuleHeader) {
1414-
bool isModularHeader = ModuleMap::isModular(Role);
1415-
14161432
// Don't mark the file info as non-external if there's nothing to change.
14171433
if (!isCompilingModuleHeader) {
1418-
if (!isModularHeader)
1434+
if ((Role & ModuleMap::ExcludedHeader))
14191435
return;
14201436
auto *HFI = getExistingFileInfo(FE);
14211437
if (HFI && HFI->isModuleHeader)
14221438
return;
14231439
}
14241440

14251441
auto &HFI = getFileInfo(FE);
1426-
HFI.isModuleHeader |= isModularHeader;
1442+
HFI.mergeModuleMembership(Role);
14271443
HFI.isCompilingModuleHeader |= isCompilingModuleHeader;
14281444
}
14291445

14301446
bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
14311447
const FileEntry *File, bool isImport,
14321448
bool ModulesEnabled, Module *M,
14331449
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;
14361465
IsFirstIncludeOfFile = false;
1437-
1438-
// Get information about this file.
14391466
HeaderFileInfo &FileInfo = getFileInfo(File);
14401467

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)
14451487
return false;
1488+
14461489
// Ensure FileInfo bits are up to date.
14471490
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.
14591504
//
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;
14771545
};
14781546

1479-
// If this is a #import directive, check that we have not already imported
1480-
// this header.
14811547
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.
14831550
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())
14871552
return false;
14881553
} 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()))
14921559
return false;
14931560
}
14941561

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)) {
14991568
// 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.
15021572
if (M ? PP.isMacroDefinedInLocalModule(ControllingMacro, M)
15031573
: PP.isMacroDefined(ControllingMacro)) {
15041574
++NumMultiIncludeFileOptzn;
@@ -1507,7 +1577,6 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
15071577
}
15081578

15091579
IsFirstIncludeOfFile = PP.markIncluded(File);
1510-
15111580
return true;
15121581
}
15131582

clang/lib/Serialization/ASTReader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2086,7 +2086,7 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
20862086
Module::Header H = {std::string(key.Filename), "", *FE};
20872087
ModMap.addHeader(Mod, H, HeaderRole, /*Imported=*/true);
20882088
}
2089-
HFI.isModuleHeader |= ModuleMap::isModular(HeaderRole);
2089+
HFI.mergeModuleMembership(HeaderRole);
20902090
}
20912091

20922092
// This HeaderFileInfo was externally loaded.

clang/test/Modules/builtin-import.mm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
// RUN: rm -rf %t
2+
// RUN: %clang_cc1 -fsyntax-only -nobuiltininc -nostdinc++ -isysroot %S/Inputs/libc-libcxx/sysroot -isystem %S/Inputs/libc-libcxx/sysroot/usr/include/c++/v1 -isystem %S/Inputs/libc-libcxx/sysroot/usr/include -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c++ %s
3+
// RUN: rm -rf %t
24
// RUN: %clang_cc1 -fsyntax-only -nobuiltininc -nostdinc++ -isysroot %S/Inputs/libc-libcxx/sysroot -isystem %S/Inputs/libc-libcxx/sysroot/usr/include/c++/v1 -isystem %S/Inputs/libc-libcxx/sysroot/usr/include -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c++ -fmodules-local-submodule-visibility %s
35

46
#include <stdio.h>

clang/test/Modules/import-textual-noguard.mm

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
// RUN: rm -rf %t
2+
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fmodules -fimplicit-module-maps -I%S/Inputs/import-textual/M2 -fmodules-cache-path=%t -x objective-c++ %s -verify
3+
// RUN: rm -rf %t
24
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fmodules -fimplicit-module-maps -I%S/Inputs/import-textual/M2 -fmodules-cache-path=%t -x objective-c++ -fmodules-local-submodule-visibility %s -verify
35

4-
#include "A/A.h" // expected-error {{could not build module 'M'}}
6+
// expected-no-diagnostics
7+
8+
#include "A/A.h"
59
#include "B/B.h"
610

711
typedef aint xxx;

clang/test/Modules/import-textual.mm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
// RUN: rm -rf %t
2+
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fmodules -fimplicit-module-maps -I%S/Inputs/import-textual/M -fmodules-cache-path=%t -x objective-c++ %s -verify
3+
// RUN: rm -rf %t
24
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fmodules -fimplicit-module-maps -I%S/Inputs/import-textual/M -fmodules-cache-path=%t -x objective-c++ -fmodules-local-submodule-visibility %s -verify
35

46
// expected-no-diagnostics

clang/test/Modules/multiple-import.m

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: %clang_cc1 -std=c17 -fmodules-cache-path=%t/no-lsv -fmodules -fimplicit-module-maps -I%t %t/multiple-imports.m -verify
4+
// RUN: %clang_cc1 -std=c17 -fmodules-cache-path=%t/lsv -fmodules -fimplicit-module-maps -fmodules-local-submodule-visibility -I%t %t/multiple-imports.m -verify
5+
6+
//--- multiple-imports.m
7+
// expected-no-diagnostics
8+
#import <one.h>
9+
#import <assert.h>
10+
void test(void) {
11+
assert(0);
12+
}
13+
14+
//--- module.modulemap
15+
module Submodules [system] {
16+
module one {
17+
header "one.h"
18+
export *
19+
}
20+
module two {
21+
header "two.h"
22+
export *
23+
}
24+
}
25+
26+
module libc [system] {
27+
textual header "assert.h"
28+
}
29+
30+
//--- one.h
31+
#ifndef one_h
32+
#define one_h
33+
#endif
34+
35+
//--- two.h
36+
#ifndef two_h
37+
#define two_h
38+
#include <assert.h>
39+
#endif
40+
41+
//--- assert.h
42+
#undef assert
43+
#define assert(expression) ((void)0)

0 commit comments

Comments
 (0)