[C++][Modules] A module directive may only appear as the first preprocessing tokens in a file (#144233)
This PR is 2nd part of [P1857R3](https://github.com/llvm/llvm-project/pull/107168) implementation, and mainly implement the restriction `A module directive may only appear as the first preprocessing tokens in a file (excluding the global module fragment.)`: [cpp.pre](https://eel.is/c++draft/cpp.pre): ``` module-file: pp-global-module-fragment[opt] pp-module group[opt] pp-private-module-fragment[opt] ``` We also refine tests use `split-file` instead of conditional macro. Signed-off-by: yronglin <yronglin777@gmail.com>
This commit is contained in:
parent
1b5d6ec685
commit
ea321392eb
@ -143,6 +143,9 @@ class Lexer : public PreprocessorLexer {
|
||||
/// True if this is the first time we're lexing the input file.
|
||||
bool IsFirstTimeLexingFile;
|
||||
|
||||
/// True if current lexing token is the first pp-token.
|
||||
bool IsFirstPPToken;
|
||||
|
||||
// NewLinePtr - A pointer to new line character '\n' being lexed. For '\r\n',
|
||||
// it also points to '\n.'
|
||||
const char *NewLinePtr;
|
||||
|
||||
@ -350,6 +350,9 @@ private:
|
||||
/// Whether the last token we lexed was an '@'.
|
||||
bool LastTokenWasAt = false;
|
||||
|
||||
/// First pp-token in current translation unit.
|
||||
std::optional<Token> FirstPPToken;
|
||||
|
||||
/// A position within a C++20 import-seq.
|
||||
class StdCXXImportSeq {
|
||||
public:
|
||||
@ -1766,6 +1769,20 @@ public:
|
||||
std::optional<LexEmbedParametersResult> LexEmbedParameters(Token &Current,
|
||||
bool ForHasEmbed);
|
||||
|
||||
/// Whether the preprocessor already seen the first pp-token in main file.
|
||||
bool hasSeenMainFileFirstPPToken() const { return FirstPPToken.has_value(); }
|
||||
|
||||
/// Record first pp-token and check if it has a Token::FirstPPToken flag.
|
||||
void HandleMainFileFirstPPToken(const Token &Tok) {
|
||||
if (!hasSeenMainFileFirstPPToken() && Tok.isFirstPPToken() &&
|
||||
SourceMgr.isWrittenInMainFile(Tok.getLocation()))
|
||||
FirstPPToken = Tok;
|
||||
}
|
||||
|
||||
Token getMainFileFirstPPToken() const {
|
||||
assert(FirstPPToken && "First main file pp-token doesn't exists");
|
||||
return *FirstPPToken;
|
||||
}
|
||||
bool LexAfterModuleImport(Token &Result);
|
||||
void CollectPpImportSuffix(SmallVectorImpl<Token> &Toks);
|
||||
|
||||
|
||||
@ -86,9 +86,12 @@ public:
|
||||
// macro stringizing or charizing operator.
|
||||
CommaAfterElided = 0x200, // The comma following this token was elided (MS).
|
||||
IsEditorPlaceholder = 0x400, // This identifier is a placeholder.
|
||||
IsReinjected = 0x800, // A phase 4 token that was produced before and
|
||||
// re-added, e.g. via EnterTokenStream. Annotation
|
||||
// tokens are *not* reinjected.
|
||||
|
||||
IsReinjected = 0x800, // A phase 4 token that was produced before and
|
||||
// re-added, e.g. via EnterTokenStream. Annotation
|
||||
// tokens are *not* reinjected.
|
||||
FirstPPToken = 0x1000, // This token is the first pp token in the
|
||||
// translation unit.
|
||||
};
|
||||
|
||||
tok::TokenKind getKind() const { return Kind; }
|
||||
@ -318,6 +321,9 @@ public:
|
||||
/// represented as characters between '<#' and '#>' in the source code. The
|
||||
/// lexer uses identifier tokens to represent placeholders.
|
||||
bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); }
|
||||
|
||||
/// Returns true if this token is the first pp-token.
|
||||
bool isFirstPPToken() const { return getFlag(FirstPPToken); }
|
||||
};
|
||||
|
||||
/// Information about the conditional stack (\#if directives)
|
||||
|
||||
@ -9822,7 +9822,8 @@ public:
|
||||
DeclGroupPtrTy ActOnModuleDecl(SourceLocation StartLoc,
|
||||
SourceLocation ModuleLoc, ModuleDeclKind MDK,
|
||||
ModuleIdPath Path, ModuleIdPath Partition,
|
||||
ModuleImportState &ImportState);
|
||||
ModuleImportState &ImportState,
|
||||
bool IntroducerIsFirstPPToken);
|
||||
|
||||
/// The parser has processed a global-module-fragment declaration that begins
|
||||
/// the definition of the global module fragment of the current module unit.
|
||||
|
||||
@ -174,6 +174,8 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
|
||||
ExtendedTokenMode = 0;
|
||||
|
||||
NewLinePtr = nullptr;
|
||||
|
||||
IsFirstPPToken = true;
|
||||
}
|
||||
|
||||
/// Lexer constructor - Create a new lexer object for the specified buffer
|
||||
@ -3725,6 +3727,11 @@ bool Lexer::Lex(Token &Result) {
|
||||
HasLeadingEmptyMacro = false;
|
||||
}
|
||||
|
||||
if (IsFirstPPToken) {
|
||||
Result.setFlag(Token::FirstPPToken);
|
||||
IsFirstPPToken = false;
|
||||
}
|
||||
|
||||
bool atPhysicalStartOfLine = IsAtPhysicalStartOfLine;
|
||||
IsAtPhysicalStartOfLine = false;
|
||||
bool isRawLex = isLexingRawMode();
|
||||
@ -3732,6 +3739,10 @@ bool Lexer::Lex(Token &Result) {
|
||||
bool returnedToken = LexTokenInternal(Result, atPhysicalStartOfLine);
|
||||
// (After the LexTokenInternal call, the lexer might be destroyed.)
|
||||
assert((returnedToken || !isRawLex) && "Raw lex must succeed");
|
||||
|
||||
if (returnedToken && Result.isFirstPPToken() && PP &&
|
||||
!PP->hasSeenMainFileFirstPPToken())
|
||||
PP->HandleMainFileFirstPPToken(Result);
|
||||
return returnedToken;
|
||||
}
|
||||
|
||||
@ -4535,6 +4546,8 @@ const char *Lexer::convertDependencyDirectiveToken(
|
||||
Result.setFlag((Token::TokenFlags)DDTok.Flags);
|
||||
Result.setLength(DDTok.Length);
|
||||
BufferPtr = TokPtr + DDTok.Length;
|
||||
if (PP && !PP->hasSeenMainFileFirstPPToken() && Result.isFirstPPToken())
|
||||
PP->HandleMainFileFirstPPToken(Result);
|
||||
return TokPtr;
|
||||
}
|
||||
|
||||
|
||||
@ -1242,6 +1242,9 @@ void Preprocessor::HandleDirective(Token &Result) {
|
||||
// pp-directive.
|
||||
bool ReadAnyTokensBeforeDirective =CurPPLexer->MIOpt.getHasReadAnyTokensVal();
|
||||
|
||||
if (!hasSeenMainFileFirstPPToken())
|
||||
HandleMainFileFirstPPToken(Result);
|
||||
|
||||
// Save the '#' token in case we need to return it later.
|
||||
Token SavedHash = Result;
|
||||
|
||||
|
||||
@ -469,6 +469,9 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
|
||||
// to disable the optimization in this case.
|
||||
if (CurPPLexer) CurPPLexer->MIOpt.ExpandedMacro();
|
||||
|
||||
if (!hasSeenMainFileFirstPPToken())
|
||||
HandleMainFileFirstPPToken(Identifier);
|
||||
|
||||
// If this is a builtin macro, like __LINE__ or _Pragma, handle it specially.
|
||||
if (MI->isBuiltinMacro()) {
|
||||
if (Callbacks)
|
||||
|
||||
@ -247,6 +247,8 @@ void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const {
|
||||
llvm::errs() << " [LeadingSpace]";
|
||||
if (Tok.isExpandDisabled())
|
||||
llvm::errs() << " [ExpandDisabled]";
|
||||
if (Tok.isFirstPPToken())
|
||||
llvm::errs() << " [First pp-token]";
|
||||
if (Tok.needsCleaning()) {
|
||||
const char *Start = SourceMgr.getCharacterData(Tok.getLocation());
|
||||
llvm::errs() << " [UnClean='" << StringRef(Start, Tok.getLength())
|
||||
|
||||
@ -2340,7 +2340,8 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
|
||||
|
||||
Parser::DeclGroupPtrTy
|
||||
Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) {
|
||||
SourceLocation StartLoc = Tok.getLocation();
|
||||
Token Introducer = Tok;
|
||||
SourceLocation StartLoc = Introducer.getLocation();
|
||||
|
||||
Sema::ModuleDeclKind MDK = TryConsumeToken(tok::kw_export)
|
||||
? Sema::ModuleDeclKind::Interface
|
||||
@ -2359,7 +2360,7 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) {
|
||||
// Parse a global-module-fragment, if present.
|
||||
if (getLangOpts().CPlusPlusModules && Tok.is(tok::semi)) {
|
||||
SourceLocation SemiLoc = ConsumeToken();
|
||||
if (ImportState != Sema::ModuleImportState::FirstDecl) {
|
||||
if (!Introducer.isFirstPPToken()) {
|
||||
Diag(StartLoc, diag::err_global_module_introducer_not_at_start)
|
||||
<< SourceRange(StartLoc, SemiLoc);
|
||||
return nullptr;
|
||||
@ -2416,7 +2417,7 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) {
|
||||
ExpectAndConsumeSemi(diag::err_module_expected_semi);
|
||||
|
||||
return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, Partition,
|
||||
ImportState);
|
||||
ImportState, Introducer.isFirstPPToken());
|
||||
}
|
||||
|
||||
Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
|
||||
|
||||
@ -263,11 +263,11 @@ static bool DiagReservedModuleName(Sema &S, const IdentifierInfo *II,
|
||||
Sema::DeclGroupPtrTy
|
||||
Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
|
||||
ModuleDeclKind MDK, ModuleIdPath Path,
|
||||
ModuleIdPath Partition, ModuleImportState &ImportState) {
|
||||
ModuleIdPath Partition, ModuleImportState &ImportState,
|
||||
bool IntroducerIsFirstPPToken) {
|
||||
assert(getLangOpts().CPlusPlusModules &&
|
||||
"should only have module decl in standard C++ modules");
|
||||
|
||||
bool IsFirstDecl = ImportState == ModuleImportState::FirstDecl;
|
||||
bool SeenGMF = ImportState == ModuleImportState::GlobalFragment;
|
||||
// If any of the steps here fail, we count that as invalidating C++20
|
||||
// module state;
|
||||
@ -333,14 +333,11 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
|
||||
SeenGMF == (bool)this->TheGlobalModuleFragment) &&
|
||||
"mismatched global module state");
|
||||
|
||||
// In C++20, the module-declaration must be the first declaration if there
|
||||
// is no global module fragment.
|
||||
if (getLangOpts().CPlusPlusModules && !IsFirstDecl && !SeenGMF) {
|
||||
// In C++20, A module directive may only appear as the first preprocessing
|
||||
// tokens in a file (excluding the global module fragment.).
|
||||
if (getLangOpts().CPlusPlusModules && !IntroducerIsFirstPPToken && !SeenGMF) {
|
||||
Diag(ModuleLoc, diag::err_module_decl_not_at_start);
|
||||
SourceLocation BeginLoc =
|
||||
ModuleScopes.empty()
|
||||
? SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID())
|
||||
: ModuleScopes.back().BeginLoc;
|
||||
SourceLocation BeginLoc = PP.getMainFileFirstPPToken().getLocation();
|
||||
if (BeginLoc.isValid()) {
|
||||
Diag(BeginLoc, diag::note_global_module_introducer_missing)
|
||||
<< FixItHint::CreateInsertion(BeginLoc, "module;\n");
|
||||
|
||||
@ -1,57 +1,128 @@
|
||||
// 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
|
||||
// RUN: rm -rf %t
|
||||
// RUN: split-file %s %t
|
||||
|
||||
#ifndef NO_GLOBAL_FRAG
|
||||
#ifdef EXPORT_FRAGS
|
||||
export // expected-error {{global module fragment cannot be exported}}
|
||||
#endif
|
||||
// RUN: %clang_cc1 -std=c++2a -verify %t/M.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a -verify %t/NoGlobalFrag.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a -verify %t/NoModuleDecl.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a -verify %t/NoPrivateFrag.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a -verify %t/NoModuleDeclAndNoPrivateFrag.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a -verify %t/NoGlobalFragAndNoPrivateFrag.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a -verify %t/NoGlobalFragAndNoModuleDecl.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a -verify %t/NoGlobalFragAndNoModuleDeclAndNoPrivateFrag.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a -verify %t/ExportFrags.cppm
|
||||
|
||||
//--- M.cppm
|
||||
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
|
||||
export module Foo;
|
||||
|
||||
int a; // expected-error {{declaration of 'a' in module Foo follows declaration in the global module}}
|
||||
// expected-note@#a1 {{previous decl}}
|
||||
extern int b;
|
||||
|
||||
module; // expected-error {{'module;' introducing a global module fragment can appear only at the start of the translation unit}}
|
||||
module :private; // #priv-frag
|
||||
int b; // ok
|
||||
module :private; // expected-error {{private module fragment redefined}}
|
||||
// expected-note@#priv-frag {{previous definition is here}}
|
||||
|
||||
//--- NoGlobalFrag.cppm
|
||||
|
||||
extern int a; // #a1
|
||||
|
||||
#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
|
||||
export module Foo; // expected-error {{module declaration must occur at the start of the translation unit}}
|
||||
// expected-note@-2 {{add 'module;' to the start of the file to introduce a global module fragment}}
|
||||
|
||||
// expected-error@#a2 {{declaration of 'a' in module Foo follows declaration in the global module}}
|
||||
// expected-note@#a1 {{previous decl}}
|
||||
|
||||
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}}
|
||||
module :private; // #priv-frag
|
||||
int b; // ok
|
||||
module :private; // expected-error {{private module fragment redefined}}
|
||||
// expected-note@#priv-frag {{previous definition is here}}
|
||||
|
||||
//--- NoModuleDecl.cppm
|
||||
module; // expected-error {{missing 'module' declaration at end of global module fragment introduced here}}
|
||||
extern int a; // #a1
|
||||
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}}
|
||||
module :private; // expected-error {{private module fragment declaration with no preceding module declaration}}
|
||||
int b; // ok
|
||||
|
||||
//--- NoPrivateFrag.cppm
|
||||
module;
|
||||
extern int a; // #a1
|
||||
export module Foo;
|
||||
|
||||
// expected-error@#a2 {{declaration of 'a' in module Foo follows declaration in the global module}}
|
||||
// expected-note@#a1 {{previous decl}}
|
||||
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}}
|
||||
int b; // ok
|
||||
|
||||
|
||||
//--- NoModuleDeclAndNoPrivateFrag.cppm
|
||||
module; // expected-error {{missing 'module' declaration at end of global module fragment introduced here}}
|
||||
extern int a; // #a1
|
||||
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}}
|
||||
|
||||
int b; // ok
|
||||
|
||||
//--- NoGlobalFragAndNoPrivateFrag.cppm
|
||||
extern int a; // #a1
|
||||
export module Foo; // expected-error {{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}}
|
||||
|
||||
// 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}}
|
||||
|
||||
#ifndef NO_PRIVATE_FRAG
|
||||
#ifdef EXPORT_FRAGS
|
||||
export // expected-error {{private module fragment cannot be exported}}
|
||||
#endif
|
||||
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
|
||||
|
||||
//--- NoGlobalFragAndNoModuleDecl.cppm
|
||||
extern int a; // #a1
|
||||
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}}
|
||||
module :private; // #priv-frag
|
||||
// expected-error@-1 {{private module fragment declaration with no preceding module declaration}}
|
||||
int b; // ok
|
||||
|
||||
|
||||
#ifndef NO_PRIVATE_FRAG
|
||||
#ifndef NO_MODULE_DECL
|
||||
//--- NoGlobalFragAndNoModuleDeclAndNoPrivateFrag.cppm
|
||||
extern int a; // #a1
|
||||
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}}
|
||||
int b; // ok
|
||||
|
||||
//--- ExportFrags.cppm
|
||||
export module; // expected-error {{global module fragment cannot be exported}}
|
||||
extern int a; // #a1
|
||||
export module Foo;
|
||||
// expected-error@#a2 {{declaration of 'a' in module Foo follows declaration in the global module}}
|
||||
// expected-note@#a1 {{previous decl}}
|
||||
|
||||
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}}
|
||||
|
||||
module :private; // #priv-frag
|
||||
|
||||
int b; // ok
|
||||
module :private; // expected-error {{private module fragment redefined}}
|
||||
// expected-note@#priv-frag {{previous definition is here}}
|
||||
#endif
|
||||
#endif
|
||||
// expected-note@#priv-frag {{previous definition is here}}
|
||||
|
||||
@ -1,16 +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=M=%t.pcm
|
||||
// RUN: rm -rf %t
|
||||
// RUN: split-file %s %t
|
||||
|
||||
#ifdef EXPORT
|
||||
// RUN: %clang_cc1 -std=c++2a %t/pmf_in_interface.cpp -verify
|
||||
// RUN: %clang_cc1 -std=c++2a %t/pmf_in_interface.cpp -emit-module-interface -o %t.pcm
|
||||
// RUN: %clang_cc1 -std=c++2a %t/pmf_in_implementation.cpp -verify -fmodule-file=M=%t.pcm
|
||||
|
||||
|
||||
//--- pmf_in_interface.cpp
|
||||
// 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
|
||||
export module M;
|
||||
module :private;
|
||||
|
||||
//--- pmf_in_implementation.cpp
|
||||
module M; // expected-note {{add 'export' here}}
|
||||
module :private; // expected-error {{private module fragment in module implementation unit}}
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: mkdir -p %t
|
||||
// RUN: echo '#ifndef FOO_H' > %t/foo.h
|
||||
// RUN: echo '#define FOO_H' >> %t/foo.h
|
||||
// RUN: echo 'extern int in_header;' >> %t/foo.h
|
||||
// RUN: echo '#endif' >> %t/foo.h
|
||||
// RUN: %clang_cc1 -std=c++2a -I%t -emit-module-interface -DINTERFACE %s -o %t.pcm
|
||||
// RUN: %clang_cc1 -std=c++2a -I%t -fmodule-file=A=%t.pcm -DIMPLEMENTATION %s -verify -fno-modules-error-recovery
|
||||
// RUN: %clang_cc1 -std=c++2a -I%t -fmodule-file=A=%t.pcm %s -verify -fno-modules-error-recovery
|
||||
// RUN: split-file %s %t
|
||||
// RUN: %clang_cc1 -std=c++2a -I%t -emit-module-interface %t/interface.cppm -o %t.pcm
|
||||
// RUN: %clang_cc1 -std=c++2a -I%t -fmodule-file=A=%t.pcm %t/implA.cppm -verify -fno-modules-error-recovery
|
||||
// RUN: %clang_cc1 -std=c++2a -I%t -fmodule-file=A=%t.pcm %t/implB.cppm -verify -fno-modules-error-recovery
|
||||
|
||||
#ifdef INTERFACE
|
||||
//--- foo.h
|
||||
#ifndef FOO_H
|
||||
#define FOO_H
|
||||
extern int in_header;
|
||||
#endif
|
||||
|
||||
//--- interface.cppm
|
||||
module;
|
||||
#include "foo.h"
|
||||
// FIXME: The following need to be moved to a header file. The global module
|
||||
@ -22,11 +24,9 @@ static int internal;
|
||||
module :private;
|
||||
int not_exported_private;
|
||||
static int internal_private;
|
||||
#else
|
||||
|
||||
#ifdef IMPLEMENTATION
|
||||
//--- implA.cppm
|
||||
module;
|
||||
#endif
|
||||
|
||||
void test_early() {
|
||||
in_header = 1; // expected-error {{use of undeclared identifier 'in_header'}}
|
||||
@ -46,11 +46,7 @@ void test_early() {
|
||||
internal_private = 1; // expected-error {{undeclared identifier}}
|
||||
}
|
||||
|
||||
#ifdef IMPLEMENTATION
|
||||
module A;
|
||||
#else
|
||||
import A;
|
||||
#endif
|
||||
|
||||
void test_late() {
|
||||
in_header = 1; // expected-error {{missing '#include "foo.h"'; 'in_header' must be declared before it is used}}
|
||||
@ -61,20 +57,54 @@ void test_late() {
|
||||
exported = 1;
|
||||
|
||||
not_exported = 1;
|
||||
#ifndef IMPLEMENTATION
|
||||
// expected-error@-2 {{use of undeclared identifier 'not_exported'; did you mean 'exported'?}}
|
||||
// expected-note@p2.cpp:18 {{'exported' declared here}}
|
||||
#endif
|
||||
|
||||
internal = 1; // expected-error {{use of undeclared identifier 'internal'}}
|
||||
|
||||
not_exported_private = 1;
|
||||
#ifndef IMPLEMENTATION
|
||||
// FIXME: should not be visible here
|
||||
// expected-error@-3 {{undeclared identifier}}
|
||||
#endif
|
||||
|
||||
internal_private = 1; // expected-error {{use of undeclared identifier 'internal_private'}}
|
||||
}
|
||||
|
||||
#endif
|
||||
//--- implB.cppm
|
||||
module;
|
||||
|
||||
void test_early() {
|
||||
in_header = 1; // expected-error {{use of undeclared identifier 'in_header'}}
|
||||
// expected-note@* {{not visible}}
|
||||
|
||||
global_module_fragment = 1; // expected-error {{use of undeclared identifier 'global_module_fragment'}}
|
||||
|
||||
exported = 1; // expected-error {{use of undeclared identifier 'exported'}}
|
||||
|
||||
not_exported = 1; // expected-error {{use of undeclared identifier 'not_exported'}}
|
||||
|
||||
// FIXME: We need better diagnostic message for static variable.
|
||||
internal = 1; // expected-error {{use of undeclared identifier 'internal'}}
|
||||
|
||||
not_exported_private = 1; // expected-error {{undeclared identifier}}
|
||||
|
||||
internal_private = 1; // expected-error {{undeclared identifier}}
|
||||
}
|
||||
|
||||
export module B;
|
||||
import A;
|
||||
|
||||
void test_late() {
|
||||
in_header = 1; // expected-error {{missing '#include "foo.h"'; 'in_header' must be declared before it is used}}
|
||||
// expected-note@* {{not visible}}
|
||||
|
||||
global_module_fragment = 1; // expected-error {{missing '#include'; 'global_module_fragment' must be declared before it is used}}
|
||||
|
||||
exported = 1;
|
||||
|
||||
not_exported = 1; // expected-error {{use of undeclared identifier 'not_exported'; did you mean 'exported'?}}
|
||||
// expected-note@* {{'exported' declared here}}
|
||||
|
||||
internal = 1; // expected-error {{use of undeclared identifier 'internal'}}
|
||||
|
||||
not_exported_private = 1;
|
||||
// FIXME: should not be visible here
|
||||
// expected-error@-2 {{undeclared identifier}}
|
||||
|
||||
internal_private = 1; // expected-error {{use of undeclared identifier 'internal_private'}}
|
||||
}
|
||||
@ -3,29 +3,28 @@
|
||||
// RUN: split-file %s %t
|
||||
//
|
||||
// RUN: %clang_cc1 -std=c++20 -verify %t/global-vs-module.cppm
|
||||
// RUN: %clang_cc1 -std=c++20 -verify %t/global-vs-module.cppm -DEXPORT
|
||||
// RUN: %clang_cc1 -std=c++20 -verify %t/global-vs-module.cppm -DUSING
|
||||
// RUN: %clang_cc1 -std=c++20 -verify %t/global-vs-module-export.cppm
|
||||
// RUN: %clang_cc1 -std=c++20 -verify %t/global-vs-module-using.cppm
|
||||
//
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/global-vs-module.cppm -o %t/M.pcm -DNO_GLOBAL -DEXPORT
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/M.cppm -o %t/M.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 -verify %t/module-vs-global.cpp -fmodule-file=M=%t/M.pcm
|
||||
//
|
||||
// Some of the following tests intentionally have no -verify in their RUN
|
||||
// lines; we are testing that those cases do not produce errors.
|
||||
//
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -DMODULE_INTERFACE -verify
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -DMODULE_INTERFACE -DNO_IMPORT
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-interface.cpp -fmodule-file=M=%t/M.pcm -verify
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-interface.cpp -fmodule-file=M=%t/M.pcm -DNO_IMPORT
|
||||
//
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -emit-module-interface -o %t/N.pcm -DMODULE_INTERFACE -DNO_ERRORS
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N.pcm -verify
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-interface.cpp -fmodule-file=M=%t/M.pcm -emit-module-interface -o %t/N.pcm -DNO_ERRORS
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-impl.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N.pcm -verify
|
||||
//
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N.pcm -DNO_IMPORT -verify
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-impl.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N.pcm -DNO_IMPORT -verify
|
||||
//
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -emit-module-interface -o %t/N-no-M.pcm -DMODULE_INTERFACE -DNO_ERRORS -DNO_IMPORT
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N-no-M.pcm -verify
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=N=%t/N-no-M.pcm -DNO_IMPORT
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-interface.cpp -fmodule-file=M=%t/M.pcm -emit-module-interface -o %t/N-no-M.pcm -DNO_ERRORS -DNO_IMPORT
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-impl.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N-no-M.pcm -verify
|
||||
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module-impl.cpp -fmodule-file=N=%t/N-no-M.pcm -DNO_IMPORT
|
||||
|
||||
//--- global-vs-module.cppm
|
||||
#ifndef NO_GLOBAL
|
||||
module;
|
||||
extern int var; // expected-note {{previous declaration is here}}
|
||||
int func(); // expected-note {{previous declaration is here}}
|
||||
@ -40,25 +39,9 @@ template<typename> using type_tpl = int; // expected-note {{previous declaration
|
||||
typedef int type;
|
||||
namespace ns { using ::func; }
|
||||
namespace ns_alias = ns;
|
||||
#endif
|
||||
|
||||
export module M;
|
||||
|
||||
#ifdef USING
|
||||
using ::var;
|
||||
using ::func;
|
||||
using ::str;
|
||||
using ::type;
|
||||
using ::var_tpl;
|
||||
using ::func_tpl;
|
||||
using ::str_tpl;
|
||||
using ::type_tpl;
|
||||
#endif
|
||||
|
||||
#ifdef EXPORT
|
||||
export {
|
||||
#endif
|
||||
|
||||
extern int var; // expected-error {{declaration of 'var' in module M follows declaration in the global module}}
|
||||
int func(); // expected-error {{declaration of 'func' in module M follows declaration in the global module}}
|
||||
struct str; // expected-error {{declaration of 'str' in module M follows declaration in the global module}}
|
||||
@ -73,51 +56,162 @@ typedef int type;
|
||||
namespace ns { using ::func; }
|
||||
namespace ns_alias = ns;
|
||||
|
||||
#ifdef EXPORT
|
||||
}
|
||||
#endif
|
||||
|
||||
//--- module-vs-global.cpp
|
||||
import M;
|
||||
|
||||
extern int var; // expected-error {{declaration of 'var' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:35 {{previous}}
|
||||
int func(); // expected-error {{declaration of 'func' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:36 {{previous}}
|
||||
struct str; // expected-error {{declaration of 'str' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:37 {{previous}}
|
||||
//--- global-vs-module-export.cppm
|
||||
module;
|
||||
extern int var; // expected-note {{previous declaration is here}}
|
||||
int func(); // expected-note {{previous declaration is here}}
|
||||
struct str; // expected-note {{previous declaration is here}}
|
||||
using type = int;
|
||||
|
||||
template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:40 {{previous}}
|
||||
template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:41 {{previous}}
|
||||
template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:42 {{previous}}
|
||||
template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cppm:43 {{previous}}
|
||||
template<typename> extern int var_tpl; // expected-note {{previous declaration is here}}
|
||||
template<typename> int func_tpl(); // expected-note {{previous declaration is here}}
|
||||
template<typename> struct str_tpl; // expected-note {{previous declaration is here}}
|
||||
template<typename> using type_tpl = int; // expected-note {{previous declaration is here}}
|
||||
|
||||
typedef int type;
|
||||
namespace ns { using ::func; }
|
||||
namespace ns_alias = ns;
|
||||
|
||||
export module M;
|
||||
|
||||
export {
|
||||
extern int var; // expected-error {{declaration of 'var' in module M follows declaration in the global module}}
|
||||
int func(); // expected-error {{declaration of 'func' in module M follows declaration in the global module}}
|
||||
struct str; // expected-error {{declaration of 'str' in module M follows declaration in the global module}}
|
||||
using type = int;
|
||||
|
||||
template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module M follows declaration in the global module}}
|
||||
template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in module M follows declaration in the global module}}
|
||||
template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in module M follows declaration in the global module}}
|
||||
template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module M follows declaration in the global module}}
|
||||
|
||||
typedef int type;
|
||||
namespace ns { using ::func; }
|
||||
namespace ns_alias = ns;
|
||||
}
|
||||
|
||||
//--- global-vs-module-using.cppm
|
||||
module;
|
||||
extern int var; // expected-note {{previous declaration is here}}
|
||||
int func(); // expected-note {{previous declaration is here}}
|
||||
struct str; // expected-note {{previous declaration is here}}
|
||||
using type = int;
|
||||
|
||||
template<typename> extern int var_tpl; // expected-note {{previous declaration is here}}
|
||||
template<typename> int func_tpl(); // expected-note {{previous declaration is here}}
|
||||
template<typename> struct str_tpl; // expected-note {{previous declaration is here}}
|
||||
template<typename> using type_tpl = int; // expected-note {{previous declaration is here}}
|
||||
|
||||
typedef int type;
|
||||
namespace ns { using ::func; }
|
||||
namespace ns_alias = ns;
|
||||
|
||||
export module M;
|
||||
|
||||
using ::var;
|
||||
using ::func;
|
||||
using ::str;
|
||||
using ::type;
|
||||
using ::var_tpl;
|
||||
using ::func_tpl;
|
||||
using ::str_tpl;
|
||||
using ::type_tpl;
|
||||
|
||||
extern int var; // expected-error {{declaration of 'var' in module M follows declaration in the global module}}
|
||||
int func(); // expected-error {{declaration of 'func' in module M follows declaration in the global module}}
|
||||
struct str; // expected-error {{declaration of 'str' in module M follows declaration in the global module}}
|
||||
using type = int;
|
||||
|
||||
template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module M follows declaration in the global module}}
|
||||
template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in module M follows declaration in the global module}}
|
||||
template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in module M follows declaration in the global module}}
|
||||
template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module M follows declaration in the global module}}
|
||||
|
||||
typedef int type;
|
||||
namespace ns { using ::func; }
|
||||
namespace ns_alias = ns;
|
||||
|
||||
//--- M.cppm
|
||||
export module M;
|
||||
|
||||
export {
|
||||
extern int var; // expected-error {{declaration of 'var' in module M follows declaration in the global module}}
|
||||
int func(); // expected-error {{declaration of 'func' in module M follows declaration in the global module}}
|
||||
struct str; // expected-error {{declaration of 'str' in module M follows declaration in the global module}}
|
||||
using type = int;
|
||||
|
||||
template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module M follows declaration in the global module}}
|
||||
template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in module M follows declaration in the global module}}
|
||||
template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in module M follows declaration in the global module}}
|
||||
template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module M follows declaration in the global module}}
|
||||
|
||||
typedef int type;
|
||||
namespace ns { using ::func; }
|
||||
namespace ns_alias = ns;
|
||||
}
|
||||
|
||||
//--- module-vs-global.cpp
|
||||
module;
|
||||
import M;
|
||||
|
||||
extern int var; // expected-error {{declaration of 'var' in the global module follows declaration in module M}} expected-note@M.cppm:4 {{previous}}
|
||||
int func(); // expected-error {{declaration of 'func' in the global module follows declaration in module M}} expected-note@M.cppm:5 {{previous}}
|
||||
struct str; // expected-error {{declaration of 'str' in the global module follows declaration in module M}} expected-note@M.cppm:6 {{previous}}
|
||||
using type = int;
|
||||
|
||||
template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in the global module follows declaration in module M}} expected-note@M.cppm:9 {{previous}}
|
||||
template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in the global module follows declaration in module M}} expected-note@M.cppm:10 {{previous}}
|
||||
template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in the global module follows declaration in module M}} expected-note@M.cppm:11 {{previous}}
|
||||
template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in the global module follows declaration in module M}} expected-note@M.cppm:12 {{previous}}
|
||||
|
||||
typedef int type;
|
||||
namespace ns { using ::func; }
|
||||
namespace ns_alias = ns;
|
||||
|
||||
//--- module-vs-module.cpp
|
||||
#ifdef MODULE_INTERFACE
|
||||
export module N;
|
||||
#else
|
||||
module N;
|
||||
#endif
|
||||
|
||||
//--- module-vs-module-interface.cpp
|
||||
export module N;
|
||||
|
||||
#ifndef NO_IMPORT
|
||||
import M;
|
||||
#endif
|
||||
|
||||
#ifndef NO_ERRORS
|
||||
extern int var; // expected-error {{declaration of 'var' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:35 {{previous}}
|
||||
int func(); // expected-error {{declaration of 'func' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:36 {{previous}}
|
||||
struct str; // expected-error {{declaration of 'str' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:37 {{previous}}
|
||||
extern int var; // expected-error {{declaration of 'var' in module N follows declaration in module M}} expected-note@M.cppm:4 {{previous}}
|
||||
int func(); // expected-error {{declaration of 'func' in module N follows declaration in module M}} expected-note@M.cppm:5 {{previous}}
|
||||
struct str; // expected-error {{declaration of 'str' in module N follows declaration in module M}} expected-note@M.cppm:6 {{previous}}
|
||||
using type = int;
|
||||
|
||||
template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:40 {{previous}}
|
||||
template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:41 {{previous}}
|
||||
template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:42 {{previous}}
|
||||
template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cppm:43 {{previous}}
|
||||
template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module N follows declaration in module M}} expected-note@M.cppm:9 {{previous}}
|
||||
template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in module N follows declaration in module M}} expected-note@M.cppm:10 {{previous}}
|
||||
template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in module N follows declaration in module M}} expected-note@M.cppm:11 {{previous}}
|
||||
template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module N follows declaration in module M}} expected-note@M.cppm:12 {{previous}}
|
||||
|
||||
typedef int type;
|
||||
namespace ns { using ::func; }
|
||||
namespace ns_alias = ns;
|
||||
#endif
|
||||
|
||||
//--- module-vs-module-impl.cpp
|
||||
module N;
|
||||
|
||||
#ifndef NO_IMPORT
|
||||
import M;
|
||||
#endif
|
||||
|
||||
#ifndef NO_ERRORS
|
||||
extern int var; // expected-error {{declaration of 'var' in module N follows declaration in module M}} expected-note@M.cppm:4 {{previous}}
|
||||
int func(); // expected-error {{declaration of 'func' in module N follows declaration in module M}} expected-note@M.cppm:5 {{previous}}
|
||||
struct str; // expected-error {{declaration of 'str' in module N follows declaration in module M}} expected-note@M.cppm:6 {{previous}}
|
||||
using type = int;
|
||||
|
||||
template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module N follows declaration in module M}} expected-note@M.cppm:9 {{previous}}
|
||||
template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in module N follows declaration in module M}} expected-note@M.cppm:10 {{previous}}
|
||||
template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in module N follows declaration in module M}} expected-note@M.cppm:11 {{previous}}
|
||||
template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module N follows declaration in module M}} expected-note@M.cppm:12 {{previous}}
|
||||
|
||||
typedef int type;
|
||||
namespace ns { using ::func; }
|
||||
namespace ns_alias = ns;
|
||||
#endif
|
||||
|
||||
@ -8,27 +8,19 @@
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface -fmodule-file=x=%t/x.pcm %t/x.y.cppm -o %t/x.y.pcm
|
||||
//
|
||||
// Module implementation for unknown and known module. (The former is ill-formed.)
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify -x c++ %t/M.cpp \
|
||||
// RUN: -DTEST=1 -DEXPORT= -DMODULE_NAME=z
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x=%t/x.pcm -fmodule-file=x.y=%t/x.y.pcm -verify -x c++ %t/M.cpp \
|
||||
// RUN: -DTEST=2 -DEXPORT= -DMODULE_NAME=x
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify -x c++ %t/z_impl.cppm
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x=%t/x.pcm -fmodule-file=x.y=%t/x.y.pcm -verify -x c++ %t/x_impl.cppm
|
||||
//
|
||||
// Module interface for unknown and known module. (The latter is ill-formed due to
|
||||
// redefinition.)
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \
|
||||
// RUN: -DTEST=3 -DEXPORT=export -DMODULE_NAME=z
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \
|
||||
// RUN: -DTEST=4 -DEXPORT=export -DMODULE_NAME=x
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/z_interface.cppm
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/x_interface.cppm
|
||||
//
|
||||
// Miscellaneous syntax.
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \
|
||||
// RUN: -DTEST=7 -DEXPORT=export -DMODULE_NAME='z elderberry'
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \
|
||||
// RUN: -DTEST=8 -DEXPORT=export -DMODULE_NAME='z [[]]'
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \
|
||||
// RUN: -DTEST=9 -DEXPORT=export -DMODULE_NAME='z [[fancy]]'
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \
|
||||
// RUN: -DTEST=10 -DEXPORT=export -DMODULE_NAME='z [[maybe_unused]]'
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/invalid_module_name.cppm
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/empty_attribute.cppm
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/fancy_attribute.cppm
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/maybe_unused_attribute.cppm
|
||||
|
||||
//--- x.cppm
|
||||
export module x;
|
||||
@ -38,17 +30,31 @@ int a, b;
|
||||
export module x.y;
|
||||
int c;
|
||||
|
||||
//--- M.cpp
|
||||
//--- z_impl.cppm
|
||||
module z; // expected-error {{module 'z' not found}}
|
||||
|
||||
EXPORT module MODULE_NAME;
|
||||
#if TEST == 7
|
||||
// expected-error@-2 {{expected ';'}} expected-error@-2 {{a type specifier is required}}
|
||||
#elif TEST == 9
|
||||
// expected-warning@-4 {{unknown attribute 'fancy' ignored}}
|
||||
#elif TEST == 10
|
||||
// expected-error-re@-6 {{'maybe_unused' attribute cannot be applied to a module{{$}}}}
|
||||
#elif TEST == 1
|
||||
// expected-error@-8 {{module 'z' not found}}
|
||||
#else
|
||||
//--- x_impl.cppm
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
module x;
|
||||
|
||||
//--- z_interface.cppm
|
||||
// expected-no-diagnostics
|
||||
export module z;
|
||||
|
||||
//--- x_interface.cppm
|
||||
// expected-no-diagnostics
|
||||
export module x;
|
||||
|
||||
//--- invalid_module_name.cppm
|
||||
export module z elderberry; // expected-error {{expected ';'}} \
|
||||
// expected-error {{a type specifier is required}}
|
||||
|
||||
//--- empty_attribute.cppm
|
||||
// expected-no-diagnostics
|
||||
export module z [[]];
|
||||
|
||||
//--- fancy_attribute.cppm
|
||||
export module z [[fancy]]; // expected-warning {{unknown attribute 'fancy' ignored}}
|
||||
|
||||
//--- maybe_unused_attribute.cppm
|
||||
export module z [[maybe_unused]]; // expected-error-re {{'maybe_unused' attribute cannot be applied to a module{{$}}}}
|
||||
|
||||
8
clang/test/CXX/module/cpp.pre/module_decl.cpp
Normal file
8
clang/test/CXX/module/cpp.pre/module_decl.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: mkdir -p %t
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -verify -o %t/M.pcm
|
||||
|
||||
// This is a comment
|
||||
#define I32 int // expected-note {{add 'module;' to the start of the file to introduce a global module fragment}}
|
||||
export module M; // expected-error {{module declaration must occur at the start of the translation unit}}
|
||||
export I32 i32;
|
||||
@ -6,10 +6,10 @@
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface -fmodule-file=x=%t/x.pcm %t/x.y.cppm -o %t/x.y.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/a.b.cppm -o %t/a.b.pcm
|
||||
//
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm -verify %t/test.cpp \
|
||||
// RUN: -DMODULE_NAME=z -DINTERFACE
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm \
|
||||
// RUN: -fmodule-file=a.b=%t/a.b.pcm -verify %t/test.cpp -DMODULE_NAME=a.b
|
||||
// RUN: -verify %t/test.interface.cpp
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm \
|
||||
// RUN: -fmodule-file=a.b=%t/a.b.pcm -verify %t/test.implementation.cpp
|
||||
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm -verify %t/test.x.cpp
|
||||
|
||||
//--- x.cppm
|
||||
@ -33,19 +33,33 @@ int use_2 = b; // ok
|
||||
// There is no relation between module x and module x.y.
|
||||
int use_3 = c; // expected-error {{use of undeclared identifier 'c'}}
|
||||
|
||||
//--- test.cpp
|
||||
#ifdef INTERFACE
|
||||
export module MODULE_NAME;
|
||||
#else
|
||||
module MODULE_NAME;
|
||||
#endif
|
||||
//--- test.interface.cpp
|
||||
export module z;
|
||||
|
||||
import x;
|
||||
|
||||
import x [[]];
|
||||
import x [[foo]]; // expected-warning {{unknown attribute 'foo' ignored}}
|
||||
import x [[noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to a module import}}
|
||||
import x [[blarg::noreturn]]; // expected-warning {{unknown attribute 'blarg::noreturn' ignored}}
|
||||
import x [[blarg::noreturn]]; // expected-warning-re {{unknown attribute 'blarg::noreturn' ignored{{.*}}}}
|
||||
|
||||
import x.y;
|
||||
import x.; // expected-error {{expected a module name after 'import'}}
|
||||
import .x; // expected-error {{expected a module name after 'import'}}
|
||||
|
||||
import blarg; // expected-error {{module 'blarg' not found}}
|
||||
|
||||
int use_4 = c; // ok
|
||||
|
||||
//--- test.implementation.cpp
|
||||
module a.b;
|
||||
|
||||
import x;
|
||||
|
||||
import x [[]];
|
||||
import x [[foo]]; // expected-warning {{unknown attribute 'foo' ignored}}
|
||||
import x [[noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to a module import}}
|
||||
import x [[blarg::noreturn]]; // expected-warning-re {{unknown attribute 'blarg::noreturn' ignored{{.*}}}}
|
||||
|
||||
import x.y;
|
||||
import x.; // expected-error {{expected a module name after 'import'}}
|
||||
|
||||
@ -1,29 +1,26 @@
|
||||
// RUN: %clang_cc1 -std=c++20 %s -verify -emit-module-interface -o /dev/null
|
||||
// RUN: %clang_cc1 -std=c++20 %s -DINTERFACE -verify -emit-module-interface -o %t
|
||||
// RUN: %clang_cc1 -std=c++20 %s -DIMPLEMENTATION -verify -fmodule-file=A=%t -o /dev/null
|
||||
//
|
||||
// RUN: %clang_cc1 -std=c++20 %s -DBUILT_AS_INTERFACE -emit-module-interface -verify -o /dev/null
|
||||
// RUN: %clang_cc1 -std=c++20 %s -DINTERFACE -DBUILT_AS_INTERFACE -emit-module-interface -verify -o /dev/null
|
||||
// RUN: %clang_cc1 -std=c++20 %s -DIMPLEMENTATION -DBUILT_AS_INTERFACE -emit-module-interface -verify -o /dev/null
|
||||
// RUN: rm -rf %t
|
||||
// RUN: split-file %s %t
|
||||
|
||||
#if INTERFACE
|
||||
// RUN: %clang_cc1 -std=c++20 %t/ExportDeclNotInModulePurview.cppm -verify -emit-module-interface -o /dev/null
|
||||
// RUN: %clang_cc1 -std=c++20 %t/A.cppm -verify -emit-module-interface -o %t/A.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 %t/AddExport.cppm -verify -fmodule-file=A=%t/A.pcm -o /dev/null
|
||||
//
|
||||
// RUN: %clang_cc1 -std=c++20 %t/AddExport2.cppm -emit-module-interface -verify -o /dev/null
|
||||
|
||||
//--- ExportDeclNotInModulePurview.cppm
|
||||
// expected-error@* {{missing 'export module' declaration in module interface unit}}
|
||||
export int b; // expected-error {{export declaration can only be used within a module purview}}
|
||||
|
||||
//--- A.cppm
|
||||
// expected-no-diagnostics
|
||||
export module A;
|
||||
#elif IMPLEMENTATION
|
||||
module A; // #module-decl
|
||||
#ifdef BUILT_AS_INTERFACE
|
||||
// expected-error@-2 {{missing 'export' specifier in module declaration while building module interface}}
|
||||
#define INTERFACE
|
||||
#endif
|
||||
#else // Not in a module
|
||||
// expected-error@* {{missing 'export module' declaration in module interface unit}}
|
||||
#endif
|
||||
|
||||
#ifndef INTERFACE
|
||||
export int b; // expected-error {{export declaration can only be used within a module purview}}
|
||||
#ifdef IMPLEMENTATION
|
||||
// expected-note@#module-decl {{add 'export' here}}
|
||||
#endif
|
||||
#else
|
||||
export int a;
|
||||
#endif
|
||||
|
||||
//--- AddExport.cppm
|
||||
module A; // #module-decl
|
||||
export int b; // expected-error {{export declaration can only be used within a module purview}}
|
||||
// expected-note@#module-decl {{add 'export' here}}
|
||||
|
||||
//--- AddExport2.cppm
|
||||
module A; // expected-error {{missing 'export' specifier in module declaration while building module interface}}
|
||||
export int a;
|
||||
|
||||
@ -1,14 +1,30 @@
|
||||
// RUN: %clang_cc1 -std=c++20 -verify %s -DFOO=export -DBAR=export
|
||||
// RUN: %clang_cc1 -std=c++20 -verify %s -DFOO=export -DBAR=
|
||||
// RUN: %clang_cc1 -std=c++20 %s -DFOO=export -emit-module-interface -o %t
|
||||
// RUN: %clang_cc1 -std=c++20 %s -fmodule-file=foo=%t -DFOO=
|
||||
// RUN: %clang_cc1 -std=c++20 %s -fmodule-file=foo=%t -DBAR=export
|
||||
// RUN: %clang_cc1 -std=c++20 -verify %s -fmodule-file=foo=%t -DFOO= -DBAR=export
|
||||
// RUN: rm -rf %t
|
||||
// RUN: split-file %s %t
|
||||
|
||||
#ifdef FOO
|
||||
FOO module foo; // expected-note {{previous module declaration is here}}
|
||||
#endif
|
||||
// RUN: %clang_cc1 -std=c++20 -verify %t/A.cppm
|
||||
// RUN: %clang_cc1 -std=c++20 -verify %t/B.cppm
|
||||
// RUN: %clang_cc1 -std=c++20 %t/C.cppm -emit-module-interface -o %t/C.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 %t/D.cppm -fmodule-file=foo=%t/C.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 %t/E.cppm -fmodule-file=foo=%t/C.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 -verify %t/F.cppm -fmodule-file=foo=%t/C.pcm
|
||||
|
||||
#ifdef BAR
|
||||
BAR module bar; // expected-error {{translation unit contains multiple module declarations}}
|
||||
#endif
|
||||
//--- A.cppm
|
||||
export module foo; // expected-note {{previous module declaration is here}}
|
||||
export module bar; // expected-error {{translation unit contains multiple module declarations}}
|
||||
|
||||
//--- B.cppm
|
||||
export module foo; // expected-note {{previous module declaration is here}}
|
||||
module bar; // expected-error {{translation unit contains multiple module declarations}}
|
||||
|
||||
//--- C.cppm
|
||||
export module foo;
|
||||
|
||||
//--- D.cppm
|
||||
module foo;
|
||||
|
||||
//--- E.cppm
|
||||
export module bar;
|
||||
|
||||
//--- F.cppm
|
||||
module foo; // expected-note {{previous module declaration is here}}
|
||||
export module bar; // expected-error {{translation unit contains multiple module declarations}}
|
||||
|
||||
@ -1,22 +1,14 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -o %t -DINTERFACE
|
||||
// RUN: %clang_cc1 -std=c++20 -fmodule-file=Foo=%t %s -verify -DIMPLEMENTATION
|
||||
// RUN: %clang_cc1 -std=c++20 -fmodule-file=Foo=%t %s -verify -DEARLY_IMPLEMENTATION
|
||||
// RUN: %clang_cc1 -std=c++20 -fmodule-file=Foo=%t %s -verify -DUSER
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/interface.cppm -o %t/interface.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 -fmodule-file=Foo=%t/interface.pcm %t/implementation.cppm -verify -DIMPLEMENTATION
|
||||
// RUN: %clang_cc1 -std=c++20 -fmodule-file=Foo=%t/interface.pcm %t/early_impl.cppm -verify -DEARLY_IMPLEMENTATION
|
||||
// RUN: %clang_cc1 -std=c++20 -fmodule-file=Foo=%t/interface.pcm %t/user.cppm -verify -DUSER
|
||||
|
||||
//--- interface.cppm
|
||||
// expected-no-diagnostics
|
||||
|
||||
#if defined(INTERFACE) || defined(EARLY_IMPLEMENTATION) || defined(IMPLEMENTATION)
|
||||
module;
|
||||
#endif
|
||||
|
||||
#ifdef USER
|
||||
import Foo;
|
||||
#endif
|
||||
|
||||
#ifdef EARLY_IMPLEMENTATION
|
||||
module Foo;
|
||||
#endif
|
||||
|
||||
template<typename T> struct type_template {
|
||||
typedef T type;
|
||||
@ -28,10 +20,49 @@ template<typename T> void type_template<T>::f(type) {}
|
||||
template<int = 0, typename = int, template<typename> class = type_template>
|
||||
struct default_template_args {};
|
||||
|
||||
#ifdef INTERFACE
|
||||
export module Foo;
|
||||
#endif
|
||||
|
||||
#ifdef IMPLEMENTATION
|
||||
//--- implementation.cppm
|
||||
// expected-no-diagnostics
|
||||
module;
|
||||
|
||||
template<typename T> struct type_template {
|
||||
typedef T type;
|
||||
void f(type);
|
||||
};
|
||||
|
||||
template<typename T> void type_template<T>::f(type) {}
|
||||
|
||||
template<int = 0, typename = int, template<typename> class = type_template>
|
||||
struct default_template_args {};
|
||||
|
||||
module Foo;
|
||||
#endif
|
||||
|
||||
//--- early_impl.cppm
|
||||
// expected-no-diagnostics
|
||||
module;
|
||||
module Foo;
|
||||
|
||||
template<typename T> struct type_template {
|
||||
typedef T type;
|
||||
void f(type);
|
||||
};
|
||||
|
||||
template<typename T> void type_template<T>::f(type) {}
|
||||
|
||||
template<int = 0, typename = int, template<typename> class = type_template>
|
||||
struct default_template_args {};
|
||||
|
||||
//--- user.cppm
|
||||
// expected-no-diagnostics
|
||||
import Foo;
|
||||
|
||||
template<typename T> struct type_template {
|
||||
typedef T type;
|
||||
void f(type);
|
||||
};
|
||||
|
||||
template<typename T> void type_template<T>::f(type) {}
|
||||
|
||||
template<int = 0, typename = int, template<typename> class = type_template>
|
||||
struct default_template_args {};
|
||||
|
||||
@ -1,24 +1,26 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: mkdir -p %t
|
||||
// RUN: split-file %s %t
|
||||
//
|
||||
// RUN: %clang_cc1 -std=c++20 -x c++-header %S/Inputs/header.h -emit-header-unit -o %t/h.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 %s -DX_INTERFACE -emit-module-interface -o %t/x.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 %s -DY_INTERFACE -emit-module-interface -o %t/y.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 %s -DINTERFACE -fmodule-file=X=%t/x.pcm -fmodule-file=Y=%t/y.pcm -emit-module-interface -o %t/m.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 %s -DIMPLEMENTATION -I%S/Inputs -fmodule-file=%t/h.pcm \
|
||||
// RUN: %clang_cc1 -std=c++20 %t/x.cppm -emit-module-interface -o %t/x.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 %t/y.cppm -emit-module-interface -o %t/y.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 %t/interface.cppm -fmodule-file=X=%t/x.pcm -fmodule-file=Y=%t/y.pcm -emit-module-interface -o %t/m.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 %t/impl.cppm -I%S/Inputs -fmodule-file=%t/h.pcm \
|
||||
// RUN: -fmodule-file=X=%t/x.pcm -fmodule-file=Y=%t/y.pcm -fmodule-file=p2=%t/m.pcm -verify \
|
||||
// RUN: -Wno-experimental-header-units
|
||||
// RUN: %clang_cc1 -std=c++20 %s -DUSER -I%S/Inputs -fmodule-file=%t/h.pcm -fmodule-file=p2=%t/m.pcm \
|
||||
// RUN: %clang_cc1 -std=c++20 %t/user.cppm -I%S/Inputs -fmodule-file=%t/h.pcm -fmodule-file=p2=%t/m.pcm \
|
||||
// RUN: -fmodule-file=X=%t/x.pcm -fmodule-file=Y=%t/y.pcm -Wno-experimental-header-units -verify
|
||||
|
||||
#if defined(X_INTERFACE)
|
||||
//--- x.cppm
|
||||
export module X;
|
||||
export int x;
|
||||
|
||||
#elif defined(Y_INTERFACE)
|
||||
//--- y.cppm
|
||||
export module Y;
|
||||
export int y;
|
||||
|
||||
#elif defined(INTERFACE)
|
||||
//--- interface.cppm
|
||||
export module p2;
|
||||
export import X;
|
||||
import Y; // not exported
|
||||
@ -39,7 +41,7 @@ namespace C {}
|
||||
namespace D { int f(); }
|
||||
export namespace D {}
|
||||
|
||||
#elif defined(IMPLEMENTATION)
|
||||
//--- impl.cppm
|
||||
module p2;
|
||||
import "header.h";
|
||||
|
||||
@ -66,7 +68,7 @@ void use() {
|
||||
|
||||
int use_header() { return foo + bar::baz(); }
|
||||
|
||||
#elif defined(USER)
|
||||
//--- user.cppm
|
||||
import p2;
|
||||
import "header.h";
|
||||
|
||||
@ -96,7 +98,3 @@ void use() {
|
||||
}
|
||||
|
||||
int use_header() { return foo + bar::baz(); }
|
||||
|
||||
#else
|
||||
#error unknown mode
|
||||
#endif
|
||||
|
||||
@ -1,37 +1,45 @@
|
||||
// RUN: echo 'export module foo; export int n;' > %t.cppm
|
||||
// RUN: rm -rf %t
|
||||
// RUN: mkdir %t
|
||||
// RUN: split-file %s %t
|
||||
// RUN: echo 'export module foo;' > %t.cppm
|
||||
// RUN: echo 'export int n;' >> %t.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a %t.cppm -emit-module-interface -o %t.pcm
|
||||
// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=0 %s
|
||||
// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=1 %s
|
||||
// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=2 %s
|
||||
// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=3 %s
|
||||
// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=4 %s
|
||||
// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=5 %s
|
||||
// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=0 %t/A.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=1 %t/B.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=2 %t/C.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=3 %t/D.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=4 %t/E.cppm
|
||||
// RUN: %clang_cc1 -std=c++2a -fmodule-file=foo=%t.pcm -verify -DMODE=5 %t/F.cppm
|
||||
|
||||
#if MODE == 0
|
||||
//--- A.cppm
|
||||
// no module declaration
|
||||
// expected-no-diagnostics
|
||||
|
||||
#elif MODE == 1
|
||||
//--- B.cppm
|
||||
// expected-no-diagnostics
|
||||
module foo; // Implementation, implicitly imports foo.
|
||||
#define IMPORTED
|
||||
|
||||
#elif MODE == 2
|
||||
int k = n;
|
||||
|
||||
//--- C.cppm
|
||||
export module foo;
|
||||
|
||||
#elif MODE == 3
|
||||
int k = n; // expected-error {{use of undeclared identifier 'n'}}
|
||||
|
||||
//--- D.cppm
|
||||
export module bar; // A different module
|
||||
|
||||
#elif MODE == 4
|
||||
int k = n; // expected-error {{use of undeclared identifier 'n'}}
|
||||
|
||||
//--- E.cppm
|
||||
module foo:bar; // Partition implementation
|
||||
//#define IMPORTED (we don't import foo here)
|
||||
|
||||
#elif MODE == 5
|
||||
int k = n; // expected-error {{use of undeclared identifier 'n'}}
|
||||
|
||||
//--- F.cppm
|
||||
export module foo:bar; // Partition interface
|
||||
//#define IMPORTED (we don't import foo here)
|
||||
|
||||
#endif
|
||||
|
||||
int k = n;
|
||||
#ifndef IMPORTED
|
||||
// expected-error@-2 {{use of undeclared identifier 'n'}}
|
||||
#endif
|
||||
int k = n; // expected-error {{use of undeclared identifier 'n'}}
|
||||
|
||||
@ -1,43 +1,48 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: mkdir %t
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// Check compiling a module interface to a .pcm file.
|
||||
//
|
||||
// RUN: %clang -std=c++2a -x c++-module --precompile %s -o %t/module.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE
|
||||
// RUN: %clang -std=gnu++2a -x c++-module --precompile %s -o %t/module-gnu.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE
|
||||
// RUN: %clang -std=c++2a -x c++-module --precompile %t/foo.cpp -o %t/foo.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE
|
||||
// RUN: %clang -std=gnu++2a -x c++-module --precompile %t/foo.cpp -o %t/foo-gnu.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE
|
||||
//
|
||||
// CHECK-PRECOMPILE: -cc1 {{.*}} -emit-module-interface
|
||||
// CHECK-PRECOMPILE-SAME: -o {{.*}}.pcm
|
||||
// CHECK-PRECOMPILE-SAME: -x c++
|
||||
// CHECK-PRECOMPILE-SAME: modules.cpp
|
||||
// CHECK-PRECOMPILE-SAME: foo.cpp
|
||||
|
||||
// Check compiling a .pcm file to a .o file.
|
||||
//
|
||||
// RUN: %clang -std=c++2a %t/module.pcm -S -o %t/module.pcm.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-COMPILE
|
||||
// RUN: %clang -std=c++2a %t/foo.pcm -S -o %t/foo.pcm.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-COMPILE
|
||||
//
|
||||
// CHECK-COMPILE: -cc1 {{.*}} {{-emit-obj|-S}}
|
||||
// CHECK-COMPILE-SAME: -o {{.*}}module{{2*}}.pcm.o
|
||||
// CHECK-COMPILE-SAME: -o {{.*}}foo{{2*}}.pcm.o
|
||||
// CHECK-COMPILE-SAME: -x pcm
|
||||
// CHECK-COMPILE-SAME: {{.*}}.pcm
|
||||
|
||||
// Check use of a .pcm file in another compilation.
|
||||
//
|
||||
// RUN: %clang -std=c++2a -fmodule-file=%t/module.pcm -Dexport= %s -S -o %t/module.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE
|
||||
// RUN: %clang -std=c++20 -fmodule-file=%t/module.pcm -Dexport= %s -S -o %t/module.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE
|
||||
// RUN: %clang -std=gnu++20 -fmodule-file=%t/module-gnu.pcm -Dexport= %s -S -o %t/module.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE
|
||||
// RUN: %clang -std=c++2a -fmodule-file=foo=%t/foo.pcm %t/foo_impl.cpp -S -o %t/module.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE
|
||||
// RUN: %clang -std=c++20 -fmodule-file=foo=%t/foo.pcm %t/foo_impl.cpp -S -o %t/module.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE
|
||||
// RUN: %clang -std=gnu++20 -fmodule-file=foo=%t/foo-gnu.pcm %t/foo_impl.cpp -S -o %t/module.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE
|
||||
//
|
||||
// CHECK-USE: -cc1 {{.*}} {{-emit-obj|-S}}
|
||||
// CHECK-USE-SAME: -fmodule-file={{.*}}.pcm
|
||||
// CHECK-USE-SAME: -fmodule-file=foo={{.*}}.pcm
|
||||
// CHECK-USE-SAME: -o {{.*}}.{{o|s}}{{"?}} {{.*}}-x c++
|
||||
// CHECK-USE-SAME: modules.cpp
|
||||
// CHECK-USE-SAME: foo_impl.cpp
|
||||
|
||||
// Check combining precompile and compile steps works.
|
||||
//
|
||||
// RUN: %clang -std=c++2a -x c++-module %s -S -o %t/module2.pcm.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE --check-prefix=CHECK-COMPILE
|
||||
// RUN: %clang -std=c++2a -x c++-module %t/foo.cpp -S -o %t/foo2.pcm.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE --check-prefix=CHECK-COMPILE
|
||||
|
||||
// Check that .cppm is treated as a module implicitly.
|
||||
//
|
||||
// RUN: cp %s %t/module.cppm
|
||||
// RUN: %clang -std=c++2a --precompile %t/module.cppm -o %t/module.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE
|
||||
// RUN: cp %t/foo.cpp %t/foo.cppm
|
||||
// RUN: %clang -std=c++2a --precompile %t/foo.cppm -o %t/foo.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE
|
||||
|
||||
//--- foo.cpp
|
||||
export module foo;
|
||||
|
||||
//--- foo_impl.cpp
|
||||
module foo;
|
||||
|
||||
@ -58,6 +58,7 @@ void b(T x) {
|
||||
}
|
||||
|
||||
//--- c.cppm
|
||||
module;
|
||||
#ifdef EXPORT_OPERATOR
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
|
||||
@ -88,12 +88,14 @@ export module module; // expected-error {{'module' is an invalid name for a modu
|
||||
export module import; // expected-error {{'import' is an invalid name for a module}}
|
||||
|
||||
//--- _Test.cppm
|
||||
module;
|
||||
#ifdef NODIAGNOSTICS
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
export module _Test; // loud-warning {{'_Test' is a reserved name for a module}}
|
||||
|
||||
//--- __test.cppm
|
||||
module;
|
||||
#ifdef NODIAGNOSTICS
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
@ -101,6 +103,7 @@ export module __test; // loud-warning {{'__test' is a reserved name for a module
|
||||
export int a = 43;
|
||||
|
||||
//--- te__st.cppm
|
||||
module;
|
||||
#ifdef NODIAGNOSTICS
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
@ -108,6 +111,7 @@ export module te__st; // loud-warning {{'te__st' is a reserved name for a module
|
||||
export int a = 43;
|
||||
|
||||
//--- std.cppm
|
||||
module;
|
||||
#ifdef NODIAGNOSTICS
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
@ -116,36 +120,42 @@ export module std; // loud-warning {{'std' is a reserved name for a module}}
|
||||
export int a = 43;
|
||||
|
||||
//--- std.foo.cppm
|
||||
module;
|
||||
#ifdef NODIAGNOSTICS
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
export module std.foo;// loud-warning {{'std' is a reserved name for a module}}
|
||||
|
||||
//--- std0.cppm
|
||||
module;
|
||||
#ifdef NODIAGNOSTICS
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
export module std0; // loud-warning {{'std0' is a reserved name for a module}}
|
||||
|
||||
//--- std1000000.cppm
|
||||
module;
|
||||
#ifdef NODIAGNOSTICS
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
export module std1000000; // loud-warning {{'std1000000' is a reserved name for a module}}
|
||||
|
||||
//--- should_diag._Test.cppm
|
||||
module;
|
||||
#ifdef NODIAGNOSTICS
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
export module should_diag._Test; // loud-warning {{'_Test' is a reserved name for a module}}
|
||||
|
||||
//--- system-module.cppm
|
||||
module; // expected-error {{missing 'module' declaration at end of global module fragment introduced here}}
|
||||
// Show that being in a system header doesn't save you from diagnostics about
|
||||
// use of an invalid module-name identifier.
|
||||
# 34 "reserved-names-1.cpp" 1 3
|
||||
export module module; // expected-error {{'module' is an invalid name for a module}}
|
||||
|
||||
//--- system._Test.import.cppm
|
||||
module; // expected-error {{missing 'module' declaration at end of global module fragment introduced here}}
|
||||
# 34 "reserved-names-1.cpp" 1 3
|
||||
export module _Test.import; // expected-error {{'import' is an invalid name for a module}}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
module;
|
||||
// Show that we suppress the reserved identifier diagnostic in a system header.
|
||||
# 100 "file.cpp" 1 3 // Enter a system header
|
||||
export module std;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
module;
|
||||
// Show that we suppress the reserved identifier diagnostic in a system header.
|
||||
# 100 "file.cpp" 1 3 // Enter a system header
|
||||
export module __test;
|
||||
|
||||
@ -1,19 +1,20 @@
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -o %t.0.pcm -verify -DTEST=0
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -o %t.1.pcm -verify -DTEST=1
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -fmodule-file=foo=%t.0.pcm -o %t.2.pcm -verify -DTEST=2
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -fmodule-file=foo=%t.0.pcm -o %t.3.pcm -verify -Dfoo=bar -DTEST=3
|
||||
// RUN: rm -rf %t
|
||||
// RUN: mkdir -p %t
|
||||
// RUN: split-file %s %t
|
||||
|
||||
#if TEST == 0 || TEST == 2
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/test0.cpp -o %t/test0.pcm -verify
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/test1.cpp -o %t/test1.pcm -verify
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/test2.cpp -fmodule-file=foo=%t/test0.pcm -o %t/test2.pcm -verify
|
||||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/test3.cpp -fmodule-file=foo=%t/test0.pcm -o %t/test3.pcm -verify
|
||||
|
||||
//--- test0.cpp
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
|
||||
export module foo;
|
||||
|
||||
static int m;
|
||||
|
||||
int n;
|
||||
|
||||
#if TEST == 0
|
||||
export {
|
||||
int a;
|
||||
int b;
|
||||
@ -27,10 +28,52 @@ export void f() {}
|
||||
|
||||
export struct T {
|
||||
} t;
|
||||
#elif TEST == 3
|
||||
|
||||
//--- test1.cpp
|
||||
export module foo;
|
||||
|
||||
static int m;
|
||||
|
||||
int n;
|
||||
|
||||
struct S {
|
||||
export int n; // expected-error {{expected member name or ';'}}
|
||||
export static int n; // expected-error {{expected member name or ';'}}
|
||||
};
|
||||
|
||||
// FIXME: Exports of declarations without external linkage are disallowed.
|
||||
// Exports of declarations with non-external-linkage types are disallowed.
|
||||
|
||||
// Cannot export within another export. This isn't precisely covered by the
|
||||
// language rules right now, but (per personal correspondence between zygoloid
|
||||
// and gdr) is the intent.
|
||||
export { // expected-note {{export block begins here}}
|
||||
extern "C++" {
|
||||
namespace NestedExport {
|
||||
export { // expected-error {{export declaration appears within another export declaration}}
|
||||
int q;
|
||||
}
|
||||
} // namespace NestedExport
|
||||
}
|
||||
}
|
||||
|
||||
//--- test2.cpp
|
||||
// expected-no-diagnostics
|
||||
export module foo;
|
||||
|
||||
static int m;
|
||||
|
||||
int n;
|
||||
|
||||
//--- test3.cpp
|
||||
export module bar;
|
||||
|
||||
static int m;
|
||||
|
||||
int n;
|
||||
|
||||
int use_a = a; // expected-error {{use of undeclared identifier 'a'}}
|
||||
|
||||
#undef foo
|
||||
import foo; // expected-error {{imports must immediately follow the module declaration}}
|
||||
|
||||
export {}
|
||||
@ -46,29 +89,3 @@ int use_n = n; // FIXME: this should not be visible, because it is not exported
|
||||
|
||||
extern int n;
|
||||
static_assert(&n != p); // expected-error{{use of undeclared identifier 'p'}}
|
||||
#endif
|
||||
|
||||
#if TEST == 1
|
||||
struct S {
|
||||
export int n; // expected-error {{expected member name or ';'}}
|
||||
export static int n; // expected-error {{expected member name or ';'}}
|
||||
};
|
||||
#endif
|
||||
|
||||
// FIXME: Exports of declarations without external linkage are disallowed.
|
||||
// Exports of declarations with non-external-linkage types are disallowed.
|
||||
|
||||
// Cannot export within another export. This isn't precisely covered by the
|
||||
// language rules right now, but (per personal correspondence between zygoloid
|
||||
// and gdr) is the intent.
|
||||
#if TEST == 1
|
||||
export { // expected-note {{export block begins here}}
|
||||
extern "C++" {
|
||||
namespace NestedExport {
|
||||
export { // expected-error {{export declaration appears within another export declaration}}
|
||||
int q;
|
||||
}
|
||||
} // namespace NestedExport
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1,12 +1,22 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -fexceptions -DTRANSPARENT_DECL=0
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -fexceptions -DTRANSPARENT_DECL=1
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -fexceptions -DTRANSPARENT_DECL=2
|
||||
// RUN: rm -rf %t
|
||||
// RUN: mkdir %t
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %t/testing.cpp -std=c++26 -fexceptions -DTRANSPARENT_DECL=0
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %t/testing.cpp -std=c++26 -fexceptions -DTRANSPARENT_DECL=1
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %t/module_testing.cppm -std=c++26 -fexceptions -DTRANSPARENT_DECL=2
|
||||
|
||||
//--- module_testing.cppm
|
||||
// expected-no-diagnostics
|
||||
#if TRANSPARENT_DECL==2
|
||||
export module Testing;
|
||||
#endif
|
||||
|
||||
#include "testing.inc"
|
||||
|
||||
//--- testing.cpp
|
||||
// expected-no-diagnostics
|
||||
#include "testing.inc"
|
||||
|
||||
//--- testing.inc
|
||||
namespace std {
|
||||
template <class T> struct type_identity {};
|
||||
using size_t = __SIZE_TYPE__;
|
||||
|
||||
@ -49,7 +49,8 @@ protected:
|
||||
}
|
||||
|
||||
std::unique_ptr<Preprocessor> CreatePP(StringRef Source,
|
||||
TrivialModuleLoader &ModLoader) {
|
||||
TrivialModuleLoader &ModLoader,
|
||||
StringRef PreDefines = {}) {
|
||||
std::unique_ptr<llvm::MemoryBuffer> Buf =
|
||||
llvm::MemoryBuffer::getMemBuffer(Source);
|
||||
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
|
||||
@ -61,6 +62,8 @@ protected:
|
||||
PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
|
||||
/*IILookup =*/nullptr,
|
||||
/*OwnsHeaderSearch =*/false);
|
||||
if (!PreDefines.empty())
|
||||
PP->setPredefines(PreDefines.str());
|
||||
PP->Initialize(*Target);
|
||||
PP->EnterMainSourceFile();
|
||||
return PP;
|
||||
@ -769,4 +772,46 @@ TEST(LexerPreambleTest, PreambleBounds) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(LexerTest, CheckFirstPPToken) {
|
||||
{
|
||||
TrivialModuleLoader ModLoader;
|
||||
auto PP = CreatePP("// This is a comment\n"
|
||||
"int a;",
|
||||
ModLoader);
|
||||
Token Tok;
|
||||
PP->Lex(Tok);
|
||||
EXPECT_TRUE(Tok.is(tok::kw_int));
|
||||
EXPECT_TRUE(PP->hasSeenMainFileFirstPPToken());
|
||||
EXPECT_TRUE(PP->getMainFileFirstPPToken().isFirstPPToken());
|
||||
EXPECT_TRUE(PP->getMainFileFirstPPToken().is(tok::kw_int));
|
||||
}
|
||||
{
|
||||
TrivialModuleLoader ModLoader;
|
||||
auto PP = CreatePP("// This is a comment\n"
|
||||
"#define FOO int\n"
|
||||
"FOO a;",
|
||||
ModLoader);
|
||||
Token Tok;
|
||||
PP->Lex(Tok);
|
||||
EXPECT_TRUE(Tok.is(tok::kw_int));
|
||||
EXPECT_TRUE(PP->hasSeenMainFileFirstPPToken());
|
||||
EXPECT_TRUE(PP->getMainFileFirstPPToken().isFirstPPToken());
|
||||
EXPECT_TRUE(PP->getMainFileFirstPPToken().is(tok::hash));
|
||||
}
|
||||
|
||||
{
|
||||
TrivialModuleLoader ModLoader;
|
||||
auto PP = CreatePP("// This is a comment\n"
|
||||
"FOO a;",
|
||||
ModLoader, "#define FOO int\n");
|
||||
Token Tok;
|
||||
PP->Lex(Tok);
|
||||
EXPECT_TRUE(Tok.is(tok::kw_int));
|
||||
EXPECT_TRUE(PP->hasSeenMainFileFirstPPToken());
|
||||
EXPECT_TRUE(PP->getMainFileFirstPPToken().isFirstPPToken());
|
||||
EXPECT_TRUE(PP->getMainFileFirstPPToken().is(tok::identifier));
|
||||
EXPECT_TRUE(
|
||||
PP->getMainFileFirstPPToken().getIdentifierInfo()->isStr("FOO"));
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user