summaryrefslogtreecommitdiffstats
path: root/lib/Lex
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2017-04-29 00:34:47 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2017-04-29 00:34:47 +0000
commitee60c74826a0ec615fcc7fef362686f4aae95c1a (patch)
tree571977cdcc552e6b3ccdd3f9ebbb3af053fa9644 /lib/Lex
parent538445b124c198013a391d78bb2865221ce88dce (diff)
Add pragma to perform module import and use it in -E output.
Many of our supported configurations support modules but do not have any first-class syntax to perform a module import. This leaves us with a problem: there is no way to represent the expansion of a #include that imports a module in the -E output for such languages. (We don't want to just leave it as a #include because that requires the consumer of the preprocessed source to have the same file system layout and include paths as the creator.) This patch adds a new pragma: #pragma clang module import MODULE.NAME.HERE that imports a module, and changes -E and -frewrite-includes to use it when rewriting a #include that maps to a module import. We don't make any attempt to use a native language syntax import if one exists, to get more consistent output. (If in the future, @import and #include have different semantics in some way, the pragma will track the #include semantics.) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@301725 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Lex')
-rw-r--r--lib/Lex/PPDirectives.cpp17
-rw-r--r--lib/Lex/Pragma.cpp59
2 files changed, 68 insertions, 8 deletions
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 54578e8fb9..4826e399af 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -1588,18 +1588,18 @@ bool Preprocessor::ConcatenateIncludeName(SmallString<128> &FilenameBuffer,
}
/// \brief Push a token onto the token stream containing an annotation.
-static void EnterAnnotationToken(Preprocessor &PP,
- SourceLocation Begin, SourceLocation End,
- tok::TokenKind Kind, void *AnnotationVal) {
+void Preprocessor::EnterAnnotationToken(SourceRange Range,
+ tok::TokenKind Kind,
+ void *AnnotationVal) {
// FIXME: Produce this as the current token directly, rather than
// allocating a new token for it.
auto Tok = llvm::make_unique<Token[]>(1);
Tok[0].startToken();
Tok[0].setKind(Kind);
- Tok[0].setLocation(Begin);
- Tok[0].setAnnotationEndLoc(End);
+ Tok[0].setLocation(Range.getBegin());
+ Tok[0].setAnnotationEndLoc(Range.getEnd());
Tok[0].setAnnotationValue(AnnotationVal);
- PP.EnterTokenStream(std::move(Tok), 1, true);
+ EnterTokenStream(std::move(Tok), 1, true);
}
/// \brief Produce a diagnostic informing the user that a #include or similar
@@ -2021,7 +2021,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
if (IncludeTok.getIdentifierInfo()->getPPKeywordID() !=
tok::pp___include_macros)
- EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_include, M);
+ EnterAnnotationToken(SourceRange(HashLoc, End),
+ tok::annot_module_include, M);
}
return;
}
@@ -2059,7 +2060,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// submodule.
// FIXME: There's no point doing this if we're handling a #__include_macros
// directive.
- EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_begin, M);
+ EnterAnnotationToken(SourceRange(HashLoc, End), tok::annot_module_begin, M);
}
}
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index fcaaa2d416..576151a98b 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -534,6 +534,47 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
}
}
+void Preprocessor::HandlePragmaModuleImport(Token &ImportTok) {
+ SourceLocation ImportLoc = ImportTok.getLocation();
+
+ Token Tok;
+
+ llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8> ModuleName;
+ while (true) {
+ LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok.getLocation(),
+ diag::err_pragma_module_import_expected_module_name) << 0;
+ return;
+ }
+
+ ModuleName.emplace_back(Tok.getIdentifierInfo(), Tok.getLocation());
+
+ LexUnexpandedToken(Tok);
+ assert(Tok.isNot(tok::eof));
+ if (Tok.is(tok::eod))
+ break;
+ if (Tok.isNot(tok::period)) {
+ Diag(Tok.getLocation(),
+ diag::err_pragma_module_import_expected_module_name) << 1;
+ return;
+ }
+ }
+
+ // If we have a non-empty module path, load the named module.
+ Module *Imported =
+ TheModuleLoader.loadModule(ImportLoc, ModuleName, Module::Hidden,
+ /*IsIncludeDirective=*/false);
+ if (!Imported)
+ return;
+
+ makeModuleVisible(Imported, ImportLoc);
+ EnterAnnotationToken(SourceRange(ImportLoc, Tok.getLocation()),
+ tok::annot_module_include, Imported);
+ if (Callbacks)
+ Callbacks->moduleImport(ImportLoc, ModuleName, Imported);
+}
+
/// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro.
/// Return the IdentifierInfo* associated with the macro to push or pop.
IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) {
@@ -1301,6 +1342,19 @@ public:
}
};
+/// Handle the clang \#pragma module import extension. The syntax is:
+/// \code
+/// #pragma clang module import some.module.name
+/// \endcode
+struct PragmaModuleImportHandler : public PragmaHandler {
+ PragmaModuleImportHandler() : PragmaHandler("import") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &ImportTok) override {
+ PP.HandlePragmaModuleImport(ImportTok);
+ }
+};
+
/// PragmaPushMacroHandler - "\#pragma push_macro" saves the value of the
/// macro on the top of the stack.
struct PragmaPushMacroHandler : public PragmaHandler {
@@ -1524,6 +1578,11 @@ void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler());
AddPragmaHandler("clang", new PragmaAssumeNonNullHandler());
+ // #pragma clang module ...
+ auto *ModuleHandler = new PragmaNamespace("module");
+ AddPragmaHandler("clang", ModuleHandler);
+ ModuleHandler->AddPragma(new PragmaModuleImportHandler());
+
AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler());
AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler());
AddPragmaHandler("STDC", new PragmaSTDC_UnknownHandler());