Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit f76493a

Browse files
committed
C++ Modules TS: support parsing the 'module' declaration (including extensions
from p0273r0 approved by EWG). We'll eventually need to handle this from the lexer as well, in order to disallow preprocessor directives preceding the module declaration and to support macro import. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@279196 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent cbb67b5 commit f76493a

File tree

8 files changed

+217
-36
lines changed

8 files changed

+217
-36
lines changed

include/clang/Basic/DiagnosticParseKinds.td

+5-1
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,11 @@ def warn_pragma_unroll_cuda_value_in_parens : Warning<
10221022

10231023
let CategoryName = "Modules Issue" in {
10241024
def err_module_expected_ident : Error<
1025-
"expected a module name after module import">;
1025+
"expected a module name after module%select{| import}0">;
1026+
def err_unexpected_module_kind : Error<
1027+
"unexpected module kind %0; expected 'implementation' or 'partition'">;
1028+
def err_attribute_not_module_attr : Error<
1029+
"%0 attribute cannot be applied to a module">;
10261030
def err_attribute_not_import_attr : Error<
10271031
"%0 attribute cannot be applied to a module import">;
10281032
def err_module_expected_semi : Error<

include/clang/Basic/DiagnosticSemaKinds.td

+5
Original file line numberDiff line numberDiff line change
@@ -8462,6 +8462,11 @@ def note_related_result_type_explicit : Note<
84628462
}
84638463

84648464
let CategoryName = "Modules Issue" in {
8465+
def err_module_interface_implementation_mismatch : Error<
8466+
"%select{'module'|'module partition'|'module implementation'}0 declaration "
8467+
"found while %select{not |not |}0building module interface">;
8468+
def err_current_module_name_mismatch : Error<
8469+
"module name '%0' specified on command line does not match name of module">;
84658470
def err_module_private_specialization : Error<
84668471
"%select{template|partial|member}0 specialization cannot be "
84678472
"declared __module_private__">;

include/clang/Parse/Parser.h

+9
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,9 @@ class Parser : public CodeCompletionHandler {
278278
///
279279
void Initialize();
280280

281+
/// Parse the first top-level declaration in a translation unit.
282+
bool ParseFirstTopLevelDecl(DeclGroupPtrTy &Result);
283+
281284
/// ParseTopLevelDecl - Parse one top-level declaration. Returns true if
282285
/// the EOF was encountered.
283286
bool ParseTopLevelDecl(DeclGroupPtrTy &Result);
@@ -2656,6 +2659,7 @@ class Parser : public CodeCompletionHandler {
26562659

26572660
//===--------------------------------------------------------------------===//
26582661
// Modules
2662+
DeclGroupPtrTy ParseModuleDecl();
26592663
DeclGroupPtrTy ParseModuleImport(SourceLocation AtLoc);
26602664
bool parseMisplacedModuleImport();
26612665
bool tryParseMisplacedModuleImport() {
@@ -2666,6 +2670,11 @@ class Parser : public CodeCompletionHandler {
26662670
return false;
26672671
}
26682672

2673+
bool ParseModuleName(
2674+
SourceLocation UseLoc,
2675+
SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path,
2676+
bool IsImport);
2677+
26692678
//===--------------------------------------------------------------------===//
26702679
// C++11/G++: Type Traits [Type-Traits.html in the GCC manual]
26712680
ExprResult ParseTypeTrait();

include/clang/Sema/Sema.h

+11
Original file line numberDiff line numberDiff line change
@@ -1859,6 +1859,17 @@ class Sema {
18591859
AttributeList *AttrList,
18601860
SourceLocation SemiLoc);
18611861

1862+
enum class ModuleDeclKind {
1863+
Module, ///< 'module X;'
1864+
Partition, ///< 'module partition X;'
1865+
Implementation, ///< 'module implementation X;'
1866+
};
1867+
1868+
/// The parser has processed a module-declaration that begins the definition
1869+
/// of a module interface or implementation.
1870+
DeclGroupPtrTy ActOnModuleDecl(SourceLocation ModuleLoc, ModuleDeclKind MDK,
1871+
ModuleIdPath Path);
1872+
18621873
/// \brief The parser has processed a module import declaration.
18631874
///
18641875
/// \param AtLoc The location of the '@' symbol, if any.

lib/Parse/ParseAST.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
147147
if (External)
148148
External->StartTranslationUnit(Consumer);
149149

150-
if (P.ParseTopLevelDecl(ADecl)) {
150+
if (P.ParseFirstTopLevelDecl(ADecl)) {
151151
if (!External && !S.getLangOpts().CPlusPlus)
152152
P.Diag(diag::ext_empty_translation_unit);
153153
} else {

lib/Parse/Parser.cpp

+98-30
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,20 @@ void Parser::LateTemplateParserCleanupCallback(void *P) {
537537
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(((Parser *)P)->TemplateIds);
538538
}
539539

540+
bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) {
541+
// C++ Modules TS: module-declaration must be the first declaration in the
542+
// file. (There can be no preceding preprocessor directives, but we expect
543+
// the lexer to check that.)
544+
if (Tok.is(tok::kw_module)) {
545+
Result = ParseModuleDecl();
546+
return false;
547+
}
548+
// FIXME: If we're parsing a module interface and we don't have a module
549+
// declaration here, diagnose.
550+
551+
return ParseTopLevelDecl(Result);
552+
}
553+
540554
/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
541555
/// action tells us to. This returns true if the EOF was encountered.
542556
bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
@@ -2000,18 +2014,58 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
20002014
Braces.consumeClose();
20012015
}
20022016

2017+
/// Parse a C++ Modules TS module declaration, which appears at the beginning
2018+
/// of a module interface, module partition, or module implementation file.
2019+
///
2020+
/// module-declaration: [Modules TS + P0273R0]
2021+
/// 'module' module-kind[opt] module-name attribute-specifier-seq[opt] ';'
2022+
/// module-kind:
2023+
/// 'implementation'
2024+
/// 'partition'
2025+
///
2026+
/// Note that the module-kind values are context-sensitive keywords.
2027+
Parser::DeclGroupPtrTy Parser::ParseModuleDecl() {
2028+
assert(Tok.is(tok::kw_module) && getLangOpts().ModulesTS &&
2029+
"should not be parsing a module declaration");
2030+
SourceLocation ModuleLoc = ConsumeToken();
2031+
2032+
// Check for a module-kind.
2033+
Sema::ModuleDeclKind MDK = Sema::ModuleDeclKind::Module;
2034+
if (Tok.is(tok::identifier) && NextToken().is(tok::identifier)) {
2035+
if (Tok.getIdentifierInfo()->isStr("implementation"))
2036+
MDK = Sema::ModuleDeclKind::Implementation;
2037+
else if (Tok.getIdentifierInfo()->isStr("partition"))
2038+
MDK = Sema::ModuleDeclKind::Partition;
2039+
else {
2040+
Diag(Tok, diag::err_unexpected_module_kind) << Tok.getIdentifierInfo();
2041+
SkipUntil(tok::semi);
2042+
return nullptr;
2043+
}
2044+
ConsumeToken();
2045+
}
2046+
2047+
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
2048+
if (ParseModuleName(ModuleLoc, Path, /*IsImport*/false))
2049+
return nullptr;
2050+
2051+
ParsedAttributesWithRange Attrs(AttrFactory);
2052+
MaybeParseCXX11Attributes(Attrs);
2053+
// We don't support any module attributes yet.
2054+
ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr);
2055+
2056+
ExpectAndConsumeSemi(diag::err_module_expected_semi);
2057+
2058+
return Actions.ActOnModuleDecl(ModuleLoc, MDK, Path);
2059+
}
2060+
20032061
/// Parse a module import declaration. This is essentially the same for
20042062
/// Objective-C and the C++ Modules TS, except for the leading '@' (in ObjC)
20052063
/// and the trailing optional attributes (in C++).
20062064
///
20072065
/// [ObjC] @import declaration:
2008-
/// '@' 'import' (identifier '.')* ';'
2066+
/// '@' 'import' module-name ';'
20092067
/// [ModTS] module-import-declaration:
2010-
/// 'module' module-name attribute-specifier-seq[opt] ';'
2011-
/// module-name:
2012-
/// module-name-qualifier[opt] identifier
2013-
/// module-name-qualifier:
2014-
/// module-name-qualifier[opt] identifier '.'
2068+
/// 'import' module-name attribute-specifier-seq[opt] ';'
20152069
Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
20162070
assert((AtLoc.isInvalid() ? Tok.is(tok::kw_import)
20172071
: Tok.isObjCAtKeyword(tok::objc_import)) &&
@@ -2020,30 +2074,8 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
20202074
SourceLocation StartLoc = AtLoc.isInvalid() ? ImportLoc : AtLoc;
20212075

20222076
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
2023-
2024-
// Parse the module path.
2025-
while (true) {
2026-
if (!Tok.is(tok::identifier)) {
2027-
if (Tok.is(tok::code_completion)) {
2028-
Actions.CodeCompleteModuleImport(ImportLoc, Path);
2029-
cutOffParsing();
2030-
return nullptr;
2031-
}
2032-
2033-
Diag(Tok, diag::err_module_expected_ident);
2034-
SkipUntil(tok::semi);
2035-
return nullptr;
2036-
}
2037-
2038-
// Record this part of the module path.
2039-
Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation()));
2040-
ConsumeToken();
2041-
2042-
if (Tok.isNot(tok::period))
2043-
break;
2044-
2045-
ConsumeToken();
2046-
}
2077+
if (ParseModuleName(ImportLoc, Path, /*IsImport*/true))
2078+
return nullptr;
20472079

20482080
ParsedAttributesWithRange Attrs(AttrFactory);
20492081
MaybeParseCXX11Attributes(Attrs);
@@ -2064,6 +2096,42 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
20642096
return Actions.ConvertDeclToDeclGroup(Import.get());
20652097
}
20662098

2099+
/// Parse a C++ Modules TS / Objective-C module name (both forms use the same
2100+
/// grammar).
2101+
///
2102+
/// module-name:
2103+
/// module-name-qualifier[opt] identifier
2104+
/// module-name-qualifier:
2105+
/// module-name-qualifier[opt] identifier '.'
2106+
bool Parser::ParseModuleName(
2107+
SourceLocation UseLoc,
2108+
SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path,
2109+
bool IsImport) {
2110+
// Parse the module path.
2111+
while (true) {
2112+
if (!Tok.is(tok::identifier)) {
2113+
if (Tok.is(tok::code_completion)) {
2114+
Actions.CodeCompleteModuleImport(UseLoc, Path);
2115+
cutOffParsing();
2116+
return true;
2117+
}
2118+
2119+
Diag(Tok, diag::err_module_expected_ident) << IsImport;
2120+
SkipUntil(tok::semi);
2121+
return true;
2122+
}
2123+
2124+
// Record this part of the module path.
2125+
Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation()));
2126+
ConsumeToken();
2127+
2128+
if (Tok.isNot(tok::period))
2129+
return false;
2130+
2131+
ConsumeToken();
2132+
}
2133+
}
2134+
20672135
/// \brief Try recover parser when module annotation appears where it must not
20682136
/// be found.
20692137
/// \returns false if the recover was successful and parsing may be continued, or

lib/Sema/SemaDecl.cpp

+54-1
Original file line numberDiff line numberDiff line change
@@ -15178,6 +15178,56 @@ void Sema::diagnoseMisplacedModuleImport(Module *M, SourceLocation ImportLoc) {
1517815178
return checkModuleImportContext(*this, M, ImportLoc, CurContext);
1517915179
}
1518015180

15181+
Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation ModuleLoc,
15182+
ModuleDeclKind MDK,
15183+
ModuleIdPath Path) {
15184+
// We should see 'module implementation' if and only if we are not compiling
15185+
// a module interface.
15186+
if (getLangOpts().CompilingModule ==
15187+
(MDK == ModuleDeclKind::Implementation)) {
15188+
Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch)
15189+
<< (unsigned)MDK;
15190+
return nullptr;
15191+
}
15192+
15193+
// FIXME: Create a ModuleDecl and return it.
15194+
// FIXME: Teach the lexer to handle this declaration too.
15195+
15196+
switch (MDK) {
15197+
case ModuleDeclKind::Module:
15198+
// FIXME: Check we're not in a submodule.
15199+
// FIXME: Set CurrentModule and create a corresponding Module object.
15200+
return nullptr;
15201+
15202+
case ModuleDeclKind::Partition:
15203+
// FIXME: Check we are in a submodule of the named module.
15204+
return nullptr;
15205+
15206+
case ModuleDeclKind::Implementation:
15207+
DeclResult Import = ActOnModuleImport(ModuleLoc, ModuleLoc, Path);
15208+
if (Import.isInvalid())
15209+
return nullptr;
15210+
ImportDecl *ID = cast<ImportDecl>(Import.get());
15211+
15212+
// The current module is whatever we just loaded.
15213+
//
15214+
// FIXME: We should probably do this from the lexer rather than waiting
15215+
// until now, in case we look ahead across something where the current
15216+
// module matters (eg a #include).
15217+
auto Name = ID->getImportedModule()->getTopLevelModuleName();
15218+
if (!getLangOpts().CurrentModule.empty() &&
15219+
getLangOpts().CurrentModule != Name) {
15220+
Diag(Path.front().second, diag::err_current_module_name_mismatch)
15221+
<< SourceRange(Path.front().second, Path.back().second)
15222+
<< getLangOpts().CurrentModule;
15223+
}
15224+
const_cast<LangOptions&>(getLangOpts()).CurrentModule = Name;
15225+
return ConvertDeclToDeclGroup(ID);
15226+
}
15227+
15228+
llvm_unreachable("unexpected module decl kind");
15229+
}
15230+
1518115231
DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
1518215232
SourceLocation ImportLoc,
1518315233
ModuleIdPath Path) {
@@ -15194,7 +15244,10 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
1519415244
// FIXME: we should support importing a submodule within a different submodule
1519515245
// of the same top-level module. Until we do, make it an error rather than
1519615246
// silently ignoring the import.
15197-
if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule)
15247+
// Import-from-implementation is valid in the Modules TS. FIXME: Should we
15248+
// warn on a redundant import of the current module?
15249+
if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule &&
15250+
(getLangOpts().CompilingModule || !getLangOpts().ModulesTS))
1519815251
Diag(ImportLoc, getLangOpts().CompilingModule
1519915252
? diag::err_module_self_import
1520015253
: diag::err_module_import_in_implementation)

