forked from OSchip/llvm-project
[modules] When a #include is mapped to a module import and appears somewhere
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. llvm-svn: 253398
This commit is contained in:
parent
70507e59fe
commit
752ada870d
|
@ -7930,6 +7930,9 @@ def note_module_import_in_extern_c : Note<
|
|||
"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'">;
|
||||
|
|
|
@ -3589,8 +3589,8 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
|
|||
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.
|
||||
|
|
|
@ -210,8 +210,8 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation> &IdentLoc,
|
|||
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);
|
||||
|
@ -3064,8 +3064,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
|||
|
||||
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);
|
||||
|
|
|
@ -948,8 +948,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
|
|||
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;
|
||||
|
|
|
@ -14500,8 +14500,8 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
|
|||
}
|
||||
|
||||
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)) {
|
||||
|
@ -14520,7 +14520,9 @@ static void checkModuleImportContext(Sema &S, Module *M,
|
|||
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;
|
||||
|
@ -14579,7 +14581,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
|
|||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// 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.
|
||||
|
@ -85,5 +86,16 @@ int getNotInModule() {
|
|||
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue