mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-04 08:16:49 +00:00
[c++2a] Add semantic support for private module fragments.
llvm-svn: 358713
This commit is contained in:
parent
4664916017
commit
a5bbbfef15
@ -9276,8 +9276,20 @@ def note_global_module_introducer_missing : Note<
|
||||
def err_export_within_export : Error<
|
||||
"export declaration appears within another export declaration">;
|
||||
def err_export_not_in_module_interface : Error<
|
||||
"export declaration can only be used within a module interface unit after "
|
||||
"the module declaration">;
|
||||
"export declaration can only be used within a module interface unit"
|
||||
"%select{ after the module declaration|}0">;
|
||||
def err_export_in_private_module_fragment : Error<
|
||||
"export declaration cannot be used in a private module fragment">;
|
||||
def note_private_module_fragment : Note<
|
||||
"private module fragment begins here">;
|
||||
def err_private_module_fragment_not_module : Error<
|
||||
"private module fragment declaration with no preceding module declaration">;
|
||||
def err_private_module_fragment_redefined : Error<
|
||||
"private module fragment redefined">;
|
||||
def err_private_module_fragment_not_module_interface : Error<
|
||||
"private module fragment in module implementation unit">;
|
||||
def note_not_module_interface_add_export : Note<
|
||||
"add 'export' here if this is intended to be a module interface unit">;
|
||||
|
||||
def ext_equivalent_internal_linkage_decl_in_modules : ExtWarn<
|
||||
"ambiguous use of internal linkage declaration %0 defined in multiple modules">,
|
||||
|
@ -77,9 +77,11 @@ public:
|
||||
/// This is a C++ Modules TS module interface unit.
|
||||
ModuleInterfaceUnit,
|
||||
|
||||
/// This is a fragment of the global module within some C++ Modules
|
||||
/// TS module.
|
||||
/// This is a fragment of the global module within some C++ module.
|
||||
GlobalModuleFragment,
|
||||
|
||||
/// This is the private module fragment within some C++ module.
|
||||
PrivateModuleFragment,
|
||||
};
|
||||
|
||||
/// The kind of this module.
|
||||
@ -111,6 +113,11 @@ public:
|
||||
/// eventually be exposed, for use in "private" modules.
|
||||
std::string ExportAsModule;
|
||||
|
||||
/// Does this Module scope describe part of the purview of a named C++ module?
|
||||
bool isModulePurview() const {
|
||||
return Kind == ModuleInterfaceUnit || Kind == PrivateModuleFragment;
|
||||
}
|
||||
|
||||
private:
|
||||
/// The submodules of this module, indexed by name.
|
||||
std::vector<Module *> SubModules;
|
||||
|
@ -520,14 +520,18 @@ public:
|
||||
bool IsFramework,
|
||||
bool IsExplicit);
|
||||
|
||||
/// Create a 'global module' for a C++ Modules TS module interface unit.
|
||||
/// Create a global module fragment for a C++ module unit.
|
||||
///
|
||||
/// We model the global module as a submodule of the module interface unit.
|
||||
/// Unfortunately, we can't create the module interface unit's Module until
|
||||
/// later, because we don't know what it will be called.
|
||||
Module *createGlobalModuleForInterfaceUnit(SourceLocation Loc);
|
||||
/// We model the global module fragment as a submodule of the module
|
||||
/// interface unit. Unfortunately, we can't create the module interface
|
||||
/// unit's Module until later, because we don't know what it will be called.
|
||||
Module *createGlobalModuleFragmentForModuleUnit(SourceLocation Loc);
|
||||
|
||||
/// Create a new module for a C++ Modules TS module interface unit.
|
||||
/// Create a global module fragment for a C++ module interface unit.
|
||||
Module *createPrivateModuleFragmentForInterfaceUnit(Module *Parent,
|
||||
SourceLocation Loc);
|
||||
|
||||
/// Create a new module for a C++ module interface unit.
|
||||
/// The module must not already exist, and will be configured for the current
|
||||
/// compilation.
|
||||
///
|
||||
|
@ -1386,8 +1386,21 @@ public:
|
||||
|
||||
void emitAndClearUnusedLocalTypedefWarnings();
|
||||
|
||||
enum TUFragmentKind {
|
||||
/// The global module fragment, between 'module;' and a module-declaration.
|
||||
Global,
|
||||
/// A normal translation unit fragment. For a non-module unit, this is the
|
||||
/// entire translation unit. Otherwise, it runs from the module-declaration
|
||||
/// to the private-module-fragment (if any) or the end of the TU (if not).
|
||||
Normal,
|
||||
/// The private module fragment, between 'module :private;' and the end of
|
||||
/// the translation unit.
|
||||
Private
|
||||
};
|
||||
|
||||
void ActOnStartOfTranslationUnit();
|
||||
void ActOnEndOfTranslationUnit();
|
||||
void ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind);
|
||||
|
||||
void CheckDelegatingCtorCycles();
|
||||
|
||||
@ -2180,10 +2193,7 @@ public:
|
||||
/// \param ModuleLoc The location of the 'module' keyword.
|
||||
/// \param PrivateLoc The location of the 'private' keyword.
|
||||
DeclGroupPtrTy ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc,
|
||||
SourceLocation PrivateLoc) {
|
||||
// FIXME
|
||||
return DeclGroupPtrTy();
|
||||
}
|
||||
SourceLocation PrivateLoc);
|
||||
|
||||
/// The parser has processed a module import declaration.
|
||||
///
|
||||
|
@ -567,6 +567,13 @@ static bool isSingleLineLanguageLinkage(const Decl &D) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Determine whether D is declared in the purview of a named module.
|
||||
static bool isInModulePurview(const NamedDecl *D) {
|
||||
if (auto *M = D->getOwningModule())
|
||||
return M->isModulePurview();
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) {
|
||||
// FIXME: Handle isModulePrivate.
|
||||
switch (D->getModuleOwnershipKind()) {
|
||||
@ -575,8 +582,7 @@ static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) {
|
||||
return false;
|
||||
case Decl::ModuleOwnershipKind::Visible:
|
||||
case Decl::ModuleOwnershipKind::VisibleWhenImported:
|
||||
if (auto *M = D->getOwningModule())
|
||||
return M->Kind == Module::ModuleInterfaceUnit;
|
||||
return isInModulePurview(D);
|
||||
}
|
||||
llvm_unreachable("unexpected module ownership kind");
|
||||
}
|
||||
@ -586,9 +592,8 @@ static LinkageInfo getInternalLinkageFor(const NamedDecl *D) {
|
||||
// as "module-internal linkage", which means that they have internal linkage
|
||||
// formally but can be indirectly accessed from outside the module via inline
|
||||
// functions and templates defined within the module.
|
||||
if (auto *M = D->getOwningModule())
|
||||
if (M->Kind == Module::ModuleInterfaceUnit)
|
||||
return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false);
|
||||
if (isInModulePurview(D))
|
||||
return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false);
|
||||
|
||||
return LinkageInfo::internal();
|
||||
}
|
||||
@ -598,11 +603,9 @@ static LinkageInfo getExternalLinkageFor(const NamedDecl *D) {
|
||||
// - A name declared at namespace scope that does not have internal linkage
|
||||
// by the previous rules and that is introduced by a non-exported
|
||||
// declaration has module linkage.
|
||||
if (auto *M = D->getOwningModule())
|
||||
if (M->Kind == Module::ModuleInterfaceUnit)
|
||||
if (!isExportedFromModuleIntefaceUnit(
|
||||
cast<NamedDecl>(D->getCanonicalDecl())))
|
||||
return LinkageInfo(ModuleLinkage, DefaultVisibility, false);
|
||||
if (isInModulePurview(D) &&
|
||||
!isExportedFromModuleIntefaceUnit(cast<NamedDecl>(D->getCanonicalDecl())))
|
||||
return LinkageInfo(ModuleLinkage, DefaultVisibility, false);
|
||||
|
||||
return LinkageInfo::external();
|
||||
}
|
||||
@ -1507,6 +1510,11 @@ Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const {
|
||||
}
|
||||
return InternalLinkage ? M->Parent : nullptr;
|
||||
}
|
||||
|
||||
case Module::PrivateModuleFragment:
|
||||
// The private module fragment is part of its containing module for linkage
|
||||
// purposes.
|
||||
return M->Parent;
|
||||
}
|
||||
|
||||
llvm_unreachable("unknown module kind");
|
||||
|
@ -806,7 +806,7 @@ std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name,
|
||||
return std::make_pair(Result, true);
|
||||
}
|
||||
|
||||
Module *ModuleMap::createGlobalModuleForInterfaceUnit(SourceLocation Loc) {
|
||||
Module *ModuleMap::createGlobalModuleFragmentForModuleUnit(SourceLocation Loc) {
|
||||
PendingSubmodules.emplace_back(
|
||||
new Module("<global>", Loc, nullptr, /*IsFramework*/ false,
|
||||
/*IsExplicit*/ true, NumCreatedModules++));
|
||||
@ -814,6 +814,16 @@ Module *ModuleMap::createGlobalModuleForInterfaceUnit(SourceLocation Loc) {
|
||||
return PendingSubmodules.back().get();
|
||||
}
|
||||
|
||||
Module *
|
||||
ModuleMap::createPrivateModuleFragmentForInterfaceUnit(Module *Parent,
|
||||
SourceLocation Loc) {
|
||||
auto *Result =
|
||||
new Module("<private>", Loc, Parent, /*IsFramework*/ false,
|
||||
/*IsExplicit*/ true, NumCreatedModules++);
|
||||
Result->Kind = Module::PrivateModuleFragment;
|
||||
return Result;
|
||||
}
|
||||
|
||||
Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
|
||||
StringRef Name,
|
||||
Module *GlobalModule) {
|
||||
|
@ -857,20 +857,13 @@ void Sema::ActOnStartOfTranslationUnit() {
|
||||
}
|
||||
}
|
||||
|
||||
/// ActOnEndOfTranslationUnit - This is called at the very end of the
|
||||
/// translation unit when EOF is reached and all but the top-level scope is
|
||||
/// popped.
|
||||
void Sema::ActOnEndOfTranslationUnit() {
|
||||
assert(DelayedDiagnostics.getCurrentPool() == nullptr
|
||||
&& "reached end of translation unit with a pool attached?");
|
||||
|
||||
// If code completion is enabled, don't perform any end-of-translation-unit
|
||||
// work.
|
||||
if (PP.isCodeCompletionEnabled())
|
||||
void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) {
|
||||
// No explicit actions are required at the end of the global module fragment.
|
||||
if (Kind == TUFragmentKind::Global)
|
||||
return;
|
||||
|
||||
// Transfer late parsed template instantiations over to the pending template
|
||||
// instantiation list. During normal compliation, the late template parser
|
||||
// instantiation list. During normal compilation, the late template parser
|
||||
// will be installed and instantiating these templates will succeed.
|
||||
//
|
||||
// If we are building a TU prefix for serialization, it is also safe to
|
||||
@ -883,50 +876,79 @@ void Sema::ActOnEndOfTranslationUnit() {
|
||||
LateParsedInstantiations.end());
|
||||
LateParsedInstantiations.clear();
|
||||
|
||||
// If DefinedUsedVTables ends up marking any virtual member functions it
|
||||
// might lead to more pending template instantiations, which we then need
|
||||
// to instantiate.
|
||||
DefineUsedVTables();
|
||||
|
||||
// C++: Perform implicit template instantiations.
|
||||
//
|
||||
// FIXME: When we perform these implicit instantiations, we do not
|
||||
// carefully keep track of the point of instantiation (C++ [temp.point]).
|
||||
// This means that name lookup that occurs within the template
|
||||
// instantiation will always happen at the end of the translation unit,
|
||||
// so it will find some names that are not required to be found. This is
|
||||
// valid, but we could do better by diagnosing if an instantiation uses a
|
||||
// name that was not visible at its first point of instantiation.
|
||||
if (ExternalSource) {
|
||||
// Load pending instantiations from the external source.
|
||||
SmallVector<PendingImplicitInstantiation, 4> Pending;
|
||||
ExternalSource->ReadPendingInstantiations(Pending);
|
||||
for (auto PII : Pending)
|
||||
if (auto Func = dyn_cast<FunctionDecl>(PII.first))
|
||||
Func->setInstantiationIsPending(true);
|
||||
PendingInstantiations.insert(PendingInstantiations.begin(),
|
||||
Pending.begin(), Pending.end());
|
||||
}
|
||||
|
||||
{
|
||||
llvm::TimeTraceScope TimeScope("PerformPendingInstantiations",
|
||||
StringRef(""));
|
||||
PerformPendingInstantiations();
|
||||
}
|
||||
|
||||
assert(LateParsedInstantiations.empty() &&
|
||||
"end of TU template instantiation should not create more "
|
||||
"late-parsed templates");
|
||||
}
|
||||
|
||||
/// ActOnEndOfTranslationUnit - This is called at the very end of the
|
||||
/// translation unit when EOF is reached and all but the top-level scope is
|
||||
/// popped.
|
||||
void Sema::ActOnEndOfTranslationUnit() {
|
||||
assert(DelayedDiagnostics.getCurrentPool() == nullptr
|
||||
&& "reached end of translation unit with a pool attached?");
|
||||
|
||||
// If code completion is enabled, don't perform any end-of-translation-unit
|
||||
// work.
|
||||
if (PP.isCodeCompletionEnabled())
|
||||
return;
|
||||
|
||||
// Complete translation units and modules define vtables and perform implicit
|
||||
// instantiations. PCH files do not.
|
||||
if (TUKind != TU_Prefix) {
|
||||
DiagnoseUseOfUnimplementedSelectors();
|
||||
|
||||
// If DefinedUsedVTables ends up marking any virtual member functions it
|
||||
// might lead to more pending template instantiations, which we then need
|
||||
// to instantiate.
|
||||
DefineUsedVTables();
|
||||
|
||||
// C++: Perform implicit template instantiations.
|
||||
//
|
||||
// FIXME: When we perform these implicit instantiations, we do not
|
||||
// carefully keep track of the point of instantiation (C++ [temp.point]).
|
||||
// This means that name lookup that occurs within the template
|
||||
// instantiation will always happen at the end of the translation unit,
|
||||
// so it will find some names that are not required to be found. This is
|
||||
// valid, but we could do better by diagnosing if an instantiation uses a
|
||||
// name that was not visible at its first point of instantiation.
|
||||
if (ExternalSource) {
|
||||
// Load pending instantiations from the external source.
|
||||
SmallVector<PendingImplicitInstantiation, 4> Pending;
|
||||
ExternalSource->ReadPendingInstantiations(Pending);
|
||||
for (auto PII : Pending)
|
||||
if (auto Func = dyn_cast<FunctionDecl>(PII.first))
|
||||
Func->setInstantiationIsPending(true);
|
||||
PendingInstantiations.insert(PendingInstantiations.begin(),
|
||||
Pending.begin(), Pending.end());
|
||||
}
|
||||
|
||||
{
|
||||
llvm::TimeTraceScope TimeScope("PerformPendingInstantiations",
|
||||
StringRef(""));
|
||||
PerformPendingInstantiations();
|
||||
}
|
||||
|
||||
assert(LateParsedInstantiations.empty() &&
|
||||
"end of TU template instantiation should not create more "
|
||||
"late-parsed templates");
|
||||
ActOnEndOfTranslationUnitFragment(
|
||||
!ModuleScopes.empty() && ModuleScopes.back().Module->Kind ==
|
||||
Module::PrivateModuleFragment
|
||||
? TUFragmentKind::Private
|
||||
: TUFragmentKind::Normal);
|
||||
|
||||
if (LateTemplateParserCleanup)
|
||||
LateTemplateParserCleanup(OpaqueParser);
|
||||
|
||||
CheckDelayedMemberExceptionSpecs();
|
||||
} else {
|
||||
// If we are building a TU prefix for serialization, it is safe to transfer
|
||||
// these over, even though they are not parsed. The end of the TU should be
|
||||
// outside of any eager template instantiation scope, so when this AST is
|
||||
// deserialized, these templates will not be parsed until the end of the
|
||||
// combined TU.
|
||||
PendingInstantiations.insert(PendingInstantiations.end(),
|
||||
LateParsedInstantiations.begin(),
|
||||
LateParsedInstantiations.end());
|
||||
LateParsedInstantiations.clear();
|
||||
}
|
||||
|
||||
DiagnoseUnterminatedPragmaPack();
|
||||
@ -1000,7 +1022,7 @@ void Sema::ActOnEndOfTranslationUnit() {
|
||||
if (getLangOpts().getCompilingModule() ==
|
||||
LangOptions::CMK_ModuleInterface &&
|
||||
(ModuleScopes.empty() ||
|
||||
ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) &&
|
||||
!ModuleScopes.back().Module->isModulePurview()) &&
|
||||
!DiagnosedMissingModuleDeclaration) {
|
||||
// FIXME: Make a better guess as to where to put the module declaration.
|
||||
Diag(getSourceManager().getLocForStartOfFile(
|
||||
|
@ -1461,12 +1461,17 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
|
||||
|
||||
Module *NewM = New->getOwningModule();
|
||||
Module *OldM = Old->getOwningModule();
|
||||
|
||||
if (NewM && NewM->Kind == Module::PrivateModuleFragment)
|
||||
NewM = NewM->Parent;
|
||||
if (OldM && OldM->Kind == Module::PrivateModuleFragment)
|
||||
OldM = OldM->Parent;
|
||||
|
||||
if (NewM == OldM)
|
||||
return false;
|
||||
|
||||
// FIXME: Check proclaimed-ownership-declarations here too.
|
||||
bool NewIsModuleInterface = NewM && NewM->Kind == Module::ModuleInterfaceUnit;
|
||||
bool OldIsModuleInterface = OldM && OldM->Kind == Module::ModuleInterfaceUnit;
|
||||
bool NewIsModuleInterface = NewM && NewM->isModulePurview();
|
||||
bool OldIsModuleInterface = OldM && OldM->isModulePurview();
|
||||
if (NewIsModuleInterface || OldIsModuleInterface) {
|
||||
// C++ Modules TS [basic.def.odr] 6.2/6.7 [sic]:
|
||||
// if a declaration of D [...] appears in the purview of a module, all
|
||||
|
@ -69,7 +69,7 @@ Sema::ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc) {
|
||||
// We start in the global module; all those declarations are implicitly
|
||||
// module-private (though they do not have module linkage).
|
||||
auto &Map = PP.getHeaderSearchInfo().getModuleMap();
|
||||
auto *GlobalModule = Map.createGlobalModuleForInterfaceUnit(ModuleLoc);
|
||||
auto *GlobalModule = Map.createGlobalModuleFragmentForModuleUnit(ModuleLoc);
|
||||
assert(GlobalModule && "module creation should not fail");
|
||||
|
||||
// Enter the scope of the global module.
|
||||
@ -128,7 +128,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
|
||||
|
||||
// Only one module-declaration is permitted per source file.
|
||||
if (!ModuleScopes.empty() &&
|
||||
ModuleScopes.back().Module->Kind == Module::ModuleInterfaceUnit) {
|
||||
ModuleScopes.back().Module->isModulePurview()) {
|
||||
Diag(ModuleLoc, diag::err_module_redeclaration);
|
||||
Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module),
|
||||
diag::note_prev_module_declaration);
|
||||
@ -220,6 +220,9 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
|
||||
ModuleScopes.push_back({});
|
||||
if (getLangOpts().ModulesLocalVisibility)
|
||||
ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
|
||||
} else {
|
||||
// We're done with the global module fragment now.
|
||||
ActOnEndOfTranslationUnitFragment(TUFragmentKind::Global);
|
||||
}
|
||||
|
||||
// Switch from the global module fragment (if any) to the named module.
|
||||
@ -239,6 +242,68 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Sema::DeclGroupPtrTy
|
||||
Sema::ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc,
|
||||
SourceLocation PrivateLoc) {
|
||||
// C++20 [basic.link]/2:
|
||||
// A private-module-fragment shall appear only in a primary module
|
||||
// interface unit.
|
||||
switch (ModuleScopes.empty() ? Module::GlobalModuleFragment
|
||||
: ModuleScopes.back().Module->Kind) {
|
||||
case Module::ModuleMapModule:
|
||||
case Module::GlobalModuleFragment:
|
||||
Diag(PrivateLoc, diag::err_private_module_fragment_not_module);
|
||||
return nullptr;
|
||||
|
||||
case Module::PrivateModuleFragment:
|
||||
Diag(PrivateLoc, diag::err_private_module_fragment_redefined);
|
||||
Diag(ModuleScopes.back().BeginLoc, diag::note_previous_definition);
|
||||
return nullptr;
|
||||
|
||||
case Module::ModuleInterfaceUnit:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ModuleScopes.back().ModuleInterface) {
|
||||
Diag(PrivateLoc, diag::err_private_module_fragment_not_module_interface);
|
||||
Diag(ModuleScopes.back().BeginLoc,
|
||||
diag::note_not_module_interface_add_export)
|
||||
<< FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export ");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// FIXME: Check this isn't a module interface partition.
|
||||
// FIXME: Check that this translation unit does not import any partitions;
|
||||
// such imports would violate [basic.link]/2's "shall be the only module unit"
|
||||
// restriction.
|
||||
|
||||
// We've finished the public fragment of the translation unit.
|
||||
ActOnEndOfTranslationUnitFragment(TUFragmentKind::Normal);
|
||||
|
||||
auto &Map = PP.getHeaderSearchInfo().getModuleMap();
|
||||
Module *PrivateModuleFragment =
|
||||
Map.createPrivateModuleFragmentForInterfaceUnit(
|
||||
ModuleScopes.back().Module, PrivateLoc);
|
||||
assert(PrivateModuleFragment && "module creation should not fail");
|
||||
|
||||
// Enter the scope of the private module fragment.
|
||||
ModuleScopes.push_back({});
|
||||
ModuleScopes.back().BeginLoc = ModuleLoc;
|
||||
ModuleScopes.back().Module = PrivateModuleFragment;
|
||||
ModuleScopes.back().ModuleInterface = true;
|
||||
VisibleModules.setVisible(PrivateModuleFragment, ModuleLoc);
|
||||
|
||||
// All declarations created from now on are scoped to the private module
|
||||
// fragment (and are neither visible nor reachable in importers of the module
|
||||
// interface).
|
||||
auto *TU = Context.getTranslationUnitDecl();
|
||||
TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
|
||||
TU->setLocalOwningModule(PrivateModuleFragment);
|
||||
|
||||
// FIXME: Consider creating an explicit representation of this declaration.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
|
||||
SourceLocation ExportLoc,
|
||||
SourceLocation ImportLoc,
|
||||
@ -451,17 +516,26 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
|
||||
SourceLocation LBraceLoc) {
|
||||
ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc);
|
||||
|
||||
// C++ Modules TS draft:
|
||||
// An export-declaration shall appear in the purview of a module other than
|
||||
// the global module.
|
||||
if (ModuleScopes.empty() || !ModuleScopes.back().ModuleInterface)
|
||||
Diag(ExportLoc, diag::err_export_not_in_module_interface);
|
||||
// C++20 [module.interface]p1:
|
||||
// An export-declaration shall appear only [...] in the purview of a module
|
||||
// interface unit. An export-declaration shall not appear directly or
|
||||
// indirectly within an unnamed namespace or a private-module-fragment.
|
||||
// FIXME: Check for the unnamed namespace case.
|
||||
if (ModuleScopes.empty() || !ModuleScopes.back().Module->isModulePurview()) {
|
||||
Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0;
|
||||
} else if (!ModuleScopes.back().ModuleInterface) {
|
||||
Diag(ExportLoc, diag::err_export_not_in_module_interface) << 1;
|
||||
Diag(ModuleScopes.back().BeginLoc,
|
||||
diag::note_not_module_interface_add_export)
|
||||
<< FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export ");
|
||||
} else if (ModuleScopes.back().Module->Kind ==
|
||||
Module::PrivateModuleFragment) {
|
||||
Diag(ExportLoc, diag::err_export_in_private_module_fragment);
|
||||
Diag(ModuleScopes.back().BeginLoc, diag::note_private_module_fragment);
|
||||
}
|
||||
|
||||
// An export-declaration [...] shall not contain more than one
|
||||
// export keyword.
|
||||
//
|
||||
// The intent here is that an export-declaration cannot appear within another
|
||||
// export-declaration.
|
||||
// [...] its declaration or declaration-seq shall not contain an
|
||||
// export-declaration.
|
||||
if (D->isExported())
|
||||
Diag(ExportLoc, diag::err_export_within_export);
|
||||
|
||||
|
@ -1,24 +1,31 @@
|
||||
// RUN: %clang_cc1 -std=c++2a -verify %s
|
||||
// RUN: %clang_cc1 -std=c++2a -verify -DNO_GLOBAL_FRAG %s
|
||||
// RUN: %clang_cc1 -std=c++2a -verify -DNO_MODULE_DECL %s
|
||||
// RUN: %clang_cc1 -std=c++2a -verify -DNO_PRIVATE_FRAG %s
|
||||
// RUN: %clang_cc1 -std=c++2a -verify -DNO_MODULE_DECL -DNO_PRIVATE_FRAG %s
|
||||
// RUN: %clang_cc1 -std=c++2a -verify -DNO_GLOBAL_FRAG -DNO_PRIVATE_FRAG %s
|
||||
// RUN: %clang_cc1 -std=c++2a -verify -DNO_GLOBAL_FRAG -DNO_MODULE_DECL %s
|
||||
// RUN: %clang_cc1 -std=c++2a -verify -DNO_GLOBAL_FRAG -DNO_MODULE_DECL -DNO_PRIVATE_FRAG %s
|
||||
// RUN: %clang_cc1 -std=c++2a -verify -DEXPORT_FRAGS %s
|
||||
|
||||
#ifdef NO_GLOBAL_FRAG
|
||||
// expected-error@#mod-decl {{module declaration must occur at the start of the translation unit}}
|
||||
// expected-note@1 {{add 'module;' to the start of the file to introduce a global module fragment}}
|
||||
#else
|
||||
#ifndef NO_GLOBAL_FRAG
|
||||
#ifdef EXPORT_FRAGS
|
||||
export // expected-error {{global module fragment cannot be exported}}
|
||||
#endif
|
||||
module; // #glob-frag
|
||||
module;
|
||||
#ifdef NO_MODULE_DECL
|
||||
// expected-error@-2 {{missing 'module' declaration at end of global module fragment introduced here}}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern int a; // #a1
|
||||
|
||||
#ifdef NO_MODULE_DECL
|
||||
// expected-error@#glob-frag {{missing 'module' declaration at end of global module fragment introduced here}}
|
||||
#else
|
||||
export module Foo; // #mod-decl
|
||||
#ifndef NO_MODULE_DECL
|
||||
export module Foo;
|
||||
#ifdef NO_GLOBAL_FRAG
|
||||
// expected-error@-2 {{module declaration must occur at the start of the translation unit}}
|
||||
// expected-note@1 {{add 'module;' to the start of the file to introduce a global module fragment}}
|
||||
#endif
|
||||
|
||||
// expected-error@#a2 {{declaration of 'a' in module Foo follows declaration in the global module}}
|
||||
// expected-note@#a1 {{previous decl}}
|
||||
@ -29,9 +36,22 @@ extern int b;
|
||||
|
||||
module; // expected-error {{'module;' introducing a global module fragment can appear only at the start of the translation unit}}
|
||||
|
||||
#ifndef NO_PRIVATE_FRAG
|
||||
#ifdef EXPORT_FRAGS
|
||||
export // expected-error {{private module fragment cannot be exported}}
|
||||
#endif
|
||||
module :private;
|
||||
module :private; // #priv-frag
|
||||
#ifdef NO_MODULE_DECL
|
||||
// expected-error@-2 {{private module fragment declaration with no preceding module declaration}}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int b; // ok
|
||||
|
||||
|
||||
#ifndef NO_PRIVATE_FRAG
|
||||
#ifndef NO_MODULE_DECL
|
||||
module :private; // expected-error {{private module fragment redefined}}
|
||||
// expected-note@#priv-frag {{previous definition is here}}
|
||||
#endif
|
||||
#endif
|
||||
|
16
clang/test/CXX/basic/basic.link/p2.cpp
Normal file
16
clang/test/CXX/basic/basic.link/p2.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
// RUN: %clang_cc1 -std=c++2a -DEXPORT %s -verify
|
||||
// RUN: %clang_cc1 -std=c++2a -DEXPORT %s -emit-module-interface -o %t.pcm
|
||||
// RUN: %clang_cc1 -std=c++2a -UEXPORT %s -verify -fmodule-file=%t.pcm
|
||||
|
||||
#ifdef EXPORT
|
||||
// expected-no-diagnostics
|
||||
export
|
||||
#else
|
||||
// expected-note@+2 {{add 'export' here}}
|
||||
#endif
|
||||
module M;
|
||||
|
||||
#ifndef EXPORT
|
||||
// expected-error@+2 {{private module fragment in module implementation unit}}
|
||||
#endif
|
||||
module :private;
|
38
clang/test/CXX/module/module.interface/p1.cpp
Normal file
38
clang/test/CXX/module/module.interface/p1.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
// RUN: %clang_cc1 -std=c++2a %s -DERRORS -verify
|
||||
// RUN: %clang_cc1 -std=c++2a %s -emit-module-interface -o %t.pcm
|
||||
// RUN: %clang_cc1 -std=c++2a %s -fmodule-file=%t.pcm -DIMPLEMENTATION -verify -Db=b2 -Dc=c2
|
||||
|
||||
module;
|
||||
|
||||
#ifdef ERRORS
|
||||
export int a; // expected-error {{after the module declaration}}
|
||||
#endif
|
||||
|
||||
#ifndef IMPLEMENTATION
|
||||
export
|
||||
#else
|
||||
// expected-error@#1 {{can only be used within a module interface unit}}
|
||||
// expected-error@#2 {{can only be used within a module interface unit}}
|
||||
// expected-note@+2 1+{{add 'export'}}
|
||||
#endif
|
||||
module M;
|
||||
|
||||
export int b; // #1
|
||||
namespace N {
|
||||
export int c; // #2
|
||||
}
|
||||
|
||||
#ifdef ERRORS
|
||||
namespace {
|
||||
export int d1; // FIXME: invalid
|
||||
namespace X {
|
||||
export int d2; // FIXME: invalid
|
||||
}
|
||||
}
|
||||
|
||||
export export int e; // expected-error {{within another export declaration}}
|
||||
export { export int f; } // expected-error {{within another export declaration}}
|
||||
|
||||
module :private; // expected-note {{private module fragment begins here}}
|
||||
export int priv; // expected-error {{export declaration cannot be used in a private module fragment}}
|
||||
#endif
|
@ -10,7 +10,7 @@
|
||||
// expected-no-diagnostics
|
||||
export module A;
|
||||
#elif IMPLEMENTATION
|
||||
module A;
|
||||
module A; // #module-decl
|
||||
#ifdef BUILT_AS_INTERFACE
|
||||
// expected-error@-2 {{missing 'export' specifier in module declaration while building module interface}}
|
||||
#define INTERFACE
|
||||
@ -23,6 +23,9 @@ module A;
|
||||
|
||||
#ifndef INTERFACE
|
||||
export int b; // expected-error {{export declaration can only be used within a module interface unit}}
|
||||
#ifdef IMPLEMENTATION
|
||||
// expected-note@#module-decl {{add 'export' here}}
|
||||
#endif
|
||||
#else
|
||||
export int a;
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user