forked from OSchip/llvm-project
[c++20] Parsing support for module-declarations, import-declarations,
and the global and private module fragment. For now, the private module fragment introducer is ignored, but use of the global module fragment introducer should be properly enforced. llvm-svn: 358353
This commit is contained in:
parent
de20429cfc
commit
d652bdd05f
|
@ -1223,15 +1223,22 @@ def err_unexpected_module_decl : Error<
|
|||
"module declaration can only appear at the top level">;
|
||||
def err_module_expected_ident : Error<
|
||||
"expected a module name after '%select{module|import}0'">;
|
||||
def err_module_implementation_partition : Error<
|
||||
"module partition must be declared 'export'">;
|
||||
def err_attribute_not_module_attr : Error<
|
||||
"%0 attribute cannot be applied to a module">;
|
||||
def err_attribute_not_import_attr : Error<
|
||||
"%0 attribute cannot be applied to a module import">;
|
||||
def err_module_expected_semi : Error<
|
||||
"expected ';' after module name">;
|
||||
def err_global_module_introducer_not_at_start : Error<
|
||||
"'module;' introducing a global module fragment can appear only "
|
||||
"at the start of the translation unit">;
|
||||
def err_module_fragment_exported : Error<
|
||||
"%select{global|private}0 module fragment cannot be exported">;
|
||||
def err_private_module_fragment_expected_semi : Error<
|
||||
"expected ';' after private module fragment declaration">;
|
||||
def err_missing_before_module_end : Error<"expected %0 at end of module">;
|
||||
def err_unsupported_module_partition : Error<
|
||||
"sorry, module partitions are not yet supported">;
|
||||
|
||||
def err_export_empty : Error<"export declaration cannot be empty">;
|
||||
}
|
||||
|
|
|
@ -9199,7 +9199,7 @@ let CategoryName = "Modules Issue" in {
|
|||
def err_module_decl_in_module_map_module : Error<
|
||||
"'module' declaration found while building module from module map">;
|
||||
def err_module_decl_in_header_module : Error<
|
||||
"'module' declaration found while building header module">;
|
||||
"'module' declaration found while building header unit">;
|
||||
def err_module_interface_implementation_mismatch : Error<
|
||||
"missing 'export' specifier in module declaration while "
|
||||
"building module interface">;
|
||||
|
@ -9217,6 +9217,9 @@ def err_module_redeclaration : Error<
|
|||
def note_prev_module_declaration : Note<"previous module declaration is here">;
|
||||
def err_module_declaration_missing : Error<
|
||||
"missing 'export module' declaration in module interface unit">;
|
||||
def err_module_declaration_missing_after_global_module_introducer : Error<
|
||||
"missing 'module' declaration at end of global module fragment "
|
||||
"introduced here">;
|
||||
def err_module_private_specialization : Error<
|
||||
"%select{template|partial|member}0 specialization cannot be "
|
||||
"declared __module_private__">;
|
||||
|
@ -9254,7 +9257,12 @@ def err_module_self_import : Error<
|
|||
def err_module_import_in_implementation : Error<
|
||||
"@import of module '%0' in implementation of '%1'; use #import">;
|
||||
|
||||
// C++ Modules TS
|
||||
// C++ Modules
|
||||
def err_module_decl_not_at_start : Error<
|
||||
"module declaration must occur at the start of the translation unit">;
|
||||
def note_global_module_introducer_missing : Note<
|
||||
"add 'module;' to the start of the file to introduce a "
|
||||
"global module fragment">;
|
||||
def err_export_within_export : Error<
|
||||
"export declaration appears within another export declaration">;
|
||||
def err_export_not_in_module_interface : Error<
|
||||
|
|
|
@ -2172,6 +2172,7 @@ private:
|
|||
None,
|
||||
ModuleBegin,
|
||||
ModuleImport,
|
||||
SkippedModuleImport,
|
||||
} Kind;
|
||||
Module *ModuleForHeader = nullptr;
|
||||
|
||||
|
|
|
@ -150,11 +150,15 @@ class Parser : public CodeCompletionHandler {
|
|||
IdentifierInfo *Ident_language, *Ident_defined_in,
|
||||
*Ident_generated_declaration;
|
||||
|
||||
/// C++0x contextual keywords.
|
||||
/// C++11 contextual keywords.
|
||||
mutable IdentifierInfo *Ident_final;
|
||||
mutable IdentifierInfo *Ident_GNU_final;
|
||||
mutable IdentifierInfo *Ident_override;
|
||||
|
||||
// C++2a contextual keywords.
|
||||
mutable IdentifierInfo *Ident_import;
|
||||
mutable IdentifierInfo *Ident_module;
|
||||
|
||||
// C++ type trait keywords that can be reverted to identifiers and still be
|
||||
// used as type traits.
|
||||
llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind> RevertibleTypeTraits;
|
||||
|
@ -424,7 +428,7 @@ public:
|
|||
|
||||
/// ParseTopLevelDecl - Parse one top-level declaration. Returns true if
|
||||
/// the EOF was encountered.
|
||||
bool ParseTopLevelDecl(DeclGroupPtrTy &Result);
|
||||
bool ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl = false);
|
||||
bool ParseTopLevelDecl() {
|
||||
DeclGroupPtrTy Result;
|
||||
return ParseTopLevelDecl(Result);
|
||||
|
@ -2996,7 +3000,7 @@ private:
|
|||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Modules
|
||||
DeclGroupPtrTy ParseModuleDecl();
|
||||
DeclGroupPtrTy ParseModuleDecl(bool IsFirstDecl);
|
||||
Decl *ParseModuleImport(SourceLocation AtLoc);
|
||||
bool parseMisplacedModuleImport();
|
||||
bool tryParseMisplacedModuleImport() {
|
||||
|
|
|
@ -1624,8 +1624,10 @@ private:
|
|||
TypeDiagnoser *Diagnoser);
|
||||
|
||||
struct ModuleScope {
|
||||
SourceLocation BeginLoc;
|
||||
clang::Module *Module = nullptr;
|
||||
bool ModuleInterface = false;
|
||||
bool ImplicitGlobalModuleFragment = false;
|
||||
VisibleModuleSet OuterVisibleModules;
|
||||
};
|
||||
/// The modules we're currently parsing.
|
||||
|
@ -2155,24 +2157,43 @@ public:
|
|||
enum class ModuleDeclKind {
|
||||
Interface, ///< 'export module X;'
|
||||
Implementation, ///< 'module X;'
|
||||
Partition, ///< 'module partition X;'
|
||||
};
|
||||
|
||||
/// The parser has processed a module-declaration that begins the definition
|
||||
/// of a module interface or implementation.
|
||||
DeclGroupPtrTy ActOnModuleDecl(SourceLocation StartLoc,
|
||||
SourceLocation ModuleLoc, ModuleDeclKind MDK,
|
||||
ModuleIdPath Path);
|
||||
ModuleIdPath Path, bool IsFirstDecl);
|
||||
|
||||
/// The parser has processed a global-module-fragment declaration that begins
|
||||
/// the definition of the global module fragment of the current module unit.
|
||||
/// \param ModuleLoc The location of the 'module' keyword.
|
||||
DeclGroupPtrTy ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc);
|
||||
|
||||
/// The parser has processed a private-module-fragment declaration that begins
|
||||
/// the definition of the private module fragment of the current module unit.
|
||||
/// \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();
|
||||
}
|
||||
|
||||
/// The parser has processed a module import declaration.
|
||||
///
|
||||
/// \param AtLoc The location of the '@' symbol, if any.
|
||||
///
|
||||
/// \param StartLoc The location of the first token in the declaration. This
|
||||
/// could be the location of an '@', 'export', or 'import'.
|
||||
/// \param ExportLoc The location of the 'export' keyword, if any.
|
||||
/// \param ImportLoc The location of the 'import' keyword.
|
||||
///
|
||||
/// \param Path The module access path.
|
||||
DeclResult ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc,
|
||||
ModuleIdPath Path);
|
||||
DeclResult ActOnModuleImport(SourceLocation StartLoc,
|
||||
SourceLocation ExportLoc,
|
||||
SourceLocation ImportLoc, ModuleIdPath Path);
|
||||
DeclResult ActOnModuleImport(SourceLocation StartLoc,
|
||||
SourceLocation ExportLoc,
|
||||
SourceLocation ImportLoc, Module *M,
|
||||
ModuleIdPath Path = {});
|
||||
|
||||
/// The parser has processed a module import translated from a
|
||||
/// #include or similar preprocessing directive.
|
||||
|
|
|
@ -1648,6 +1648,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
|
|||
EndLoc, LookupFrom, LookupFromFile);
|
||||
switch (Action.Kind) {
|
||||
case ImportAction::None:
|
||||
case ImportAction::SkippedModuleImport:
|
||||
break;
|
||||
case ImportAction::ModuleBegin:
|
||||
EnterAnnotationToken(SourceRange(HashLoc, EndLoc),
|
||||
|
@ -2034,6 +2035,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
|
|||
switch (Action) {
|
||||
case Skip:
|
||||
// If we don't need to enter the file, stop now.
|
||||
if (Module *M = SuggestedModule.getModule())
|
||||
return {ImportAction::SkippedModuleImport, M};
|
||||
return {ImportAction::None};
|
||||
|
||||
case IncludeLimitReached:
|
||||
|
@ -2117,6 +2120,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
|
|||
return {ImportAction::ModuleBegin, M};
|
||||
}
|
||||
|
||||
assert(!IsImportDecl && "failed to diagnose missing module for import decl");
|
||||
return {ImportAction::None};
|
||||
}
|
||||
|
||||
|
|
|
@ -1168,6 +1168,7 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
|
|||
LLVM_FALLTHROUGH;
|
||||
|
||||
case ImportAction::ModuleImport:
|
||||
case ImportAction::SkippedModuleImport:
|
||||
// We chose to import (or textually enter) the file. Convert the
|
||||
// header-name token into a header unit annotation token.
|
||||
Suffix[0].setKind(tok::annot_header_unit);
|
||||
|
|
|
@ -460,6 +460,8 @@ void Parser::Initialize() {
|
|||
Ident_sealed = nullptr;
|
||||
Ident_override = nullptr;
|
||||
Ident_GNU_final = nullptr;
|
||||
Ident_import = nullptr;
|
||||
Ident_module = nullptr;
|
||||
|
||||
Ident_super = &PP.getIdentifierTable().get("super");
|
||||
|
||||
|
@ -512,6 +514,11 @@ void Parser::Initialize() {
|
|||
PP.SetPoisonReason(Ident_AbnormalTermination,diag::err_seh___finally_block);
|
||||
}
|
||||
|
||||
if (getLangOpts().CPlusPlusModules) {
|
||||
Ident_import = PP.getIdentifierInfo("import");
|
||||
Ident_module = PP.getIdentifierInfo("module");
|
||||
}
|
||||
|
||||
Actions.Initialize();
|
||||
|
||||
// Prime the lexer look-ahead.
|
||||
|
@ -525,6 +532,16 @@ void Parser::LateTemplateParserCleanupCallback(void *P) {
|
|||
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(((Parser *)P)->TemplateIds);
|
||||
}
|
||||
|
||||
/// Parse the first top-level declaration in a translation unit.
|
||||
///
|
||||
/// translation-unit:
|
||||
/// [C] external-declaration
|
||||
/// [C] translation-unit external-declaration
|
||||
/// [C++] top-level-declaration-seq[opt]
|
||||
/// [C++20] global-module-fragment[opt] module-declaration
|
||||
/// top-level-declaration-seq[opt] private-module-fragment[opt]
|
||||
///
|
||||
/// Note that in C, it is an error if there is no first declaration.
|
||||
bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) {
|
||||
Actions.ActOnStartOfTranslationUnit();
|
||||
|
||||
|
@ -532,7 +549,7 @@ bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) {
|
|||
// declaration. C++ doesn't have this restriction. We also don't want to
|
||||
// complain if we have a precompiled header, although technically if the PCH
|
||||
// is empty we should still emit the (pedantic) diagnostic.
|
||||
bool NoTopLevelDecls = ParseTopLevelDecl(Result);
|
||||
bool NoTopLevelDecls = ParseTopLevelDecl(Result, true);
|
||||
if (NoTopLevelDecls && !Actions.getASTContext().getExternalSource() &&
|
||||
!getLangOpts().CPlusPlus)
|
||||
Diag(diag::ext_empty_translation_unit);
|
||||
|
@ -542,7 +559,11 @@ bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &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) {
|
||||
///
|
||||
/// top-level-declaration:
|
||||
/// declaration
|
||||
/// [C++20] module-import-declaration
|
||||
bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {
|
||||
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds);
|
||||
|
||||
// Skip over the EOF token, flagging end of previous input for incremental
|
||||
|
@ -557,13 +578,46 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
|
|||
return false;
|
||||
|
||||
case tok::kw_export:
|
||||
if (NextToken().isNot(tok::kw_module))
|
||||
switch (NextToken().getKind()) {
|
||||
case tok::kw_module:
|
||||
goto module_decl;
|
||||
|
||||
// Note: no need to handle kw_import here. We only form kw_import under
|
||||
// the Modules TS, and in that case 'export import' is parsed as an
|
||||
// export-declaration containing an import-declaration.
|
||||
|
||||
// Recognize context-sensitive C++20 'export module' and 'export import'
|
||||
// declarations.
|
||||
case tok::identifier: {
|
||||
IdentifierInfo *II = NextToken().getIdentifierInfo();
|
||||
if ((II == Ident_module || II == Ident_import) &&
|
||||
GetLookAheadToken(2).isNot(tok::coloncolon)) {
|
||||
if (II == Ident_module)
|
||||
goto module_decl;
|
||||
else
|
||||
goto import_decl;
|
||||
}
|
||||
break;
|
||||
LLVM_FALLTHROUGH;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case tok::kw_module:
|
||||
Result = ParseModuleDecl();
|
||||
module_decl:
|
||||
Result = ParseModuleDecl(IsFirstDecl);
|
||||
return false;
|
||||
|
||||
// tok::kw_import is handled by ParseExternalDeclaration. (Under the Modules
|
||||
// TS, an import can occur within an export block.)
|
||||
import_decl: {
|
||||
Decl *ImportDecl = ParseModuleImport(SourceLocation());
|
||||
Result = Actions.ConvertDeclToDeclGroup(ImportDecl);
|
||||
return false;
|
||||
}
|
||||
|
||||
case tok::annot_module_include:
|
||||
Actions.ActOnModuleInclude(Tok.getLocation(),
|
||||
reinterpret_cast<Module *>(
|
||||
|
@ -595,6 +649,21 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
|
|||
//else don't tell Sema that we ended parsing: more input might come.
|
||||
return true;
|
||||
|
||||
case tok::identifier:
|
||||
// C++2a [basic.link]p3:
|
||||
// A token sequence beginning with 'export[opt] module' or
|
||||
// 'export[opt] import' and not immediately followed by '::'
|
||||
// is never interpreted as the declaration of a top-level-declaration.
|
||||
if ((Tok.getIdentifierInfo() == Ident_module ||
|
||||
Tok.getIdentifierInfo() == Ident_import) &&
|
||||
NextToken().isNot(tok::coloncolon)) {
|
||||
if (Tok.getIdentifierInfo() == Ident_module)
|
||||
goto module_decl;
|
||||
else
|
||||
goto import_decl;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -2074,38 +2143,83 @@ 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.
|
||||
/// Parse a declaration beginning with the 'module' keyword or C++20
|
||||
/// context-sensitive keyword (optionally preceded by 'export').
|
||||
///
|
||||
/// module-declaration: [Modules TS + P0273R0 + P0629R0]
|
||||
/// 'export'[opt] 'module' 'partition'[opt]
|
||||
/// module-name attribute-specifier-seq[opt] ';'
|
||||
/// module-declaration: [Modules TS + P0629R0]
|
||||
/// 'export'[opt] 'module' module-name attribute-specifier-seq[opt] ';'
|
||||
///
|
||||
/// Note that 'partition' is a context-sensitive keyword.
|
||||
Parser::DeclGroupPtrTy Parser::ParseModuleDecl() {
|
||||
/// global-module-fragment: [C++2a]
|
||||
/// 'module' ';' top-level-declaration-seq[opt]
|
||||
/// module-declaration: [C++2a]
|
||||
/// 'export'[opt] 'module' module-name module-partition[opt]
|
||||
/// attribute-specifier-seq[opt] ';'
|
||||
/// private-module-fragment: [C++2a]
|
||||
/// 'module' ':' 'private' ';' top-level-declaration-seq[opt]
|
||||
Parser::DeclGroupPtrTy Parser::ParseModuleDecl(bool IsFirstDecl) {
|
||||
SourceLocation StartLoc = Tok.getLocation();
|
||||
|
||||
Sema::ModuleDeclKind MDK = TryConsumeToken(tok::kw_export)
|
||||
? Sema::ModuleDeclKind::Interface
|
||||
: Sema::ModuleDeclKind::Implementation;
|
||||
|
||||
assert(Tok.is(tok::kw_module) && "not a module declaration");
|
||||
assert(
|
||||
(Tok.is(tok::kw_module) ||
|
||||
(Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_module)) &&
|
||||
"not a module declaration");
|
||||
SourceLocation ModuleLoc = ConsumeToken();
|
||||
|
||||
if (Tok.is(tok::identifier) && NextToken().is(tok::identifier) &&
|
||||
Tok.getIdentifierInfo()->isStr("partition")) {
|
||||
// If 'partition' is present, this must be a module interface unit.
|
||||
if (MDK != Sema::ModuleDeclKind::Interface)
|
||||
Diag(Tok.getLocation(), diag::err_module_implementation_partition)
|
||||
<< FixItHint::CreateInsertion(ModuleLoc, "export ");
|
||||
MDK = Sema::ModuleDeclKind::Partition;
|
||||
// Attributes appear after the module name, not before.
|
||||
if (Tok.is(tok::l_square))
|
||||
CheckProhibitedCXX11Attribute();
|
||||
|
||||
// Parse a global-module-fragment, if present.
|
||||
if (getLangOpts().CPlusPlusModules && Tok.is(tok::semi)) {
|
||||
SourceLocation SemiLoc = ConsumeToken();
|
||||
if (!IsFirstDecl) {
|
||||
Diag(StartLoc, diag::err_global_module_introducer_not_at_start)
|
||||
<< SourceRange(StartLoc, SemiLoc);
|
||||
return nullptr;
|
||||
}
|
||||
if (MDK == Sema::ModuleDeclKind::Interface) {
|
||||
Diag(StartLoc, diag::err_module_fragment_exported)
|
||||
<< /*global*/0 << FixItHint::CreateRemoval(StartLoc);
|
||||
}
|
||||
return Actions.ActOnGlobalModuleFragmentDecl(ModuleLoc);
|
||||
}
|
||||
|
||||
// Parse a private-module-fragment, if present.
|
||||
if (getLangOpts().CPlusPlusModules && Tok.is(tok::colon) &&
|
||||
NextToken().is(tok::kw_private)) {
|
||||
if (MDK == Sema::ModuleDeclKind::Interface) {
|
||||
Diag(StartLoc, diag::err_module_fragment_exported)
|
||||
<< /*private*/1 << FixItHint::CreateRemoval(StartLoc);
|
||||
}
|
||||
ConsumeToken();
|
||||
SourceLocation PrivateLoc = ConsumeToken();
|
||||
if (Tok.is(tok::l_square))
|
||||
CheckProhibitedCXX11Attribute();
|
||||
ExpectAndConsumeSemi(diag::err_private_module_fragment_expected_semi);
|
||||
return Actions.ActOnPrivateModuleFragmentDecl(ModuleLoc, PrivateLoc);
|
||||
}
|
||||
|
||||
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
|
||||
if (ParseModuleName(ModuleLoc, Path, /*IsImport*/false))
|
||||
return nullptr;
|
||||
|
||||
// Parse the optional module-partition.
|
||||
if (Tok.is(tok::colon)) {
|
||||
SourceLocation ColonLoc = ConsumeToken();
|
||||
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition;
|
||||
if (ParseModuleName(ModuleLoc, Partition, /*IsImport*/false))
|
||||
return nullptr;
|
||||
|
||||
// FIXME: Support module partition declarations.
|
||||
Diag(ColonLoc, diag::err_unsupported_module_partition)
|
||||
<< SourceRange(ColonLoc, Partition.back().second);
|
||||
// Recover by parsing as a non-partition.
|
||||
}
|
||||
|
||||
// We don't support any module attributes yet; just parse them and diagnose.
|
||||
ParsedAttributesWithRange Attrs(AttrFactory);
|
||||
MaybeParseCXX11Attributes(Attrs);
|
||||
|
@ -2113,7 +2227,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl() {
|
|||
|
||||
ExpectAndConsumeSemi(diag::err_module_expected_semi);
|
||||
|
||||
return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path);
|
||||
return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, IsFirstDecl);
|
||||
}
|
||||
|
||||
/// Parse a module import declaration. This is essentially the same for
|
||||
|
@ -2124,17 +2238,50 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl() {
|
|||
/// '@' 'import' module-name ';'
|
||||
/// [ModTS] module-import-declaration:
|
||||
/// 'import' module-name attribute-specifier-seq[opt] ';'
|
||||
/// [C++2a] module-import-declaration:
|
||||
/// 'export'[opt] 'import' module-name
|
||||
/// attribute-specifier-seq[opt] ';'
|
||||
/// 'export'[opt] 'import' module-partition
|
||||
/// attribute-specifier-seq[opt] ';'
|
||||
/// 'export'[opt] 'import' header-name
|
||||
/// attribute-specifier-seq[opt] ';'
|
||||
Decl *Parser::ParseModuleImport(SourceLocation AtLoc) {
|
||||
assert((AtLoc.isInvalid() ? Tok.is(tok::kw_import)
|
||||
SourceLocation StartLoc = AtLoc.isInvalid() ? Tok.getLocation() : AtLoc;
|
||||
|
||||
SourceLocation ExportLoc;
|
||||
TryConsumeToken(tok::kw_export, ExportLoc);
|
||||
|
||||
assert((AtLoc.isInvalid() ? Tok.isOneOf(tok::kw_import, tok::identifier)
|
||||
: Tok.isObjCAtKeyword(tok::objc_import)) &&
|
||||
"Improper start to module import");
|
||||
bool IsObjCAtImport = Tok.isObjCAtKeyword(tok::objc_import);
|
||||
SourceLocation ImportLoc = ConsumeToken();
|
||||
SourceLocation StartLoc = AtLoc.isInvalid() ? ImportLoc : AtLoc;
|
||||
|
||||
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
|
||||
if (ParseModuleName(ImportLoc, Path, /*IsImport*/true))
|
||||
Module *HeaderUnit = nullptr;
|
||||
|
||||
if (Tok.is(tok::header_name)) {
|
||||
// This is a header import that the preprocessor decided we should skip
|
||||
// because it was malformed in some way. Parse and ignore it; it's already
|
||||
// been diagnosed.
|
||||
ConsumeToken();
|
||||
} else if (Tok.is(tok::annot_header_unit)) {
|
||||
// This is a header import that the preprocessor mapped to a module import.
|
||||
HeaderUnit = reinterpret_cast<Module *>(Tok.getAnnotationValue());
|
||||
ConsumeAnnotationToken();
|
||||
} else if (getLangOpts().CPlusPlusModules && Tok.is(tok::colon)) {
|
||||
SourceLocation ColonLoc = ConsumeToken();
|
||||
if (ParseModuleName(ImportLoc, Path, /*IsImport*/true))
|
||||
return nullptr;
|
||||
|
||||
// FIXME: Support module partition import.
|
||||
Diag(ColonLoc, diag::err_unsupported_module_partition)
|
||||
<< SourceRange(ColonLoc, Path.back().second);
|
||||
return nullptr;
|
||||
} else {
|
||||
if (ParseModuleName(ImportLoc, Path, /*IsImport*/true))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ParsedAttributesWithRange Attrs(AttrFactory);
|
||||
MaybeParseCXX11Attributes(Attrs);
|
||||
|
@ -2147,7 +2294,12 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
DeclResult Import = Actions.ActOnModuleImport(StartLoc, ImportLoc, Path);
|
||||
DeclResult Import;
|
||||
if (HeaderUnit)
|
||||
Import =
|
||||
Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, HeaderUnit);
|
||||
else if (!Path.empty())
|
||||
Import = Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Path);
|
||||
ExpectAndConsumeSemi(diag::err_module_expected_semi);
|
||||
if (Import.isInvalid())
|
||||
return nullptr;
|
||||
|
|
|
@ -849,24 +849,11 @@ void Sema::ActOnStartOfTranslationUnit() {
|
|||
if (getLangOpts().ModulesTS &&
|
||||
(getLangOpts().getCompilingModule() == LangOptions::CMK_ModuleInterface ||
|
||||
getLangOpts().getCompilingModule() == LangOptions::CMK_None)) {
|
||||
// We start in an implied global module fragment.
|
||||
SourceLocation StartOfTU =
|
||||
SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
|
||||
|
||||
// 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(StartOfTU);
|
||||
assert(GlobalModule && "module creation should not fail");
|
||||
|
||||
// Enter the scope of the global module.
|
||||
ModuleScopes.push_back({});
|
||||
ModuleScopes.back().Module = GlobalModule;
|
||||
VisibleModules.setVisible(GlobalModule, StartOfTU);
|
||||
|
||||
// All declarations created from now on are owned by the global module.
|
||||
auto *TU = Context.getTranslationUnitDecl();
|
||||
TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
|
||||
TU->setLocalOwningModule(GlobalModule);
|
||||
ActOnGlobalModuleFragmentDecl(StartOfTU);
|
||||
ModuleScopes.back().ImplicitGlobalModuleFragment = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -997,13 +984,24 @@ void Sema::ActOnEndOfTranslationUnit() {
|
|||
checkUndefinedButUsed(*this);
|
||||
}
|
||||
|
||||
// A global-module-fragment is only permitted within a module unit.
|
||||
bool DiagnosedMissingModuleDeclaration = false;
|
||||
if (!ModuleScopes.empty() &&
|
||||
ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment &&
|
||||
!ModuleScopes.back().ImplicitGlobalModuleFragment) {
|
||||
Diag(ModuleScopes.back().BeginLoc,
|
||||
diag::err_module_declaration_missing_after_global_module_introducer);
|
||||
DiagnosedMissingModuleDeclaration = true;
|
||||
}
|
||||
|
||||
if (TUKind == TU_Module) {
|
||||
// If we are building a module interface unit, we need to have seen the
|
||||
// module declaration by now.
|
||||
if (getLangOpts().getCompilingModule() ==
|
||||
LangOptions::CMK_ModuleInterface &&
|
||||
(ModuleScopes.empty() ||
|
||||
ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit)) {
|
||||
ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) &&
|
||||
!DiagnosedMissingModuleDeclaration) {
|
||||
// FIXME: Make a better guess as to where to put the module declaration.
|
||||
Diag(getSourceManager().getLocForStartOfFile(
|
||||
getSourceManager().getMainFileID()),
|
||||
|
|
|
@ -17016,12 +17016,44 @@ static void checkModuleImportContext(Sema &S, Module *M,
|
|||
}
|
||||
}
|
||||
|
||||
Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
|
||||
SourceLocation ModuleLoc,
|
||||
ModuleDeclKind MDK,
|
||||
ModuleIdPath Path) {
|
||||
assert(getLangOpts().ModulesTS &&
|
||||
"should only have module decl in modules TS");
|
||||
Sema::DeclGroupPtrTy
|
||||
Sema::ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc) {
|
||||
if (!ModuleScopes.empty() &&
|
||||
ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment) {
|
||||
// Under -std=c++2a -fmodules-ts, we can find an explicit 'module;' after
|
||||
// already implicitly entering the global module fragment. That's OK.
|
||||
assert(getLangOpts().CPlusPlusModules && getLangOpts().ModulesTS &&
|
||||
"unexpectedly encountered multiple global module fragment decls");
|
||||
ModuleScopes.back().BeginLoc = ModuleLoc;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 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);
|
||||
assert(GlobalModule && "module creation should not fail");
|
||||
|
||||
// Enter the scope of the global module.
|
||||
ModuleScopes.push_back({});
|
||||
ModuleScopes.back().BeginLoc = ModuleLoc;
|
||||
ModuleScopes.back().Module = GlobalModule;
|
||||
VisibleModules.setVisible(GlobalModule, ModuleLoc);
|
||||
|
||||
// All declarations created from now on are owned by the global module.
|
||||
auto *TU = Context.getTranslationUnitDecl();
|
||||
TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
|
||||
TU->setLocalOwningModule(GlobalModule);
|
||||
|
||||
// FIXME: Consider creating an explicit representation of this declaration.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Sema::DeclGroupPtrTy
|
||||
Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
|
||||
ModuleDeclKind MDK, ModuleIdPath Path, bool IsFirstDecl) {
|
||||
assert((getLangOpts().ModulesTS || getLangOpts().CPlusPlusModules) &&
|
||||
"should only have module decl in Modules TS or C++20");
|
||||
|
||||
// A module implementation unit requires that we are not compiling a module
|
||||
// of any kind. A module interface unit requires that we are not compiling a
|
||||
|
@ -17051,19 +17083,40 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
assert(ModuleScopes.size() == 1 && "expected to be at global module scope");
|
||||
assert(ModuleScopes.size() <= 1 && "expected to be at global module scope");
|
||||
|
||||
// FIXME: Most of this work should be done by the preprocessor rather than
|
||||
// here, in order to support macro import.
|
||||
|
||||
// Only one module-declaration is permitted per source file.
|
||||
if (ModuleScopes.back().Module->Kind == Module::ModuleInterfaceUnit) {
|
||||
if (!ModuleScopes.empty() &&
|
||||
ModuleScopes.back().Module->Kind == Module::ModuleInterfaceUnit) {
|
||||
Diag(ModuleLoc, diag::err_module_redeclaration);
|
||||
Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module),
|
||||
diag::note_prev_module_declaration);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Find the global module fragment we're adopting into this module, if any.
|
||||
Module *GlobalModuleFragment = nullptr;
|
||||
if (!ModuleScopes.empty() &&
|
||||
ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment)
|
||||
GlobalModuleFragment = ModuleScopes.back().Module;
|
||||
|
||||
// In C++20, the module-declaration must be the first declaration if there
|
||||
// is no global module fragment.
|
||||
if (getLangOpts().CPlusPlusModules && !IsFirstDecl && !GlobalModuleFragment) {
|
||||
Diag(ModuleLoc, diag::err_module_decl_not_at_start);
|
||||
SourceLocation BeginLoc =
|
||||
ModuleScopes.empty()
|
||||
? SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID())
|
||||
: ModuleScopes.back().BeginLoc;
|
||||
if (BeginLoc.isValid()) {
|
||||
Diag(BeginLoc, diag::note_global_module_introducer_missing)
|
||||
<< FixItHint::CreateInsertion(BeginLoc, "module;\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Flatten the dots in a module name. Unlike Clang's hierarchical module map
|
||||
// modules, the dots here are just another character that can appear in a
|
||||
// module name.
|
||||
|
@ -17105,15 +17158,11 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
|
|||
|
||||
// Create a Module for the module that we're defining.
|
||||
Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
|
||||
ModuleScopes.front().Module);
|
||||
GlobalModuleFragment);
|
||||
assert(Mod && "module creation should not fail");
|
||||
break;
|
||||
}
|
||||
|
||||
case ModuleDeclKind::Partition:
|
||||
// FIXME: Check we are in a submodule of the named module.
|
||||
return nullptr;
|
||||
|
||||
case ModuleDeclKind::Implementation:
|
||||
std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc(
|
||||
PP.getIdentifierInfo(ModuleName), Path[0].second);
|
||||
|
@ -17124,12 +17173,19 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
|
|||
Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
|
||||
// Create an empty module interface unit for error recovery.
|
||||
Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
|
||||
ModuleScopes.front().Module);
|
||||
GlobalModuleFragment);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Switch from the global module to the named module.
|
||||
if (!GlobalModuleFragment) {
|
||||
ModuleScopes.push_back({});
|
||||
if (getLangOpts().ModulesLocalVisibility)
|
||||
ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
|
||||
}
|
||||
|
||||
// Switch from the global module fragment (if any) to the named module.
|
||||
ModuleScopes.back().BeginLoc = StartLoc;
|
||||
ModuleScopes.back().Module = Mod;
|
||||
ModuleScopes.back().ModuleInterface = MDK != ModuleDeclKind::Implementation;
|
||||
VisibleModules.setVisible(Mod, ModuleLoc);
|
||||
|
@ -17146,6 +17202,7 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
|
|||
}
|
||||
|
||||
DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
|
||||
SourceLocation ExportLoc,
|
||||
SourceLocation ImportLoc,
|
||||
ModuleIdPath Path) {
|
||||
// Flatten the module path for a Modules TS module name.
|
||||
|
@ -17167,6 +17224,13 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
|
|||
if (!Mod)
|
||||
return true;
|
||||
|
||||
return ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Mod, Path);
|
||||
}
|
||||
|
||||
DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
|
||||
SourceLocation ExportLoc,
|
||||
SourceLocation ImportLoc,
|
||||
Module *Mod, ModuleIdPath Path) {
|
||||
VisibleModules.setVisible(Mod, ImportLoc);
|
||||
|
||||
checkModuleImportContext(*this, Mod, ImportLoc, CurContext);
|
||||
|
@ -17176,12 +17240,15 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
|
|||
// silently ignoring the import.
|
||||
// Import-from-implementation is valid in the Modules TS. FIXME: Should we
|
||||
// warn on a redundant import of the current module?
|
||||
// FIXME: Import of a module from an implementation partition of the same
|
||||
// module is permitted.
|
||||
if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule &&
|
||||
(getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS))
|
||||
(getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) {
|
||||
Diag(ImportLoc, getLangOpts().isCompilingModule()
|
||||
? diag::err_module_self_import
|
||||
: diag::err_module_import_in_implementation)
|
||||
<< Mod->getFullModuleName() << getLangOpts().CurrentModule;
|
||||
}
|
||||
|
||||
SmallVector<SourceLocation, 2> IdentifierLocs;
|
||||
Module *ModCheck = Mod;
|
||||
|
@ -17195,16 +17262,30 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
|
|||
IdentifierLocs.push_back(Path[I].second);
|
||||
}
|
||||
|
||||
// If this was a header import, pad out with dummy locations.
|
||||
// FIXME: Pass in and use the location of the header-name token in this case.
|
||||
if (Path.empty()) {
|
||||
for (; ModCheck; ModCheck = ModCheck->Parent) {
|
||||
IdentifierLocs.push_back(SourceLocation());
|
||||
}
|
||||
}
|
||||
|
||||
ImportDecl *Import = ImportDecl::Create(Context, CurContext, StartLoc,
|
||||
Mod, IdentifierLocs);
|
||||
if (!ModuleScopes.empty())
|
||||
Context.addModuleInitializer(ModuleScopes.back().Module, Import);
|
||||
CurContext->addDecl(Import);
|
||||
|
||||
// Sequence initialization of the imported module before that of the current
|
||||
// module, if any.
|
||||
if (!ModuleScopes.empty())
|
||||
Context.addModuleInitializer(ModuleScopes.back().Module, Import);
|
||||
|
||||
// Re-export the module if needed.
|
||||
if (Import->isExported() &&
|
||||
!ModuleScopes.empty() && ModuleScopes.back().ModuleInterface)
|
||||
getCurrentModule()->Exports.emplace_back(Mod, false);
|
||||
if (!ModuleScopes.empty() && ModuleScopes.back().ModuleInterface) {
|
||||
if (ExportLoc.isValid() || Import->isExported())
|
||||
getCurrentModule()->Exports.emplace_back(Mod, false);
|
||||
} else if (ExportLoc.isValid()) {
|
||||
Diag(ExportLoc, diag::err_export_not_in_module_interface);
|
||||
}
|
||||
|
||||
return Import;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
// 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 -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
|
||||
#ifdef EXPORT_FRAGS
|
||||
export // expected-error {{global module fragment cannot be exported}}
|
||||
#endif
|
||||
module; // #glob-frag
|
||||
#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
|
||||
|
||||
// expected-error@#a2 {{declaration of 'a' in module Foo follows declaration in the global module}}
|
||||
// expected-note@#a1 {{previous decl}}
|
||||
#endif
|
||||
|
||||
int a; // #a2
|
||||
extern int b;
|
||||
|
||||
module; // expected-error {{'module;' introducing a global module fragment can appear only at the start of the translation unit}}
|
||||
|
||||
#ifdef EXPORT_FRAGS
|
||||
export // expected-error {{private module fragment cannot be exported}}
|
||||
#endif
|
||||
module :private;
|
||||
|
||||
int b; // ok
|
|
@ -0,0 +1,53 @@
|
|||
// RUN: %clang_cc1 -std=c++2a -verify %s
|
||||
// RUN: %clang_cc1 -std=c++2a -verify %s -DIMPORT_ERROR=1
|
||||
// RUN: %clang_cc1 -std=c++2a -verify %s -DIMPORT_ERROR=2
|
||||
|
||||
module;
|
||||
|
||||
#if IMPORT_ERROR != 2
|
||||
struct import { struct inner {}; };
|
||||
#endif
|
||||
struct module { struct inner {}; };
|
||||
|
||||
constexpr int n = 123;
|
||||
|
||||
export module m; // #1
|
||||
|
||||
// Import errors are fatal, so we test them in isolation.
|
||||
#if IMPORT_ERROR == 1
|
||||
import x = {}; // expected-error {{module 'x' not found}}
|
||||
|
||||
#elif IMPORT_ERROR == 2
|
||||
struct X;
|
||||
template<int> struct import;
|
||||
template<> struct import<n> {
|
||||
static X y;
|
||||
};
|
||||
|
||||
// This is not valid because the 'import <n>' is a pp-import, even though it
|
||||
// grammatically can't possibly be an import declaration.
|
||||
struct X {} import<n>::y; // expected-error {{'n' file not found}}
|
||||
|
||||
#else
|
||||
module y = {}; // expected-error {{multiple module declarations}} expected-error 2{{}}
|
||||
// expected-note@#1 {{previous module declaration}}
|
||||
|
||||
::import x = {};
|
||||
::module y = {};
|
||||
|
||||
import::inner xi = {};
|
||||
module::inner yi = {};
|
||||
|
||||
namespace N {
|
||||
module a;
|
||||
import b;
|
||||
}
|
||||
|
||||
extern "C++" module cxxm;
|
||||
extern "C++" import cxxi;
|
||||
|
||||
template<typename T> module module_var_template;
|
||||
|
||||
// This is a variable named 'import' that shadows the type 'import' above.
|
||||
struct X {} import;
|
||||
#endif
|
|
@ -0,0 +1,4 @@
|
|||
// RUN: %clang_cc1 -std=c++2a -verify %s
|
||||
|
||||
export module foo:bar; // expected-error {{sorry, module partitions are not yet supported}}
|
||||
import :baz; // expected-error {{sorry, module partitions are not yet supported}}
|
|
@ -10,47 +10,39 @@
|
|||
//
|
||||
// Module implementation for unknown and known module. (The former is ill-formed.)
|
||||
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
|
||||
// RUN: -DTEST=1 -DEXPORT= -DPARTITION= -DMODULE_NAME=z
|
||||
// RUN: -DTEST=1 -DEXPORT= -DMODULE_NAME=z
|
||||
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
|
||||
// RUN: -DTEST=2 -DEXPORT= -DPARTITION= -DMODULE_NAME=x
|
||||
// RUN: -DTEST=2 -DEXPORT= -DMODULE_NAME=x
|
||||
//
|
||||
// Module interface for unknown and known module. (The latter is ill-formed due to
|
||||
// redefinition.)
|
||||
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
|
||||
// RUN: -DTEST=3 -DEXPORT=export -DPARTITION= -DMODULE_NAME=z
|
||||
// RUN: -DTEST=3 -DEXPORT=export -DMODULE_NAME=z
|
||||
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
|
||||
// RUN: -DTEST=4 -DEXPORT=export -DPARTITION= -DMODULE_NAME=x
|
||||
//
|
||||
// Defining a module partition.
|
||||
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
|
||||
// RUN: -DTEST=5 -DEXPORT=export -DPARTITION=partition -DMODULE_NAME=z
|
||||
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
|
||||
// RUN: -DTEST=6 -DEXPORT= -DPARTITION=partition -DMODULE_NAME=z
|
||||
// RUN: -DTEST=4 -DEXPORT=export -DMODULE_NAME=x
|
||||
//
|
||||
// Miscellaneous syntax.
|
||||
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
|
||||
// RUN: -DTEST=7 -DEXPORT= -DPARTITION=elderberry -DMODULE_NAME=z
|
||||
// RUN: -DTEST=7 -DEXPORT=export -DMODULE_NAME='z elderberry'
|
||||
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
|
||||
// RUN: -DTEST=8 -DEXPORT=export -DPARTITION= -DMODULE_NAME='z [[]]'
|
||||
// RUN: -DTEST=8 -DEXPORT=export -DMODULE_NAME='z [[]]'
|
||||
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
|
||||
// RUN: -DTEST=9 -DEXPORT=export -DPARTITION= -DMODULE_NAME='z [[fancy]]'
|
||||
// RUN: -DTEST=9 -DEXPORT=export -DMODULE_NAME='z [[fancy]]'
|
||||
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
|
||||
// RUN: -DTEST=10 -DEXPORT=export -DPARTITION= -DMODULE_NAME='z [[maybe_unused]]'
|
||||
// RUN: -DTEST=10 -DEXPORT=export -DMODULE_NAME='z [[maybe_unused]]'
|
||||
|
||||
EXPORT module PARTITION MODULE_NAME;
|
||||
EXPORT module MODULE_NAME;
|
||||
#if TEST == 4
|
||||
// expected-error@-2 {{redefinition of module 'x'}}
|
||||
// expected-note-re@module-declaration.cpp:* {{loaded from '{{.*[/\\]}}x.pcm'}}
|
||||
#elif TEST == 6
|
||||
// expected-error@-5 {{module partition must be declared 'export'}}
|
||||
#elif TEST == 7
|
||||
// expected-error@-7 {{expected ';'}} expected-error@-7 {{requires a type specifier}} expected-error@-7 {{definition of module 'elderberry' is not available}}
|
||||
// expected-error@-5 {{expected ';'}} expected-error@-5 {{requires a type specifier}}
|
||||
#elif TEST == 9
|
||||
// expected-warning@-9 {{unknown attribute 'fancy' ignored}}
|
||||
// expected-warning@-7 {{unknown attribute 'fancy' ignored}}
|
||||
#elif TEST == 10
|
||||
// expected-error-re@-11 {{'maybe_unused' attribute cannot be applied to a module{{$}}}}
|
||||
// expected-error-re@-9 {{'maybe_unused' attribute cannot be applied to a module{{$}}}}
|
||||
#elif TEST == 1
|
||||
// expected-error@-13 {{definition of module 'z' is not available}}
|
||||
// expected-error@-11 {{definition of module 'z' is not available}}
|
||||
#else
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue