Skip to content

Commit 69350e5

Browse files
committed
[C++20][Modules][3/8] Initial handling for module partitions.
This implements the parsing and recognition of module partition CMIs and removes the FIXMEs in the parser. Module partitions are recognised in the base computation of visibility, however additional amendments to visibility follow in subsequent patches. Differential Revision: https://reviews.llvm.org/D118586
1 parent e1d4d1c commit 69350e5

File tree

11 files changed

+256
-89
lines changed

11 files changed

+256
-89
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4467,6 +4467,16 @@ class CapturedDecl final
44674467
/// @import std.vector;
44684468
/// \endcode
44694469
///
4470+
/// A C++20 module import declaration imports the named module or partition.
4471+
/// Periods are permitted in C++20 module names, but have no semantic meaning.
4472+
/// For example:
4473+
/// \code
4474+
/// import NamedModule;
4475+
/// import :SomePartition; // Must be a partition of the current module.
4476+
/// import Names.Like.this; // Allowed.
4477+
/// import :and.Also.Partition.names;
4478+
/// \endcode
4479+
///
44704480
/// Import declarations can also be implicitly generated from
44714481
/// \#include/\#import directives.
44724482
class ImportDecl final : public Decl,

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1541,9 +1541,11 @@ def err_private_module_fragment_expected_semi : Error<
15411541
"expected ';' after private module fragment declaration">;
15421542
def err_missing_before_module_end : Error<"expected %0 at end of module">;
15431543
def err_unsupported_module_partition : Error<
1544-
"sorry, module partitions are not yet supported">;
1544+
"module partitions are only supported for C++20 onwards">;
15451545
def err_import_not_allowed_here : Error<
15461546
"imports must immediately follow the module declaration">;
1547+
def err_partition_import_outside_module : Error<
1548+
"module partition imports must be within a module purview">;
15471549
def err_import_in_wrong_fragment : Error<
15481550
"module%select{| partition}0 imports cannot be in the %select{global|private}1 module fragment">;
15491551

clang/include/clang/Sema/Sema.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2210,6 +2210,7 @@ class Sema final {
22102210
SourceLocation BeginLoc;
22112211
clang::Module *Module = nullptr;
22122212
bool ModuleInterface = false;
2213+
bool IsPartition = false;
22132214
bool ImplicitGlobalModuleFragment = false;
22142215
VisibleModuleSet OuterVisibleModules;
22152216
};
@@ -2962,7 +2963,7 @@ class Sema final {
29622963
/// of a module interface or implementation.
29632964
DeclGroupPtrTy ActOnModuleDecl(SourceLocation StartLoc,
29642965
SourceLocation ModuleLoc, ModuleDeclKind MDK,
2965-
ModuleIdPath Path,
2966+
ModuleIdPath Path, ModuleIdPath Partition,
29662967
ModuleImportState &ImportState);
29672968

29682969
/// The parser has processed a global-module-fragment declaration that begins
@@ -2983,10 +2984,12 @@ class Sema final {
29832984
/// could be the location of an '@', 'export', or 'import'.
29842985
/// \param ExportLoc The location of the 'export' keyword, if any.
29852986
/// \param ImportLoc The location of the 'import' keyword.
2986-
/// \param Path The module access path.
2987+
/// \param Path The module toplevel name as an access path.
2988+
/// \param Partition The module partition name as an access path.
29872989
DeclResult ActOnModuleImport(SourceLocation StartLoc,
29882990
SourceLocation ExportLoc,
2989-
SourceLocation ImportLoc, ModuleIdPath Path);
2991+
SourceLocation ImportLoc, ModuleIdPath Path,
2992+
ModuleIdPath Partition = {});
29902993
DeclResult ActOnModuleImport(SourceLocation StartLoc,
29912994
SourceLocation ExportLoc,
29922995
SourceLocation ImportLoc, Module *M,

clang/lib/Parse/Parser.cpp

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2364,20 +2364,19 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) {
23642364
}
23652365

23662366
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
2367-
if (ParseModuleName(ModuleLoc, Path, /*IsImport*/false))
2367+
if (ParseModuleName(ModuleLoc, Path, /*IsImport*/ false))
23682368
return nullptr;
23692369

23702370
// Parse the optional module-partition.
2371+
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition;
23712372
if (Tok.is(tok::colon)) {
23722373
SourceLocation ColonLoc = ConsumeToken();
2373-
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition;
2374-
if (ParseModuleName(ModuleLoc, Partition, /*IsImport*/false))
2374+
if (!getLangOpts().CPlusPlusModules)
2375+
Diag(ColonLoc, diag::err_unsupported_module_partition)
2376+
<< SourceRange(ColonLoc, Partition.back().second);
2377+
// Recover by ignoring the partition name.
2378+
else if (ParseModuleName(ModuleLoc, Partition, /*IsImport*/ false))
23752379
return nullptr;
2376-
2377-
// FIXME: Support module partition declarations.
2378-
Diag(ColonLoc, diag::err_unsupported_module_partition)
2379-
<< SourceRange(ColonLoc, Partition.back().second);
2380-
// Recover by parsing as a non-partition.
23812380
}
23822381

23832382
// We don't support any module attributes yet; just parse them and diagnose.
@@ -2387,18 +2386,19 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) {
23872386

23882387
ExpectAndConsumeSemi(diag::err_module_expected_semi);
23892388

2390-
return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, ImportState);
2389+
return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, Partition,
2390+
ImportState);
23912391
}
23922392

23932393
/// Parse a module import declaration. This is essentially the same for
2394-
/// Objective-C and the C++ Modules TS, except for the leading '@' (in ObjC)
2395-
/// and the trailing optional attributes (in C++).
2394+
/// Objective-C and C++20 except for the leading '@' (in ObjC) and the
2395+
/// trailing optional attributes (in C++).
23962396
///
23972397
/// [ObjC] @import declaration:
23982398
/// '@' 'import' module-name ';'
23992399
/// [ModTS] module-import-declaration:
24002400
/// 'import' module-name attribute-specifier-seq[opt] ';'
2401-
/// [C++2a] module-import-declaration:
2401+
/// [C++20] module-import-declaration:
24022402
/// 'export'[opt] 'import' module-name
24032403
/// attribute-specifier-seq[opt] ';'
24042404
/// 'export'[opt] 'import' module-partition
@@ -2418,9 +2418,10 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
24182418
bool IsObjCAtImport = Tok.isObjCAtKeyword(tok::objc_import);
24192419
SourceLocation ImportLoc = ConsumeToken();
24202420

2421+
// For C++20 modules, we can have "name" or ":Partition name" as valid input.
24212422
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
2423+
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition;
24222424
Module *HeaderUnit = nullptr;
2423-
24242425
if (Tok.is(tok::header_name)) {
24252426
// This is a header import that the preprocessor decided we should skip
24262427
// because it was malformed in some way. Parse and ignore it; it's already
@@ -2430,17 +2431,16 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
24302431
// This is a header import that the preprocessor mapped to a module import.
24312432
HeaderUnit = reinterpret_cast<Module *>(Tok.getAnnotationValue());
24322433
ConsumeAnnotationToken();
2433-
} else if (getLangOpts().CPlusPlusModules && Tok.is(tok::colon)) {
2434+
} else if (Tok.is(tok::colon)) {
24342435
SourceLocation ColonLoc = ConsumeToken();
2435-
if (ParseModuleName(ImportLoc, Path, /*IsImport*/true))
2436+
if (!getLangOpts().CPlusPlusModules)
2437+
Diag(ColonLoc, diag::err_unsupported_module_partition)
2438+
<< SourceRange(ColonLoc, Partition.back().second);
2439+
// Recover by leaving partition empty.
2440+
else if (ParseModuleName(ColonLoc, Partition, /*IsImport*/ true))
24362441
return nullptr;
2437-
2438-
// FIXME: Support module partition import.
2439-
Diag(ColonLoc, diag::err_unsupported_module_partition)
2440-
<< SourceRange(ColonLoc, Path.back().second);
2441-
return nullptr;
24422442
} else {
2443-
if (ParseModuleName(ImportLoc, Path, /*IsImport*/true))
2443+
if (ParseModuleName(ImportLoc, Path, /*IsImport*/ true))
24442444
return nullptr;
24452445
}
24462446

