Skip to content

Commit acc560d

Browse files
committed
[clang] Diagnose config_macros before building modules
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 llvm#83641 (cherry picked from commit ee044d5)
1 parent fa4fca2 commit acc560d

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
@@ -1686,6 +1686,14 @@ static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
16861686
}
16871687
}
16881688

1689+
static void checkConfigMacros(Preprocessor &PP, Module *M,
1690+
SourceLocation ImportLoc) {
1691+
clang::Module *TopModule = M->getTopLevelModule();
1692+
for (const StringRef ConMacro : TopModule->ConfigMacros) {
1693+
checkConfigMacro(PP, ConMacro, M, ImportLoc);
1694+
}
1695+
}
1696+
16891697
/// Write a new timestamp file with the given path.
16901698
static void writeTimestampFile(StringRef TimestampFile) {
16911699
std::error_code EC;
@@ -1926,6 +1934,13 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST(
19261934
Module *M =
19271935
HS.lookupModule(ModuleName, ImportLoc, true, !IsInclusionDirective);
19281936

1937+
// Check for any configuration macros that have changed. This is done
1938+
// immediately before potentially building a module in case this module
1939+
// depends on having one of its configuration macros defined to successfully
1940+
// build. If this is not done the user will never see the warning.
1941+
if (M)
1942+
checkConfigMacros(getPreprocessor(), M, ImportLoc);
1943+
19291944
// Select the source and filename for loading the named module.
19301945
std::string ModuleFilename;
19311946
ModuleSource Source =
@@ -2110,12 +2125,23 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
21102125
if (auto MaybeModule = MM.getCachedModuleLoad(*Path[0].first)) {
21112126
// Use the cached result, which may be nullptr.
21122127
Module = *MaybeModule;
2128+
// Config macros are already checked before building a module, but they need
2129+
// to be checked at each import location in case any of the config macros
2130+
// have a new value at the current `ImportLoc`.
2131+
if (Module)
2132+
checkConfigMacros(getPreprocessor(), Module, ImportLoc);
21132133
} else if (ModuleName == getLangOpts().CurrentModule) {
21142134
// This is the module we're building.
21152135
Module = PP->getHeaderSearchInfo().lookupModule(
21162136
ModuleName, ImportLoc, /*AllowSearch*/ true,
21172137
/*AllowExtraModuleMapSearch*/ !IsInclusionDirective);
21182138

2139+
// Config macros do not need to be checked here for two reasons.
2140+
// * This will always be textual inclusion, and thus the config macros
2141+
// actually do impact the content of the header.
2142+
// * `Preprocessor::HandleHeaderIncludeOrImport` will never call this
2143+
// function as the `#include` or `#import` is textual.
2144+
21192145
MM.cacheModuleLoad(*Path[0].first, Module);
21202146
} else {
21212147
ModuleLoadResult Result = findOrCompileModuleAndReadAST(
@@ -2252,18 +2278,11 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
22522278
TheASTReader->makeModuleVisible(Module, Visibility, ImportLoc);
22532279
}
22542280

2255-
// Check for any configuration macros that have changed.
2256-
clang::Module *TopModule = Module->getTopLevelModule();
2257-
for (unsigned I = 0, N = TopModule->ConfigMacros.size(); I != N; ++I) {
2258-
checkConfigMacro(getPreprocessor(), TopModule->ConfigMacros[I],
2259-
Module, ImportLoc);
2260-
}
2261-
22622281
// Resolve any remaining module using export_as for this one.
22632282
getPreprocessor()
22642283
.getHeaderSearchInfo()
22652284
.getModuleMap()
2266-
.resolveLinkAsDependencies(TopModule);
2285+
.resolveLinkAsDependencies(Module->getTopLevelModule());
22672286

22682287
LastModuleImportLoc = ImportLoc;
22692288
LastModuleImportResult = ModuleLoadResult(Module);

clang/test/Modules/Inputs/config.h

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

clang/test/Modules/Inputs/module.map

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.map
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)