When we hit a #include directive that maps to a module import, emit a token
representing the module import rather than making the module immediately
visible. This serves two goals:
* It avoids making declarations in the module visible prematurely, if we
walk past the #include during a tentative parse, for instance, and
* It gives a diagnostic (although, admittedly, not a very nice one) if
a header with a corresponding module is included anywhere other than
at the top level.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@194782 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index c17449c..6812cce 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -667,6 +667,9 @@
ANNOTATION(pragma_openmp)
ANNOTATION(pragma_openmp_end)
+// Annotation for module import translated from #include etc.
+ANNOTATION(module_include)
+
#undef ANNOTATION
#undef TESTING_KEYWORD
#undef OBJC2_AT_KEYWORD
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 19cef42..ed28583 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1600,6 +1600,10 @@
DeclResult ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc,
ModuleIdPath Path);
+ /// \brief The parser has processed a module import translated from a
+ /// #include or similar preprocessing directive.
+ void ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod);
+
/// \brief Create an implicit import of the given module at the given
/// source location.
///
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 3545d70..55a66d8 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -657,6 +657,11 @@
// -traditional-cpp the lexer keeps /all/ whitespace, including comments.
SourceLocation StartLoc = Tok.getLocation();
Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength()));
+ } else if (Tok.is(tok::annot_module_include)) {
+ // PrintPPOutputPPCallbacks::InclusionDirective handles producing
+ // appropriate output here. Ignore this token entirely.
+ PP.Lex(Tok);
+ continue;
} else if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
OS << II->getName();
} else if (Tok.isLiteral() && !Tok.needsCleaning() &&
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 9ba65a5..86c508f 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -1603,10 +1603,9 @@
"@import " + PathString.str().str() + ";");
}
- // Load the module.
- // If this was an #__include_macros directive, only make macros visible.
- Module::NameVisibilityKind Visibility
- = (IncludeKind == 3)? Module::MacrosVisible : Module::AllVisible;
+ // Load the module. Only make macros visible. We'll make the declarations
+ // visible when the parser gets here.
+ Module::NameVisibilityKind Visibility = Module::MacrosVisible;
ModuleLoadResult Imported
= TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility,
/*IsIncludeDirective=*/true);
@@ -1626,7 +1625,7 @@
}
return;
}
-
+
// If this header isn't part of the module we're building, we're done.
if (!BuildingImportedModule && Imported) {
if (Callbacks) {
@@ -1634,6 +1633,20 @@
FilenameRange, File,
SearchPath, RelativePath, Imported);
}
+
+ if (IncludeKind != 3) {
+ // Let the parser know that we hit a module import, and it should
+ // make the module visible.
+ // FIXME: Produce this as the current token directly, rather than
+ // allocating a new token for it.
+ Token *Tok = new Token[1];
+ Tok[0].startToken();
+ Tok[0].setKind(tok::annot_module_include);
+ Tok[0].setLocation(HashLoc);
+ Tok[0].setAnnotationEndLoc(End);
+ Tok[0].setAnnotationValue(Imported);
+ EnterTokenStream(Tok, 1, true, true);
+ }
return;
}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 84aad41..c6eac18 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -566,19 +566,30 @@
if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof))
ConsumeToken();
- while (Tok.is(tok::annot_pragma_unused))
- HandlePragmaUnused();
-
Result = DeclGroupPtrTy();
- if (Tok.is(tok::eof)) {
+ switch (Tok.getKind()) {
+ case tok::annot_pragma_unused:
+ HandlePragmaUnused();
+ return false;
+
+ case tok::annot_module_include:
+ Actions.ActOnModuleInclude(Tok.getLocation(),
+ reinterpret_cast<Module *>(
+ Tok.getAnnotationValue()));
+ ConsumeToken();
+ return false;
+
+ case tok::eof:
// Late template parsing can begin.
if (getLangOpts().DelayedTemplateParsing)
Actions.SetLateTemplateParser(LateTemplateParserCallback, this);
if (!PP.isIncrementalProcessingEnabled())
Actions.ActOnEndOfTranslationUnit();
//else don't tell Sema that we ended parsing: more input might come.
-
return true;
+
+ default:
+ break;
}
ParsedAttributesWithRange attrs(AttrFactory);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 211e858..f550779 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -12913,6 +12913,12 @@
return Import;
}
+void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
+ // FIXME: Should we synthesize an ImportDecl here?
+ PP.getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc,
+ /*Complain=*/true);
+}
+
void Sema::createImplicitModuleImport(SourceLocation Loc, Module *Mod) {
// Create the implicit import declaration.
TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
diff --git a/test/Modules/auto-module-import.m b/test/Modules/auto-module-import.m
index 23bb63b..d7fb9d1 100644
--- a/test/Modules/auto-module-import.m
+++ b/test/Modules/auto-module-import.m
@@ -82,3 +82,7 @@
int getNotInModule() {
return not_in_module;
}
+
+void includeNotAtTopLevel() {
+ #include <NoUmbrella/A.h> // expected-warning {{treating #include as an import}} expected-error {{expected expression}}
+}