test/Parser/cxx-modules-import.cpp

+34-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,41 @@
11
// RUN: rm -rf %t
22
// RUN: mkdir -p %t
33
// RUN: echo 'int a, b;' > %t/x.h
4-
// RUN: echo 'module x { header "x.h" module y {} }' > %t/map
5-
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s
4+
// RUN: echo 'module x { header "x.h" module y {} } module z {}' > %t/map
5+
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
6+
// RUN: -DTEST=1 -DMODULE_KIND=implementation -DMODULE_NAME=z
7+
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
8+
// RUN: -DTEST=2 -DMODULE_KIND=implementation -DMODULE_NAME=x
9+
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
10+
// RUN: -DTEST=3 -DMODULE_KIND= -DMODULE_NAME=z
11+
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
12+
// RUN: -DTEST=4 -DMODULE_KIND=partition -DMODULE_NAME=z
13+
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
14+
// RUN: -DTEST=5 -DMODULE_KIND=elderberry -DMODULE_NAME=z
15+
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
16+
// RUN: -DTEST=1 -DMODULE_KIND=implementation -DMODULE_NAME='z [[]]'
17+
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
18+
// RUN: -DTEST=6 -DMODULE_KIND=implementation -DMODULE_NAME='z [[fancy]]'
19+
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
20+
// RUN: -DTEST=7 -DMODULE_KIND=implementation -DMODULE_NAME='z [[maybe_unused]]'
621

7-
int use_1 = a; // expected-error {{undeclared}}
22+
module MODULE_KIND MODULE_NAME;
23+
#if TEST == 3
24+
// expected-error@-2 {{'module' declaration found while not building module interface}}
25+
#elif TEST == 4
26+
// expected-error@-4 {{'module partition' declaration found while not building module interface}}
27+
#elif TEST == 5
28+
// expected-error@-6 {{unexpected module kind 'elderberry'}}
29+
#elif TEST == 6
30+
// expected-warning@-8 {{unknown attribute 'fancy' ignored}}
31+
#elif TEST == 7
32+
// expected-error-re@-10 {{'maybe_unused' attribute cannot be applied to a module{{$}}}}
33+
#endif
34+
35+
int use_1 = a;
36+
#if TEST != 2
37+
// expected-error@-2 {{undeclared}}
38+
#endif
839

940
import x;
1041

0 commit comments

Comments
 (0)