Skip to content

Commit ee044d5

Browse files
authored
[clang] Diagnose config_macros before building modules (#83641)
Before this patch, if a module fails to build because of a missing config_macro, the user will never see the config macro warning. This patch diagnoses this before building, and each subsequent time a module is imported. rdar://123921931
1 parent caad379 commit ee044d5

File tree

4 files changed

+78
-23
lines changed

4 files changed

+78
-23
lines changed

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,6 +1591,14 @@ static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
15911591
}
15921592
}
15931593

1594+
static void checkConfigMacros(Preprocessor &PP, Module *M,
1595+
SourceLocation ImportLoc) {
1596+
clang::Module *TopModule = M->getTopLevelModule();
1597+
for (const StringRef ConMacro : TopModule->ConfigMacros) {
1598+
checkConfigMacro(PP, ConMacro, M, ImportLoc);
1599+
}
1600+
}
1601+
15941602
/// Write a new timestamp file with the given path.
15951603
static void writeTimestampFile(StringRef TimestampFile) {
15961604
std::error_code EC;
@@ -1829,6 +1837,13 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST(
18291837
Module *M =
18301838
HS.lookupModule(ModuleName, ImportLoc, true, !IsInclusionDirective);
18311839

1840+
// Check for any configuration macros that have changed. This is done
1841+
// immediately before potentially building a module in case this module
1842+
// depends on having one of its configuration macros defined to successfully
1843+
// build. If this is not done the user will never see the warning.
1844+
if (M)
1845+
checkConfigMacros(getPreprocessor(), M, ImportLoc);
1846+
18321847
// Select the source and filename for loading the named module.
18331848
std::string ModuleFilename;
18341849
ModuleSource Source =
@@ -2006,12 +2021,23 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
20062021
if (auto MaybeModule = MM.getCachedModuleLoad(*Path[0].first)) {
20072022
// Use the cached result, which may be nullptr.
20082023
Module = *MaybeModule;
2024+
// Config macros are already checked before building a module, but they need
2025+
// to be checked at each import location in case any of the config macros
2026+
// have a new value at the current `ImportLoc`.
2027+
if (Module)
2028+
checkConfigMacros(getPreprocessor(), Module, ImportLoc);
20092029
} else if (ModuleName == getLangOpts().CurrentModule) {
20102030
// This is the module we're building.
20112031
Module = PP->getHeaderSearchInfo().lookupModule(
20122032
ModuleName, ImportLoc, /*AllowSearch*/ true,
20132033
/*AllowExtraModuleMapSearch*/ !IsInclusionDirective);
20142034

2035+
// Config macros do not need to be checked here for two reasons.
2036+
// * This will always be textual inclusion, and thus the config macros
2037+
// actually do impact the content of the header.
2038+
// * `Preprocessor::HandleHeaderIncludeOrImport` will never call this
2039+
// function as the `#include` or `#import` is textual.
2040+
20152041
MM.cacheModuleLoad(*Path[0].first, Module);
20162042
} else {
20172043
ModuleLoadResult Result = findOrCompileModuleAndReadAST(
@@ -2146,18 +2172,11 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
21462172
TheASTReader->makeModuleVisible(Module, Visibility, ImportLoc);
21472173
}
21482174

2149-
// Check for any configuration macros that have changed.
2150-
clang::Module *TopModule = Module->getTopLevelModule();
2151-
for (unsigned I = 0, N = TopModule->ConfigMacros.size(); I != N; ++I) {
2152-
checkConfigMacro(getPreprocessor(), TopModule->ConfigMacros[I],
2153-
Module, ImportLoc);
2154-
}
2155-
21562175
// Resolve any remaining module using export_as for this one.
21572176
getPreprocessor()
21582177
.getHeaderSearchInfo()
21592178
.getModuleMap()
2160-
.resolveLinkAsDependencies(TopModule);
2179+
.resolveLinkAsDependencies(Module->getTopLevelModule());
21612180

21622181
LastModuleImportLoc = ImportLoc;
21632182
LastModuleImportResult = ModuleLoadResult(Module);

clang/test/Modules/Inputs/config.h

Lines changed: 0 additions & 7 deletions
This file was deleted.

clang/test/Modules/Inputs/module.modulemap

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,11 +260,6 @@ module cxx_decls_merged {
260260
header "cxx-decls-merged.h"
261261
}
262262

263-
module config {
264-
header "config.h"
265-
config_macros [exhaustive] WANT_FOO, WANT_BAR
266-
}
267-
268263
module diag_flags {
269264
header "diag_flags.h"
270265
}

clang/test/Modules/config_macros.m

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,50 @@
1+
// This test verifies that config macro warnings are emitted when it looks like
2+
// the user expected a `#define` to impact the import of a module.
3+
4+
// RUN: rm -rf %t
5+
// RUN: split-file %s %t
6+
7+
// Prebuild the `config` module so it's in the module cache.
8+
// RUN: %clang_cc1 -std=c99 -fmodules -fimplicit-module-maps -x objective-c -fmodules-cache-path=%t -DWANT_FOO=1 -emit-module -fmodule-name=config %t/module.modulemap
9+
10+
// Verify that each time the `config` module is imported the current macro state
11+
// is checked.
12+
// RUN: %clang_cc1 -std=c99 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %t -DWANT_FOO=1 %t/config.m -verify
13+
14+
// Verify that warnings are emitted before building a module in case the command
15+
// line macro state causes the module to fail to build.
16+
// RUN: %clang_cc1 -std=c99 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %t %t/config_error.m -verify
17+
18+
//--- module.modulemap
19+
20+
module config {
21+
header "config.h"
22+
config_macros [exhaustive] WANT_FOO, WANT_BAR
23+
}
24+
25+
module config_error {
26+
header "config_error.h"
27+
config_macros SOME_VALUE
28+
}
29+
30+
//--- config.h
31+
32+
#ifdef WANT_FOO
33+
int* foo(void);
34+
#endif
35+
36+
#ifdef WANT_BAR
37+
char *bar(void);
38+
#endif
39+
40+
//--- config_error.h
41+
42+
struct my_thing {
43+
char buf[SOME_VALUE];
44+
};
45+
46+
//--- config.m
47+
148
@import config;
249

350
int *test_foo(void) {
@@ -22,7 +69,8 @@
2269
#define WANT_BAR 1 // expected-note{{macro was defined here}}
2370
@import config; // expected-warning{{definition of configuration macro 'WANT_BAR' has no effect on the import of 'config'; pass '-DWANT_BAR=...' on the command line to configure the module}}
2471

25-
// RUN: rm -rf %t
26-
// RUN: %clang_cc1 -std=c99 -fmodules -fimplicit-module-maps -x objective-c -fmodules-cache-path=%t -DWANT_FOO=1 -emit-module -fmodule-name=config %S/Inputs/module.modulemap
27-
// RUN: %clang_cc1 -std=c99 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs -DWANT_FOO=1 %s -verify
72+
//--- config_error.m
2873

74+
#define SOME_VALUE 5 // expected-note{{macro was defined here}}
75+
@import config_error; // expected-error{{could not build module}} \
76+
// expected-warning{{definition of configuration macro 'SOME_VALUE' has no effect on the import of 'config_error';}}

0 commit comments

Comments
 (0)