Skip to content

Commit fd02ed8

Browse files
Merge commit '0cd0aa029647' from llvm.org/main into next
# Conflicts: # clang/lib/Lex/HeaderSearch.cpp
2 parents 13926d1 + 0cd0aa0 commit fd02ed8

File tree

7 files changed

+201
-63
lines changed

7 files changed

+201
-63
lines changed

clang/include/clang/Lex/HeaderSearch.h

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,19 @@ struct HeaderFileInfo {
7878
LLVM_PREFERRED_TYPE(bool)
7979
unsigned External : 1;
8080

81-
/// Whether this header is part of a module.
81+
/// Whether this header is part of and built with a module. i.e. it is listed
82+
/// in a module map, and is not `excluded` or `textual`. (same meaning as
83+
/// `ModuleMap::isModular()`).
8284
LLVM_PREFERRED_TYPE(bool)
8385
unsigned isModuleHeader : 1;
8486

85-
/// Whether this header is part of the module that we are building.
87+
/// Whether this header is a `textual header` in a module.
88+
LLVM_PREFERRED_TYPE(bool)
89+
unsigned isTextualModuleHeader : 1;
90+
91+
/// Whether this header is part of the module that we are building, even if it
92+
/// doesn't build with the module. i.e. this will include `excluded` and
93+
/// `textual` headers as well as normal headers.
8694
LLVM_PREFERRED_TYPE(bool)
8795
unsigned isCompilingModuleHeader : 1;
8896

@@ -128,13 +136,20 @@ struct HeaderFileInfo {
128136

129137
HeaderFileInfo()
130138
: isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User),
131-
External(false), isModuleHeader(false), isCompilingModuleHeader(false),
132-
Resolved(false), IndexHeaderMapHeader(false), IsValid(false) {}
139+
External(false), isModuleHeader(false), isTextualModuleHeader(false),
140+
isCompilingModuleHeader(false), Resolved(false),
141+
IndexHeaderMapHeader(false), IsValid(false) {}
133142

134143
/// Retrieve the controlling macro for this header file, if
135144
/// any.
136145
const IdentifierInfo *
137146
getControllingMacro(ExternalPreprocessorSource *External);
147+
148+
/// Update the module membership bits based on the header role.
149+
///
150+
/// isModuleHeader will potentially be set, but not cleared.
151+
/// isTextualModuleHeader will be set or cleared based on the role update.
152+
void mergeModuleMembership(ModuleMap::ModuleHeaderRole Role);
138153
};
139154

140155
/// An external source of header file information, which may supply
@@ -522,6 +537,9 @@ class HeaderSearch {
522537
///
523538
/// \return false if \#including the file will have no effect or true
524539
/// if we should include it.
540+
///
541+
/// \param M The module to which `File` belongs (this should usually be the
542+
/// SuggestedModule returned by LookupFile/LookupSubframeworkHeader)
525543
bool ShouldEnterIncludeFile(Preprocessor &PP, FileEntryRef File,
526544
bool isImport, bool ModulesEnabled, Module *M,
527545
bool &IsFirstIncludeOfFile);

clang/lib/Lex/HeaderSearch.cpp

Lines changed: 126 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,23 @@ OptionalFileEntryRef HeaderSearch::LookupSubframeworkHeader(
13071307
// File Info Management.
13081308
//===----------------------------------------------------------------------===//
13091309

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+
13101327
/// Merge the header file info provided by \p OtherHFI into the current
13111328
/// header file info (\p HFI)
13121329
static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
@@ -1315,7 +1332,8 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
13151332

13161333
HFI.isImport |= OtherHFI.isImport;
13171334
HFI.isPragmaOnce |= OtherHFI.isPragmaOnce;
1318-
HFI.isModuleHeader |= OtherHFI.isModuleHeader;
1335+
mergeHeaderFileInfoModuleBits(HFI, OtherHFI.isModuleHeader,
1336+
OtherHFI.isTextualModuleHeader);
13191337

13201338
if (!HFI.ControllingMacro && !HFI.ControllingMacroID) {
13211339
HFI.ControllingMacro = OtherHFI.ControllingMacro;
@@ -1403,94 +1421,146 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(FileEntryRef File) const {
14031421
void HeaderSearch::MarkFileModuleHeader(FileEntryRef FE,
14041422
ModuleMap::ModuleHeaderRole Role,
14051423
bool isCompilingModuleHeader) {
1406-
bool isModularHeader = ModuleMap::isModular(Role);
1407-
14081424
// Don't mark the file info as non-external if there's nothing to change.
14091425
if (!isCompilingModuleHeader) {
1410-
if (!isModularHeader)
1426+
if ((Role & ModuleMap::ExcludedHeader))
14111427
return;
14121428
auto *HFI = getExistingFileInfo(FE);
14131429
if (HFI && HFI->isModuleHeader)
14141430
return;
14151431
}
14161432

14171433
auto &HFI = getFileInfo(FE);
1418-
HFI.isModuleHeader |= isModularHeader;
1434+
HFI.mergeModuleMembership(Role);
14191435
HFI.isCompilingModuleHeader |= isCompilingModuleHeader;
14201436
}
14211437

14221438
bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
14231439
FileEntryRef File, bool isImport,
14241440
bool ModulesEnabled, Module *M,
14251441
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;
14281457
IsFirstIncludeOfFile = false;
1429-
1430-
// Get information about this file.
14311458
HeaderFileInfo &FileInfo = getFileInfo(File);
14321459

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)
14371479
return false;
1480+
14381481
// Ensure FileInfo bits are up to date.
14391482
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.
14511496
//
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.isCompilingModuleHeader && !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;
14691537
};
14701538

1471-
// If this is a #import directive, check that we have not already imported
1472-
// this header.
14731539
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.
14751542
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())
14791544
return false;
14801545
} 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()))
14841551
return false;
14851552
}
14861553

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)) {
14911560
// 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.
14941564
if (M ? PP.isMacroDefinedInLocalModule(ControllingMacro, M)
14951565
: PP.isMacroDefined(ControllingMacro)) {
14961566
++NumMultiIncludeFileOptzn;
@@ -1499,7 +1569,6 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
14991569
}
15001570

15011571
IsFirstIncludeOfFile = PP.markIncluded(File);
1502-
15031572
return true;
15041573
}
15051574

clang/lib/Serialization/ASTReader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2111,7 +2111,7 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
21112111
Module::Header H = {std::string(key.Filename), "", *FE};
21122112
ModMap.addHeader(Mod, H, HeaderRole, /*Imported=*/true);
21132113
}
2114-
HFI.isModuleHeader |= ModuleMap::isModular(HeaderRole);
2114+
HFI.mergeModuleMembership(HeaderRole);
21152115
}
21162116

21172117
// 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)