other than the top level, we issue an error. This breaks a fair amount of C++
code wrapping C libraries, where the C library is #included within a namespace
/ extern "C" combination, because the C library (probably) includes C++
standard library headers which may be within modules.
Without modules, this setup is harmless if (and *only* if) the corresponding
standard library module was already included outside the namespace, so
downgrade the error to a default-error extension in that case, so that it can
be selectively disabled for such misbehaving libraries.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@253398
91177308-0d34-0410-b5e6-
96231b3b80d8
"extern \"C\" language linkage specification begins here">;
def err_module_import_not_at_top_level_fatal : Error<
"import of module '%0' appears within %1">, DefaultFatal;
+def ext_module_import_not_at_top_level_noop : ExtWarn<
+ "redundant #include of module '%0' appears within %1">, DefaultError,
+ InGroup<DiagGroup<"modules-import-nested-redundant">>;
def note_module_import_not_at_top_level : Note<"%0 begins here">;
def err_module_self_import : Error<
"import of module '%0' appears within same top-level module '%1'">;
SmallVector<Decl *, 32> FieldDecls;
// While we still have something to read, read the declarations in the struct.
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof) &&
- !tryParseMisplacedModuleImport()) {
+ while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
+ Tok.isNot(tok::eof)) {
// Each iteration of this loop reads one struct-declaration.
// Check for extraneous top-level semicolon.
ParsedAttributes &attrs,
BalancedDelimiterTracker &Tracker) {
if (index == Ident.size()) {
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof) &&
- !tryParseMisplacedModuleImport()) {
+ while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
+ Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
if (TagDecl) {
// While we still have something to read, read the member-declarations.
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof) &&
- !tryParseMisplacedModuleImport()) {
+ while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
+ Tok.isNot(tok::eof)) {
// Each iteration of this loop reads one member-declaration.
ParseCXXClassMemberDeclarationWithPragmas(
CurAS, AccessAttrs, static_cast<DeclSpec::TST>(TagType), TagDecl);
Stmts.push_back(R.get());
}
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof) &&
- !tryParseMisplacedModuleImport()) {
+ while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
+ Tok.isNot(tok::eof)) {
if (Tok.is(tok::annot_pragma_unused)) {
HandlePragmaUnused();
continue;
}
static void checkModuleImportContext(Sema &S, Module *M,
- SourceLocation ImportLoc,
- DeclContext *DC) {
+ SourceLocation ImportLoc, DeclContext *DC,
+ bool FromInclude = false) {
SourceLocation ExternCLoc;
if (auto *LSD = dyn_cast<LinkageSpecDecl>(DC)) {
DC = DC->getParent();
if (!isa<TranslationUnitDecl>(DC)) {
- S.Diag(ImportLoc, diag::err_module_import_not_at_top_level_fatal)
+ S.Diag(ImportLoc, (FromInclude && S.isModuleVisible(M))
+ ? diag::ext_module_import_not_at_top_level_noop
+ : diag::err_module_import_not_at_top_level_fatal)
<< M->getFullModuleName() << DC;
S.Diag(cast<Decl>(DC)->getLocStart(),
diag::note_module_import_not_at_top_level) << DC;
}
void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
- checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext);
+ checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true);
// Determine whether we're in the #include buffer for a module. The #includes
// in that buffer do not qualify as module imports; they're just an
// RUN: rm -rf %t
// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs %s -verify -DERRORS
// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs %s -verify
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs -xobjective-c++ %s -verify
//
// Test both with and without the declarations that refer to unimported
// entities. For error recovery, those cases implicitly trigger an import.
void includeNotAtTopLevel() { // expected-note {{function 'includeNotAtTopLevel' begins here}}
#include <NoUmbrella/A.h> // expected-warning {{treating #include as an import}} \
- expected-error {{import of module 'NoUmbrella.A' appears within function 'includeNotAtTopLevel'}}
+ expected-error {{redundant #include of module 'NoUmbrella.A' appears within function 'includeNotAtTopLevel'}}
}
+
+#ifdef __cplusplus
+namespace NS { // expected-note {{begins here}}
+#include <NoUmbrella/A.h> // expected-warning {{treating #include as an import}} \
+ expected-error {{redundant #include of module 'NoUmbrella.A' appears within namespace 'NS'}}
+}
+extern "C" { // expected-note {{begins here}}
+#include <NoUmbrella/A.h> // expected-warning {{treating #include as an import}} \
+ expected-error {{import of C++ module 'NoUmbrella.A' appears within extern "C"}}
+}
+#endif