summaryrefslogtreecommitdiffstats
path: root/lib/Lex/Pragma.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Lex/Pragma.cpp')
-rw-r--r--lib/Lex/Pragma.cpp167
1 files changed, 124 insertions, 43 deletions
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 576151a98b..51da2baac9 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -534,47 +534,6 @@ 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) {
@@ -1342,6 +1301,26 @@ public:
}
};
+static bool LexModuleName(
+ Preprocessor &PP, Token &Tok,
+ llvm::SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>>
+ &ModuleName) {
+ while (true) {
+ PP.LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pp_expected_module_name)
+ << ModuleName.empty();
+ return true;
+ }
+
+ ModuleName.emplace_back(Tok.getIdentifierInfo(), Tok.getLocation());
+
+ PP.LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::period))
+ return false;
+ }
+}
+
/// Handle the clang \#pragma module import extension. The syntax is:
/// \code
/// #pragma clang module import some.module.name
@@ -1350,8 +1329,108 @@ struct PragmaModuleImportHandler : public PragmaHandler {
PragmaModuleImportHandler() : PragmaHandler("import") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &ImportTok) override {
- PP.HandlePragmaModuleImport(ImportTok);
+ Token &Tok) override {
+ SourceLocation ImportLoc = Tok.getLocation();
+
+ // Read the module name.
+ llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8>
+ ModuleName;
+ if (LexModuleName(PP, Tok, ModuleName))
+ return;
+
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
+
+ // If we have a non-empty module path, load the named module.
+ Module *Imported =
+ PP.getModuleLoader().loadModule(ImportLoc, ModuleName, Module::Hidden,
+ /*IsIncludeDirective=*/false);
+ if (!Imported)
+ return;
+
+ PP.makeModuleVisible(Imported, ImportLoc);
+ PP.EnterAnnotationToken(SourceRange(ImportLoc, ModuleName.back().second),
+ tok::annot_module_include, Imported);
+ if (auto *CB = PP.getPPCallbacks())
+ CB->moduleImport(ImportLoc, ModuleName, Imported);
+ }
+};
+
+/// Handle the clang \#pragma module begin extension. The syntax is:
+/// \code
+/// #pragma clang module begin some.module.name
+/// ...
+/// #pragma clang module end
+/// \endcode
+struct PragmaModuleBeginHandler : public PragmaHandler {
+ PragmaModuleBeginHandler() : PragmaHandler("begin") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
+ SourceLocation BeginLoc = Tok.getLocation();
+
+ // Read the module name.
+ llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8>
+ ModuleName;
+ if (LexModuleName(PP, Tok, ModuleName))
+ return;
+
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
+
+ // We can only enter submodules of the current module.
+ StringRef Current = PP.getLangOpts().CurrentModule;
+ if (ModuleName.front().first->getName() != Current) {
+ PP.Diag(ModuleName.front().second, diag::err_pp_module_begin_wrong_module)
+ << ModuleName.front().first << (ModuleName.size() > 1)
+ << Current.empty() << Current;
+ return;
+ }
+
+ // Find the module we're entering. We require that a module map for it
+ // be loaded or implicitly loadable.
+ // FIXME: We could create the submodule here. We'd need to know whether
+ // it's supposed to be explicit, but not much else.
+ Module *M = PP.getHeaderSearchInfo().getModuleMap().findModule(Current);
+ if (!M) {
+ PP.Diag(ModuleName.front().second,
+ diag::err_pp_module_begin_no_module_map) << Current;
+ return;
+ }
+ for (unsigned I = 1; I != ModuleName.size(); ++I) {
+ auto *NewM = M->findSubmodule(ModuleName[I].first->getName());
+ if (!NewM) {
+ PP.Diag(ModuleName[I].second, diag::err_pp_module_begin_no_submodule)
+ << M->getFullModuleName() << ModuleName[I].first;
+ return;
+ }
+ M = NewM;
+ }
+
+ // Enter the scope of the submodule.
+ PP.EnterSubmodule(M, BeginLoc, /*ForPragma*/true);
+ PP.EnterAnnotationToken(SourceRange(BeginLoc, ModuleName.back().second),
+ tok::annot_module_begin, M);
+ }
+};
+
+/// Handle the clang \#pragma module end extension.
+struct PragmaModuleEndHandler : public PragmaHandler {
+ PragmaModuleEndHandler() : PragmaHandler("end") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
+ SourceLocation Loc = Tok.getLocation();
+
+ PP.LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
+
+ Module *M = PP.LeaveSubmodule(/*ForPragma*/true);
+ if (M)
+ PP.EnterAnnotationToken(SourceRange(Loc), tok::annot_module_end, M);
+ else
+ PP.Diag(Loc, diag::err_pp_module_end_without_module_begin);
}
};
@@ -1582,6 +1661,8 @@ void Preprocessor::RegisterBuiltinPragmas() {
auto *ModuleHandler = new PragmaNamespace("module");
AddPragmaHandler("clang", ModuleHandler);
ModuleHandler->AddPragma(new PragmaModuleImportHandler());
+ ModuleHandler->AddPragma(new PragmaModuleBeginHandler());
+ ModuleHandler->AddPragma(new PragmaModuleEndHandler());
AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler());
AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler());