diff options
Diffstat (limited to 'lib/Lex/Pragma.cpp')
-rw-r--r-- | lib/Lex/Pragma.cpp | 167 |
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()); |