https://github.com/yronglin updated https://github.com/llvm/llvm-project/pull/90574
>From 1dcb4c3ac1efaf3a6a4317751e23089a6c8ccac1 Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Tue, 30 Apr 2024 17:18:26 +0800 Subject: [PATCH 1/2] =?UTF-8?q?[Clang]=20Implement=20P3034R1=20Module=20De?= =?UTF-8?q?clarations=20Shouldn=E2=80=99t=20be=20Macros?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yronglin <yronglin...@gmail.com> --- clang/docs/ReleaseNotes.rst | 2 ++ .../clang/Basic/DiagnosticParseKinds.td | 2 ++ clang/lib/Parse/Parser.cpp | 7 ++++ clang/test/CXX/cpp/cpp.module/p1.cppm | 13 +++++++ clang/test/CXX/cpp/cpp.module/version.h | 8 +++++ .../basic/basic.link/module-declaration.cpp | 35 +++++++++++-------- .../dcl.module/dcl.module.import/p1.cppm | 4 +-- clang/test/SemaCXX/modules.cppm | 4 +++ clang/www/cxx_status.html | 2 +- 9 files changed, 59 insertions(+), 18 deletions(-) create mode 100644 clang/test/CXX/cpp/cpp.module/p1.cppm create mode 100644 clang/test/CXX/cpp/cpp.module/version.h diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 1abc00a25f1f42..40c6bd63e9948f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -153,6 +153,8 @@ C++2c Feature Support - Implemented `P2748R5 Disallow Binding a Returned Glvalue to a Temporary <https://wg21.link/P2748R5>`_. +- Implemented `P3034R1 Module Declarations Shouldn’t be Macros <https://wg21.link/P3034R1>`_. + Resolutions to C++ Defect Reports ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Substitute template parameter pack, when it is not explicitly specified diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index fdffb35ea0d955..0d4b526ec6d15a 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1671,6 +1671,8 @@ 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_decl_cannot_be_macros : Error< + "module declaration cannot be a macro">; def err_attribute_not_module_attr : Error< "%0 attribute cannot be applied to a module">; def err_keyword_not_module_attr : Error< diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index adcbe5858bc78e..ef66348a83125c 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2690,6 +2690,13 @@ bool Parser::ParseModuleName( return true; } + // P3034R1: Module Declarations Shouldn’t be Macros + if (!IsImport && Tok.getLocation().isMacroID()) { + Diag(Tok, diag::err_module_decl_cannot_be_macros); + SkipUntil(tok::semi); + return true; + } + // Record this part of the module path. Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation())); ConsumeToken(); diff --git a/clang/test/CXX/cpp/cpp.module/p1.cppm b/clang/test/CXX/cpp/cpp.module/p1.cppm new file mode 100644 index 00000000000000..b439366db3fba0 --- /dev/null +++ b/clang/test/CXX/cpp/cpp.module/p1.cppm @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -triple x86_64-linux-gnu -DTEST=1 -verify +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -triple x86_64-linux-gnu -DTEST=2 -verify + +module; +export module x; +#include "version.h" +#if TEST == 1 +export module VERSION; // expected-error {{module declaration cannot be a macro}} +#endif // TEST == 1 + +#if TEST == 2 +export module A.B; // expected-error {{module declaration cannot be a macro}} +#endif // TEST == 2 diff --git a/clang/test/CXX/cpp/cpp.module/version.h b/clang/test/CXX/cpp/cpp.module/version.h new file mode 100644 index 00000000000000..4608934290950b --- /dev/null +++ b/clang/test/CXX/cpp/cpp.module/version.h @@ -0,0 +1,8 @@ +#ifndef VERSION_H +#define VERSION_H + +#define VERSION libv5 +#define A a +#define B b + +#endif diff --git a/clang/test/CXX/module/basic/basic.link/module-declaration.cpp b/clang/test/CXX/module/basic/basic.link/module-declaration.cpp index d71358cc7a571f..aa4bb52a57face 100644 --- a/clang/test/CXX/module/basic/basic.link/module-declaration.cpp +++ b/clang/test/CXX/module/basic/basic.link/module-declaration.cpp @@ -9,26 +9,26 @@ // // 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: -DTEST=1 // 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: -DTEST=2 // // 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: -DTEST=3 // 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: -DTEST=4 // // 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: -DTEST=7 // 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: -DTEST=8 // 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: -DTEST=9 // 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: -DTEST=10 //--- x.cppm export module x; @@ -40,15 +40,20 @@ int c; //--- M.cpp -EXPORT module MODULE_NAME; -#if TEST == 7 -// expected-error@-2 {{expected ';'}} expected-error@-2 {{a type specifier is required}} +#if TEST == 1 +module z; // expected-error {{module 'z' not found}} +#elif TEST == 2 +module x; // expected-no-diagnostics +#elif TEST == 3 +export module z; // expected-no-diagnostics +#elif TEST == 4 +export module x; // expected-no-diagnostics +#elif TEST == 7 +export module z elderberry; // expected-error {{expected ';'}} expected-error {{a type specifier is required}} #elif TEST == 9 -// expected-warning@-4 {{unknown attribute 'fancy' ignored}} +export module z [[fancy]]; // expected-warning {{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}} +export module z [[maybe_unused]]; // expected-error-re {{'maybe_unused' attribute cannot be applied to a module{{$}}}} #else // expected-no-diagnostics #endif diff --git a/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm b/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm index 873e4c0edeac25..074589ccc26926 100644 --- a/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm +++ b/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm @@ -35,9 +35,9 @@ int use_3 = c; // expected-error {{use of undeclared identifier 'c'}} //--- test.cpp #ifdef INTERFACE -export module MODULE_NAME; +export module MODULE_NAME; // expected-error {{module declaration cannot be a macro}} #else -module MODULE_NAME; +module MODULE_NAME; // expected-error {{module declaration cannot be a macro}} #endif import x; diff --git a/clang/test/SemaCXX/modules.cppm b/clang/test/SemaCXX/modules.cppm index 41204be76eafa1..75bbc5366d4a71 100644 --- a/clang/test/SemaCXX/modules.cppm +++ b/clang/test/SemaCXX/modules.cppm @@ -7,6 +7,10 @@ // expected-no-diagnostics #endif +#if TEST == 3 +// expected-error {{module declaration cannot be a macro}} +#endif // TEST == 3 + export module foo; static int m; diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index 0996abc2405857..8ae9a25caf3604 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -182,7 +182,7 @@ <h2 id="cxx26">C++2c implementation status</h2> <tr> <td>Module Declarations Shouldn’t be Macros</td> <td><a href="https://wg21.link/P3034R1">P3034R1</a> (<a href="#dr">DR</a>)</td> - <td class="none" align="center">No</td> + <td class="unreleased" align="center">Clang 19</td> </tr> <tr> <td>Trivial infinite loops are not Undefined Behavior</td> >From 0b472f255ca8f9279e58f25e2350cd0eb31baad7 Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Fri, 3 May 2024 20:06:55 +0800 Subject: [PATCH 2/2] Use split-file in test and improve implementation Signed-off-by: yronglin <yronglin...@gmail.com> --- .../clang/Basic/DiagnosticParseKinds.td | 2 +- clang/include/clang/Basic/IdentifierTable.h | 23 ++++- clang/include/clang/Lex/Preprocessor.h | 4 + clang/include/clang/Parse/Parser.h | 2 +- clang/lib/Basic/IdentifierTable.cpp | 3 +- clang/lib/Lex/PPLexerChange.cpp | 3 +- clang/lib/Lex/Preprocessor.cpp | 45 +++++++++ clang/lib/Parse/Parser.cpp | 56 ++++++----- clang/test/CXX/cpp/cpp.module/p1.cppm | 13 --- clang/test/CXX/cpp/cpp.module/p2.cppm | 46 +++++++++ clang/test/CXX/cpp/cpp.module/version.h | 8 -- .../dcl.module/dcl.module.import/p1.cppm | 4 +- clang/test/SemaCXX/modules.cppm | 93 +++++++++++-------- 13 files changed, 212 insertions(+), 90 deletions(-) delete mode 100644 clang/test/CXX/cpp/cpp.module/p1.cppm create mode 100644 clang/test/CXX/cpp/cpp.module/p2.cppm delete mode 100644 clang/test/CXX/cpp/cpp.module/version.h diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 0d4b526ec6d15a..6e3223187b699a 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1672,7 +1672,7 @@ def err_unexpected_module_decl : Error< def err_module_expected_ident : Error< "expected a module name after '%select{module|import}0'">; def err_module_decl_cannot_be_macros : Error< - "module declaration cannot be a macro">; + "the name of a module%select{| partition}0 declaration cannot contains %select{an object-like|a function-like}1 macro %2">; def err_attribute_not_module_attr : Error< "%0 attribute cannot be applied to a module">; def err_keyword_not_module_attr : Error< diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index a893e6f4d3d39d..5bbb9219552b62 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -180,6 +180,10 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo { LLVM_PREFERRED_TYPE(bool) unsigned IsModulesImport : 1; + // True if this is the 'module' contextual keyword. + LLVM_PREFERRED_TYPE(bool) + unsigned IsModulesDecl : 1; + // True if this is a mangled OpenMP variant name. LLVM_PREFERRED_TYPE(bool) unsigned IsMangledOpenMPVariantName : 1; @@ -196,7 +200,7 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo { LLVM_PREFERRED_TYPE(bool) unsigned IsFinal : 1; - // 22 bits left in a 64-bit word. + // 21 bits left in a 64-bit word. // Managed by the language front-end. void *FETokenInfo = nullptr; @@ -211,7 +215,7 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo { IsFutureCompatKeyword(false), IsPoisoned(false), IsCPPOperatorKeyword(false), NeedsHandleIdentifier(false), IsFromAST(false), ChangedAfterLoad(false), FEChangedAfterLoad(false), - RevertedTokenID(false), OutOfDate(false), IsModulesImport(false), + RevertedTokenID(false), OutOfDate(false), IsModulesImport(false), IsModulesDecl(false), IsMangledOpenMPVariantName(false), IsDeprecatedMacro(false), IsRestrictExpansion(false), IsFinal(false) {} @@ -520,6 +524,18 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo { RecomputeNeedsHandleIdentifier(); } + /// Determine whether this is the contextual keyword \c module. + bool isModulesDecl() const { return IsModulesDecl; } + + /// Set whether this identifier is the contextual keyword \c module. + void setModulesDecl(bool I) { + IsModulesDecl = I; + if (I) + NeedsHandleIdentifier = true; + else + RecomputeNeedsHandleIdentifier(); + } + /// Determine whether this is the mangled name of an OpenMP variant. bool isMangledOpenMPVariantName() const { return IsMangledOpenMPVariantName; } @@ -741,6 +757,9 @@ class IdentifierTable { if (Name.equals("import")) II->setModulesImport(true); + if (Name.equals("module")) + II->setModulesDecl(true); + return *II; } diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index e89b4a2c5230e7..ef2dba7177e1e5 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -1735,6 +1735,7 @@ class Preprocessor { bool LexHeaderName(Token &Result, bool AllowMacroExpansion = true); bool LexAfterModuleImport(Token &Result); + bool LexAfterModuleDecl(Token &Result); void CollectPpImportSuffix(SmallVectorImpl<Token> &Toks); void makeModuleVisible(Module *M, SourceLocation Loc); @@ -2937,6 +2938,9 @@ class Preprocessor { static bool CLK_LexAfterModuleImport(Preprocessor &P, Token &Result) { return P.LexAfterModuleImport(Result); } + static bool CLK_LexAfterModuleDecl(Preprocessor &P, Token &Result) { + return P.LexAfterModuleDecl(Result); + } }; /// Abstract base class that describes a handler that will receive diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 81aab8c888ab65..1b429cebde5087 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3811,7 +3811,7 @@ class Parser : public CodeCompletionHandler { bool ParseModuleName( SourceLocation UseLoc, SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path, - bool IsImport); + bool IsImport, bool IsPartition); //===--------------------------------------------------------------------===// // C++11/G++: Type Traits [Type-Traits.html in the GCC manual] diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index feea84544d62fb..76d5d1190a9643 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -322,8 +322,9 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { if (LangOpts.IEEE128) AddKeyword("__ieee128", tok::kw___float128, KEYALL, LangOpts, *this); - // Add the 'import' contextual keyword. + // Add the 'import' and 'module' contextual keyword. get("import").setModulesImport(true); + get("module").setModulesDecl(true); } /// Checks if the specified token kind represents a keyword in the diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp index 2ca2122ac71099..873a72cf9ba206 100644 --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -161,7 +161,8 @@ void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd, PushIncludeMacroStack(); CurDirLookup = nullptr; CurTokenLexer = std::move(TokLexer); - if (CurLexerCallback != CLK_LexAfterModuleImport) + if (CurLexerCallback != CLK_LexAfterModuleImport && + CurLexerCallback != CLK_LexAfterModuleDecl) CurLexerCallback = CLK_TokenLexer; } diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 0b70192743a399..b1571494f1e5f9 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -862,6 +862,14 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) { ModuleImportExpectsIdentifier = true; CurLexerCallback = CLK_LexAfterModuleImport; } + + if ((II.isModulesDecl() || + Identifier.is(tok::kw_module)) && + !InMacroArgs && !DisableMacroExpansion && + (getLangOpts().Modules || getLangOpts().DebuggerSupport) && + CurLexerCallback != CLK_CachingLexer) { + CurLexerCallback = CLK_LexAfterModuleDecl; + } return true; } @@ -942,6 +950,7 @@ void Preprocessor::Lex(Token &Result) { } else if (Result.getIdentifierInfo() == getIdentifierInfo("module")) { TrackGMFState.handleModule(StdCXXImportSeqState.afterTopLevelSeq()); ModuleDeclState.handleModule(); + CurLexerCallback = CLK_LexAfterModuleDecl; break; } } @@ -1329,6 +1338,42 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) { return true; } +/// Lex a token following the 'module' contextual keyword. +/// +/// [cpp.module]/p2: +/// The pp-tokens, if any, of a pp-module shall be of the form: +/// pp-module-name pp-module-partition[opt] pp-tokens[opt] +/// +/// where the pp-tokens (if any) shall not begin with a ( preprocessing token +/// and the grammar non-terminals are defined as: +/// pp-module-name: +/// pp-module-name-qualifierp[opt] identifier +/// pp-module-partition: +/// : pp-module-name-qualifier[opt] identifier +/// pp-module-name-qualifier: +/// identifier . +/// pp-module-name-qualifier identifier . +/// No identifier in the pp-module-name or pp-module-partition shall currently +/// be defined as an object-like macro. +/// +/// [cpp.module]/p3: +/// Any preprocessing tokens after the module preprocessing token in the module +/// directive are processed just as in normal text. +bool Preprocessor::LexAfterModuleDecl(Token &Result) { + // Figure out what kind of lexer we actually have. + recomputeCurLexerKind(); + LexUnexpandedToken(Result); + + // pp-module: + // export[opt] module pp-tokens[opt] ; new-line + // Processe tokens just as in normal text, until we see a ';', this means the + // end of the module directive. + if (!Result.is(tok::semi)) + CurLexerCallback = CLK_LexAfterModuleDecl; + + return true; +} + void Preprocessor::makeModuleVisible(Module *M, SourceLocation Loc) { CurSubmoduleState->VisibleModules.setVisible( M, Loc, [](Module *) {}, diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index ef66348a83125c..f1e35028e1ce6c 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2494,9 +2494,11 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) { return Actions.ActOnPrivateModuleFragmentDecl(ModuleLoc, PrivateLoc); } + bool HasError = false; SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; - if (ParseModuleName(ModuleLoc, Path, /*IsImport*/ false)) - return nullptr; + if (ParseModuleName(ModuleLoc, Path, /*IsImport=*/false, + /*IsPartition=*/false)) + HasError = true; // Parse the optional module-partition. SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition; @@ -2506,8 +2508,9 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) { Diag(ColonLoc, diag::err_unsupported_module_partition) << SourceRange(ColonLoc, Partition.back().second); // Recover by ignoring the partition name. - else if (ParseModuleName(ModuleLoc, Partition, /*IsImport*/ false)) - return nullptr; + else if (ParseModuleName(ModuleLoc, Partition, /*IsImport=*/false, + /*IsPartition=*/true)) + HasError = true; } // We don't support any module attributes yet; just parse them and diagnose. @@ -2520,8 +2523,9 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) { ExpectAndConsumeSemi(diag::err_module_expected_semi); - return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, Partition, - ImportState); + return HasError ? nullptr + : Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, + Partition, ImportState); } /// Parse a module import declaration. This is essentially the same for @@ -2571,12 +2575,14 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc, Diag(ColonLoc, diag::err_unsupported_module_partition) << SourceRange(ColonLoc, Path.back().second); // Recover by leaving partition empty. - else if (ParseModuleName(ColonLoc, Path, /*IsImport*/ true)) + else if (ParseModuleName(ColonLoc, Path, /*IsImport=*/true, + /*IsPartition=*/true)) return nullptr; else IsPartition = true; } else { - if (ParseModuleName(ImportLoc, Path, /*IsImport*/ true)) + if (ParseModuleName(ImportLoc, Path, /*IsImport=*/true, + /*IsPartition=*/false)) return nullptr; } @@ -2675,7 +2681,8 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc, bool Parser::ParseModuleName( SourceLocation UseLoc, SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path, - bool IsImport) { + bool IsImport, bool IsPartition) { + bool HasMacroInModuleName = false; // Parse the module path. while (true) { if (!Tok.is(tok::identifier)) { @@ -2686,25 +2693,30 @@ bool Parser::ParseModuleName( } Diag(Tok, diag::err_module_expected_ident) << IsImport; - SkipUntil(tok::semi); - return true; - } - - // P3034R1: Module Declarations Shouldn’t be Macros - if (!IsImport && Tok.getLocation().isMacroID()) { - Diag(Tok, diag::err_module_decl_cannot_be_macros); - SkipUntil(tok::semi); + SkipUntil(tok::semi, StopBeforeMatch); return true; } - // Record this part of the module path. - Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation())); + Token Identifier = Tok; ConsumeToken(); - if (Tok.isNot(tok::period)) - return false; + // P3034R1: Module Declarations Shouldn’t be Macros. + const auto *MI = PP.getMacroInfo(Identifier.getIdentifierInfo()); + if (!IsImport && MI) { + HasMacroInModuleName = true; + if (MI->isFunctionLike()) + SkipUntil(tok::r_paren, tok::period, tok::colon, StopAtSemi | StopBeforeMatch); + Diag(Identifier, diag::err_module_decl_cannot_be_macros) + << Identifier.getLocation() + << IsPartition << MI->isFunctionLike() + << Identifier.getIdentifierInfo(); + } else if (!HasMacroInModuleName) { + // Record this part of the module path. + Path.push_back(std::make_pair(Identifier.getIdentifierInfo(), Identifier.getLocation())); + } - ConsumeToken(); + if (!TryConsumeToken(tok::period)) + return HasMacroInModuleName; } } diff --git a/clang/test/CXX/cpp/cpp.module/p1.cppm b/clang/test/CXX/cpp/cpp.module/p1.cppm deleted file mode 100644 index b439366db3fba0..00000000000000 --- a/clang/test/CXX/cpp/cpp.module/p1.cppm +++ /dev/null @@ -1,13 +0,0 @@ -// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -triple x86_64-linux-gnu -DTEST=1 -verify -// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -triple x86_64-linux-gnu -DTEST=2 -verify - -module; -export module x; -#include "version.h" -#if TEST == 1 -export module VERSION; // expected-error {{module declaration cannot be a macro}} -#endif // TEST == 1 - -#if TEST == 2 -export module A.B; // expected-error {{module declaration cannot be a macro}} -#endif // TEST == 2 diff --git a/clang/test/CXX/cpp/cpp.module/p2.cppm b/clang/test/CXX/cpp/cpp.module/p2.cppm new file mode 100644 index 00000000000000..b75dfd7346211f --- /dev/null +++ b/clang/test/CXX/cpp/cpp.module/p2.cppm @@ -0,0 +1,46 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/A.cppm -triple x86_64-linux-gnu -verify +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/B.cppm -triple x86_64-linux-gnu -verify +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/C.cppm -triple x86_64-linux-gnu -verify +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/D.cppm -triple x86_64-linux-gnu -verify + +//--- version.h +#ifndef VERSION_H +#define VERSION_H + +#define VERSION libv5 +#define A a +#define B b +#define C c +#define FUNC_LIKE(X) function_like_##X + +#endif + +//--- A.cppm +export module x; +#include "version.h" +export module VERSION; // expected-error {{the name of a module declaration cannot contains an object-like macro 'VERSION'}} + +//--- B.cppm +export module x; +#include "version.h" +export module A.B; // expected-error {{the name of a module declaration cannot contains an object-like macro 'A'}} \ + // expected-error {{the name of a module declaration cannot contains an object-like macro 'B'}} + +//--- C.cppm +export module x; +#include "version.h" +export module A.FUNC_LIKE(foo):C; // expected-error {{the name of a module declaration cannot contains an object-like macro 'A'}} \ + // expected-error {{the name of a module declaration cannot contains a function-like macro 'FUNC_LIKE'}} \ + // expected-error {{the name of a module partition declaration cannot contains an object-like macro 'C'}} + +//--- D.cppm +export module x; +#include "version.h" +export module B.A.FUNC_LIKE(bar):C; // expected-error {{the name of a module declaration cannot contains an object-like macro 'B'}} \ + // expected-error {{the name of a module declaration cannot contains an object-like macro 'A'}} \ + // expected-error {{the name of a module declaration cannot contains a function-like macro 'FUNC_LIKE'}} \ + // expected-error {{the name of a module partition declaration cannot contains an object-like macro 'C'}} diff --git a/clang/test/CXX/cpp/cpp.module/version.h b/clang/test/CXX/cpp/cpp.module/version.h deleted file mode 100644 index 4608934290950b..00000000000000 --- a/clang/test/CXX/cpp/cpp.module/version.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef VERSION_H -#define VERSION_H - -#define VERSION libv5 -#define A a -#define B b - -#endif diff --git a/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm b/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm index 074589ccc26926..81c645a872d7aa 100644 --- a/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm +++ b/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm @@ -35,9 +35,9 @@ int use_3 = c; // expected-error {{use of undeclared identifier 'c'}} //--- test.cpp #ifdef INTERFACE -export module MODULE_NAME; // expected-error {{module declaration cannot be a macro}} +export module MODULE_NAME; // expected-error {{the name of a module declaration cannot contains an object-like macro 'MODULE_NAME'}} #else -module MODULE_NAME; // expected-error {{module declaration cannot be a macro}} +module MODULE_NAME; // expected-error {{the name of a module declaration cannot contains an object-like macro 'MODULE_NAME'}} #endif import x; diff --git a/clang/test/SemaCXX/modules.cppm b/clang/test/SemaCXX/modules.cppm index 75bbc5366d4a71..98c3ad3f4feff9 100644 --- a/clang/test/SemaCXX/modules.cppm +++ b/clang/test/SemaCXX/modules.cppm @@ -1,23 +1,17 @@ -// 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 -// expected-no-diagnostics -#endif - -#if TEST == 3 -// expected-error {{module declaration cannot be a macro}} -#endif // TEST == 3 +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/A.cppm -o %t.0.pcm -verify +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/B.cppm -o %t.1.pcm -verify +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/C.cppm -fmodule-file=foo=%t.0.pcm -o %t.2.pcm -verify +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/D.cppm -fmodule-file=foo=%t.0.pcm -o %t.3.pcm -verify +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/E.cppm -fmodule-file=foo=%t.0.pcm -o %t.3.pcm -verify -Dfoo=bar +//--- A.cppm export module foo; - static int m; - int n; - -#if TEST == 0 export { int a; int b; @@ -31,7 +25,43 @@ export void f() {} export struct T { } t; -#elif TEST == 3 +// expected-no-diagnostics + +//--- B.cppm +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 + } +} + +//--- C.cppm +export module foo; +static int m; +int n; +// expected-no-diagnostics + +//--- D.cppm +export module foo; +static int m; +int n; int use_a = a; // expected-error {{use of undeclared identifier 'a'}} #undef foo @@ -50,29 +80,14 @@ 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 +//--- E.cppm +export module foo; // expected-error {{the name of a module declaration cannot contains an object-like macro 'foo'}} +static int m; +int n; +int use_a = a; // expected-error {{use of undeclared identifier 'a'}} -// FIXME: Exports of declarations without external linkage are disallowed. -// Exports of declarations with non-external-linkage types are disallowed. +#undef foo +import foo; -// 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 +export {} // expected-error {{export declaration can only be used within a module purview}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits