summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Parse/ParseAST.cpp2
-rw-r--r--clang/lib/Parse/Parser.cpp128
-rw-r--r--clang/lib/Sema/SemaDecl.cpp55
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)
OpenPOWER on IntegriCloud