@@ -2457,21 +2457,24 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
24572457

24582458
// Diagnose mis-imports.
24592459
bool SeenError = true;
2460+
bool HasPart = !Partition.empty();
24602461
switch (ImportState) {
24612462
case Sema::ModuleImportState::ImportAllowed:
24622463
SeenError = false;
24632464
break;
24642465
case Sema::ModuleImportState::FirstDecl:
24652466
case Sema::ModuleImportState::NotACXX20Module:
2466-
// TODO: These cases will be an error when partitions are implemented.
2467-
SeenError = false;
2467+
// We can only import a partition within a module purview.
2468+
if (HasPart)
2469+
Diag(ImportLoc, diag::err_partition_import_outside_module);
2470+
else
2471+
SeenError = false;
24682472
break;
24692473
case Sema::ModuleImportState::GlobalFragment:
24702474
// We can only have pre-processor directives in the global module
24712475
// fragment. We can, however have a header unit import here.
24722476
if (!HeaderUnit)
2473-
// We do not have partition support yet, so first arg is 0.
2474-
Diag(ImportLoc, diag::err_import_in_wrong_fragment) << 0 << 0;
2477+
Diag(ImportLoc, diag::err_import_in_wrong_fragment) << HasPart << 0;
24752478
else
24762479
SeenError = false;
24772480
break;
@@ -2482,8 +2485,7 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
24822485
SeenError = false;
24832486
break;
24842487
case Sema::ModuleImportState::PrivateFragment:
2485-
// We do not have partition support yet, so first arg is 0.
2486-
Diag(ImportLoc, diag::err_import_in_wrong_fragment) << 0 << 1;
2488+
Diag(ImportLoc, diag::err_import_in_wrong_fragment) << HasPart << 1;
24872489
break;
24882490
}
24892491
if (SeenError) {
@@ -2495,8 +2497,9 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
24952497
if (HeaderUnit)
24962498
Import =
24972499
Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, HeaderUnit);
2498-
else if (!Path.empty())
2499-
Import = Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Path);
2500+
else if (!Path.empty() || !Partition.empty())
2501+
Import = Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Path,
2502+
Partition);
25002503
ExpectAndConsumeSemi(diag::err_module_expected_semi);
25012504
if (Import.isInvalid())
25022505
return nullptr;

clang/lib/Sema/SemaDecl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,6 +1608,14 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
16081608
if (OldM && OldM->Kind == Module::PrivateModuleFragment)
16091609
OldM = OldM->Parent;
16101610

1611+
// If we have a decl in a module partition, it is part of the containing
1612+
// module (which is the only thing that can be importing it).
1613+
if (NewM && OldM &&
1614+
(OldM->Kind == Module::ModulePartitionInterface ||
1615+
OldM->Kind == Module::ModulePartitionImplementation)) {
1616+
return false;
1617+
}
1618+
16111619
if (NewM == OldM)
16121620
return false;
16131621

clang/lib/Sema/SemaLookup.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1561,8 +1561,12 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() {
15611561
static bool isInCurrentModule(const Module *M, const LangOptions &LangOpts) {
15621562
// If M is the global module fragment of a module that we've not yet finished
15631563
// parsing, then it must be part of the current module.
1564+
// If it's a partition, then it must be visible to an importer (since only
1565+
// another partition or the named module can import it).
15641566
return M->getTopLevelModuleName() == LangOpts.CurrentModule ||
1565-
(M->Kind == Module::GlobalModuleFragment && !M->Parent);
1567+
(M->Kind == Module::GlobalModuleFragment && !M->Parent) ||
1568+
M->Kind == Module::ModulePartitionInterface ||
1569+
M->Kind == Module::ModulePartitionImplementation;
15661570
}
15671571

15681572
bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) {

0 commit comments

Comments
 (0)