diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Parse/ParseAST.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Parse/Parser.cpp | 128 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 55 |
3 files changed, 153 insertions, 32 deletions
diff --git a/clang/lib/Parse/ParseAST.cpp b/clang/lib/Parse/ParseAST.cpp index 1fb57a08c43..bab3dbefb0d 100644 --- a/clang/lib/Parse/ParseAST.cpp +++ b/clang/lib/Parse/ParseAST.cpp @@ -147,7 +147,7 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { if (External) External->StartTranslationUnit(Consumer); - if (P.ParseTopLevelDecl(ADecl)) { + if (P.ParseFirstTopLevelDecl(ADecl)) { if (!External && !S.getLangOpts().CPlusPlus) P.Diag(diag::ext_empty_translation_unit); } else { diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 9f941f40da1..a391363ff38 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -537,6 +537,20 @@ void Parser::LateTemplateParserCleanupCallback(void *P) { DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(((Parser *)P)->TemplateIds); } +bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) { + // C++ Modules TS: module-declaration must be the first declaration in the + // file. (There can be no preceding preprocessor directives, but we expect + // the lexer to check that.) + if (Tok.is(tok::kw_module)) { + Result = ParseModuleDecl(); + return false; + } + // FIXME: If we're parsing a module interface and we don't have a module + // declaration here, diagnose. + + return ParseTopLevelDecl(Result); +} + /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the /// action tells us to. This returns true if the EOF was encountered. bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { @@ -2000,18 +2014,58 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() { Braces.consumeClose(); } +/// Parse a C++ Modules TS module declaration, which appears at the beginning +/// of a module interface, module partition, or module implementation file. +/// +/// module-declaration: [Modules TS + P0273R0] +/// 'module' module-kind[opt] module-name attribute-specifier-seq[opt] ';' +/// module-kind: +/// 'implementation' +/// 'partition' +/// +/// Note that the module-kind values are context-sensitive keywords. +Parser::DeclGroupPtrTy Parser::ParseModuleDecl() { + assert(Tok.is(tok::kw_module) && getLangOpts().ModulesTS && + "should not be parsing a module declaration"); + SourceLocation ModuleLoc = ConsumeToken(); + + // Check for a module-kind. + Sema::ModuleDeclKind MDK = Sema::ModuleDeclKind::Module; + if (Tok.is(tok::identifier) && NextToken().is(tok::identifier)) { + if (Tok.getIdentifierInfo()->isStr("implementation")) + MDK = Sema::ModuleDeclKind::Implementation; + else if (Tok.getIdentifierInfo()->isStr("partition")) + MDK = Sema::ModuleDeclKind::Partition; + else { + Diag(Tok, diag::err_unexpected_module_kind) << Tok.getIdentifierInfo(); + SkipUntil(tok::semi); + return nullptr; + } + ConsumeToken(); + } + + SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; + if (ParseModuleName(ModuleLoc, Path, /*IsImport*/false)) + return nullptr; + + ParsedAttributesWithRange Attrs(AttrFactory); + MaybeParseCXX11Attributes(Attrs); + // We don't support any module attributes yet. + ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr); + + ExpectAndConsumeSemi(diag::err_module_expected_semi); + + return Actions.ActOnModuleDecl(ModuleLoc, MDK, Path); +} + /// Parse a module import declaration. This is essentially the same for /// Objective-C and the C++ Modules TS, except for the leading '@' (in ObjC) /// and the trailing optional attributes (in C++). /// /// [ObjC] @import declaration: -/// '@' 'import' (identifier '.')* ';' +/// '@' 'import' module-name ';' /// [ModTS] module-import-declaration: -/// 'module' module-name attribute-specifier-seq[opt] ';' -/// module-name: -/// module-name-qualifier[opt] identifier -/// module-name-qualifier: -/// module-name-qualifier[opt] identifier '.' +/// 'import' module-name attribute-specifier-seq[opt] ';' Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) { assert((AtLoc.isInvalid() ? Tok.is(tok::kw_import) : Tok.isObjCAtKeyword(tok::objc_import)) && @@ -2020,30 +2074,8 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) { SourceLocation StartLoc = AtLoc.isInvalid() ? ImportLoc : AtLoc; SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; - - // Parse the module path. - while (true) { - if (!Tok.is(tok::identifier)) { - if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteModuleImport(ImportLoc, Path); - cutOffParsing(); - return nullptr; - } - - Diag(Tok, diag::err_module_expected_ident); - SkipUntil(tok::semi); - return nullptr; - } - - // Record this part of the module path. - Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation())); - ConsumeToken(); - - if (Tok.isNot(tok::period)) - break; - - ConsumeToken(); - } + if (ParseModuleName(ImportLoc, Path, /*IsImport*/true)) + return nullptr; ParsedAttributesWithRange Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); @@ -2064,6 +2096,42 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) { return Actions.ConvertDeclToDeclGroup(Import.get()); } +/// Parse a C++ Modules TS / Objective-C module name (both forms use the same +/// grammar). +/// +/// module-name: +/// module-name-qualifier[opt] identifier +/// module-name-qualifier: +/// module-name-qualifier[opt] identifier '.' +bool Parser::ParseModuleName( + SourceLocation UseLoc, + SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path, + bool IsImport) { + // Parse the module path. + while (true) { + if (!Tok.is(tok::identifier)) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteModuleImport(UseLoc, Path); + cutOffParsing(); + return true; + } + + Diag(Tok, diag::err_module_expected_ident) << IsImport; + SkipUntil(tok::semi); + return true; + } + + // Record this part of the module path. + Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation())); + ConsumeToken(); + + if (Tok.isNot(tok::period)) + return false; + + ConsumeToken(); + } +} + /// \brief Try recover parser when module annotation appears where it must not /// be found. /// \returns false if the recover was successful and parsing may be continued, or diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 5dab15a8d66..ca4de55fb51 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15178,6 +15178,56 @@ void Sema::diagnoseMisplacedModuleImport(Module *M, SourceLocation ImportLoc) { return checkModuleImportContext(*this, M, ImportLoc, CurContext); } +Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation ModuleLoc, + ModuleDeclKind MDK, + ModuleIdPath Path) { + // We should see 'module implementation' if and only if we are not compiling + // a module interface. + if (getLangOpts().CompilingModule == + (MDK == ModuleDeclKind::Implementation)) { + Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch) + << (unsigned)MDK; + return nullptr; + } + + // FIXME: Create a ModuleDecl and return it. + // FIXME: Teach the lexer to handle this declaration too. + + switch (MDK) { + case ModuleDeclKind::Module: + // FIXME: Check we're not in a submodule. + // FIXME: Set CurrentModule and create a corresponding Module object. + return nullptr; + + case ModuleDeclKind::Partition: + // FIXME: Check we are in a submodule of the named module. + return nullptr; + + case ModuleDeclKind::Implementation: + DeclResult Import = ActOnModuleImport(ModuleLoc, ModuleLoc, Path); + if (Import.isInvalid()) + return nullptr; + ImportDecl *ID = cast<ImportDecl>(Import.get()); + + // The current module is whatever we just loaded. + // + // FIXME: We should probably do this from the lexer rather than waiting + // until now, in case we look ahead across something where the current + // module matters (eg a #include). + auto Name = ID->getImportedModule()->getTopLevelModuleName(); + if (!getLangOpts().CurrentModule.empty() && + getLangOpts().CurrentModule != Name) { + Diag(Path.front().second, diag::err_current_module_name_mismatch) + << SourceRange(Path.front().second, Path.back().second) + << getLangOpts().CurrentModule; + } + const_cast<LangOptions&>(getLangOpts()).CurrentModule = Name; + return ConvertDeclToDeclGroup(ID); + } + + llvm_unreachable("unexpected module decl kind"); +} + DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, SourceLocation ImportLoc, ModuleIdPath Path) { @@ -15194,7 +15244,10 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, // FIXME: we should support importing a submodule within a different submodule // of the same top-level module. Until we do, make it an error rather than // silently ignoring the import. - if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule) + // Import-from-implementation is valid in the Modules TS. FIXME: Should we + // warn on a redundant import of the current module? + if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule && + (getLangOpts().CompilingModule || !getLangOpts().ModulesTS)) Diag(ImportLoc, getLangOpts().CompilingModule ? diag::err_module_self_import : diag::err_module_import_in_implementation) |