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/8] =?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/8] 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}} >From fd75d83d8d9c1ea3e30ccf2c4646667f50c0c490 Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Fri, 3 May 2024 20:07:49 +0800 Subject: [PATCH 3/8] Format Signed-off-by: yronglin <yronglin...@gmail.com> --- clang/include/clang/Basic/IdentifierTable.h | 6 +++--- clang/lib/Lex/Preprocessor.cpp | 5 ++--- clang/lib/Parse/Parser.cpp | 11 ++++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index 5bbb9219552b62..645f7ae913fa3a 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -215,9 +215,9 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo { IsFutureCompatKeyword(false), IsPoisoned(false), IsCPPOperatorKeyword(false), NeedsHandleIdentifier(false), IsFromAST(false), ChangedAfterLoad(false), FEChangedAfterLoad(false), - RevertedTokenID(false), OutOfDate(false), IsModulesImport(false), IsModulesDecl(false), - IsMangledOpenMPVariantName(false), IsDeprecatedMacro(false), - IsRestrictExpansion(false), IsFinal(false) {} + RevertedTokenID(false), OutOfDate(false), IsModulesImport(false), + IsModulesDecl(false), IsMangledOpenMPVariantName(false), + IsDeprecatedMacro(false), IsRestrictExpansion(false), IsFinal(false) {} public: IdentifierInfo(const IdentifierInfo &) = delete; diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index b1571494f1e5f9..5982c9a72d93e9 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -863,9 +863,8 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) { CurLexerCallback = CLK_LexAfterModuleImport; } - if ((II.isModulesDecl() || - Identifier.is(tok::kw_module)) && - !InMacroArgs && !DisableMacroExpansion && + if ((II.isModulesDecl() || Identifier.is(tok::kw_module)) && !InMacroArgs && + !DisableMacroExpansion && (getLangOpts().Modules || getLangOpts().DebuggerSupport) && CurLexerCallback != CLK_CachingLexer) { CurLexerCallback = CLK_LexAfterModuleDecl; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index f1e35028e1ce6c..2c45e037a1a90c 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2705,14 +2705,15 @@ bool Parser::ParseModuleName( if (!IsImport && MI) { HasMacroInModuleName = true; if (MI->isFunctionLike()) - SkipUntil(tok::r_paren, tok::period, tok::colon, StopAtSemi | StopBeforeMatch); + 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(); + << 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())); + Path.push_back(std::make_pair(Identifier.getIdentifierInfo(), + Identifier.getLocation())); } if (!TryConsumeToken(tok::period)) >From 265189b67d63f7322be08eaf6b4e0ff5fb9b03a3 Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Fri, 3 May 2024 21:30:03 +0800 Subject: [PATCH 4/8] Do not treat no '(' following function-like macro as a macro name Signed-off-by: yronglin <yronglin...@gmail.com> --- .../clang/Basic/DiagnosticParseKinds.td | 3 +- clang/lib/Parse/Parser.cpp | 17 ++++-- clang/test/CXX/cpp/cpp.module/p2.cppm | 26 ++++++---- .../basic/basic.link/module-declaration.cpp | 52 +++++++++---------- .../dcl.module/dcl.module.import/p1.cppm | 4 +- clang/test/SemaCXX/modules.cppm | 2 +- 6 files changed, 58 insertions(+), 46 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 6e3223187b699a..02a66b4c87e121 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1672,7 +1672,8 @@ 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< - "the name of a module%select{| partition}0 declaration cannot contains %select{an object-like|a function-like}1 macro %2">; + "the name of a module%select{| partition}0 declaration cannot contains " + "%select{an object-like|a function-like}1 macro %2, and the macro will not expand">; 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 2c45e037a1a90c..2923ac720a6684 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2701,15 +2701,24 @@ bool Parser::ParseModuleName( ConsumeToken(); // P3034R1: Module Declarations Shouldn’t be Macros. + // The function-like macro are only replaced when a '(' follows. + // Therefore, if no '(' following, it's will not treated as a macro + // name, and it's a valid module name. const auto *MI = PP.getMacroInfo(Identifier.getIdentifierInfo()); - if (!IsImport && MI) { + if (!IsImport && MI && + (MI->isObjectLike() || + (MI->isFunctionLike() && Tok.is(tok::l_paren)))) { HasMacroInModuleName = true; - if (MI->isFunctionLike()) + SourceLocation StartLoc = Identifier.getLocation(); + SourceLocation EndLoc = Identifier.getLocation(); + if (MI->isFunctionLike()) { SkipUntil(tok::r_paren, tok::period, tok::colon, StopAtSemi | StopBeforeMatch); + EndLoc = PrevTokLocation; + } Diag(Identifier, diag::err_module_decl_cannot_be_macros) - << Identifier.getLocation() << IsPartition << MI->isFunctionLike() - << Identifier.getIdentifierInfo(); + << SourceRange(StartLoc, EndLoc) << IsPartition + << MI->isFunctionLike() << Identifier.getIdentifierInfo(); } else if (!HasMacroInModuleName) { // Record this part of the module path. Path.push_back(std::make_pair(Identifier.getIdentifierInfo(), diff --git a/clang/test/CXX/cpp/cpp.module/p2.cppm b/clang/test/CXX/cpp/cpp.module/p2.cppm index b75dfd7346211f..a94451ae6dfbaa 100644 --- a/clang/test/CXX/cpp/cpp.module/p2.cppm +++ b/clang/test/CXX/cpp/cpp.module/p2.cppm @@ -22,25 +22,31 @@ //--- 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'}} +export module VERSION; // expected-error {{the name of a module declaration cannot contains an object-like macro 'VERSION', and the macro will not expand}} //--- 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'}} +export module A.B; // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand}} \ + // expected-error {{the name of a module declaration cannot contains an object-like macro 'B', and the macro will not expand}} //--- 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'}} +export module A.FUNC_LIKE(foo):C; // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand}} \ + // expected-error {{the name of a module declaration cannot contains a function-like macro 'FUNC_LIKE', and the macro will not expand}} \ + // expected-error {{the name of a module partition declaration cannot contains an object-like macro 'C', and the macro will not expand}} //--- 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'}} +export module B.A.FUNC_LIKE(bar):C; // expected-error {{the name of a module declaration cannot contains an object-like macro 'B', and the macro will not expand}} \ + // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand}} \ + // expected-error {{the name of a module declaration cannot contains a function-like macro 'FUNC_LIKE', and the macro will not expand}} \ + // expected-error {{the name of a module partition declaration cannot contains an object-like macro 'C', and the macro will not expand}} + +//--- E.cppm +export module x; +#include "version.h" +export module a.FUNC_LIKE:c // OK, FUNC_LIKE would not be treated as a macro name. +// expected-no-diagnostics \ No newline at end of file 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 aa4bb52a57face..14bbc911febfcd 100644 --- a/clang/test/CXX/module/basic/basic.link/module-declaration.cpp +++ b/clang/test/CXX/module/basic/basic.link/module-declaration.cpp @@ -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 -// 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 +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify -x c++ %t/M1.cpp +// 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/M2.cpp // // 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 -// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \ -// RUN: -DTEST=4 +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M3.cpp +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M4.cpp // // 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 -// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \ -// 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 -// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \ -// RUN: -DTEST=10 +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M5.cpp +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M6.cpp +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M7.cpp +// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M8.cpp //--- x.cppm export module x; @@ -38,22 +30,26 @@ int a, b; export module x.y; int c; -//--- M.cpp - -#if TEST == 1 +//--- M1.cpp module z; // expected-error {{module 'z' not found}} -#elif TEST == 2 + +//--- M2.cpp module x; // expected-no-diagnostics -#elif TEST == 3 + +//--- M3.cpp export module z; // expected-no-diagnostics -#elif TEST == 4 + +//--- M4.cpp export module x; // expected-no-diagnostics -#elif TEST == 7 + +//--- M5.cpp export module z elderberry; // expected-error {{expected ';'}} expected-error {{a type specifier is required}} -#elif TEST == 9 + +//--- M6.cpp +export module z [[]]; // expected-no-diagnostics + +//--- M7.cpp export module z [[fancy]]; // expected-warning {{unknown attribute 'fancy' ignored}} -#elif TEST == 10 + +//--- M8.cpp 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 81c645a872d7aa..860ac3d2894e03 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 {{the name of a module declaration cannot contains an object-like macro 'MODULE_NAME'}} +export module MODULE_NAME; // expected-error {{the name of a module declaration cannot contains an object-like macro 'MODULE_NAME', and the macro will not expand}} #else -module MODULE_NAME; // expected-error {{the name of a module declaration cannot contains an object-like macro 'MODULE_NAME'}} +module MODULE_NAME; // expected-error {{the name of a module declaration cannot contains an object-like macro 'MODULE_NAME', and the macro will not expand}} #endif import x; diff --git a/clang/test/SemaCXX/modules.cppm b/clang/test/SemaCXX/modules.cppm index 98c3ad3f4feff9..c0082d51500691 100644 --- a/clang/test/SemaCXX/modules.cppm +++ b/clang/test/SemaCXX/modules.cppm @@ -82,7 +82,7 @@ extern int n; static_assert(&n != p); // expected-error{{use of undeclared identifier 'p'}} //--- E.cppm -export module foo; // expected-error {{the name of a module declaration cannot contains an object-like macro 'foo'}} +export module foo; // expected-error {{the name of a module declaration cannot contains an object-like macro 'foo', and the macro will not expand}} static int m; int n; int use_a = a; // expected-error {{use of undeclared identifier 'a'}} >From 611e1d8b177599957439d3046a60c09ab039a4c9 Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Fri, 3 May 2024 22:44:11 +0800 Subject: [PATCH 5/8] Add new line at the end of file Signed-off-by: yronglin <yronglin...@gmail.com> --- clang/test/CXX/cpp/cpp.module/p2.cppm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CXX/cpp/cpp.module/p2.cppm b/clang/test/CXX/cpp/cpp.module/p2.cppm index a94451ae6dfbaa..c966b966cd08b7 100644 --- a/clang/test/CXX/cpp/cpp.module/p2.cppm +++ b/clang/test/CXX/cpp/cpp.module/p2.cppm @@ -49,4 +49,4 @@ export module B.A.FUNC_LIKE(bar):C; // expected-error {{the name of a module d export module x; #include "version.h" export module a.FUNC_LIKE:c // OK, FUNC_LIKE would not be treated as a macro name. -// expected-no-diagnostics \ No newline at end of file +// expected-no-diagnostics >From 224e1d0c5379e7a7c0226a8c2155c34cc5b26905 Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Tue, 7 May 2024 01:05:12 +0800 Subject: [PATCH 6/8] Move implementation to Preprocessor Signed-off-by: yronglin <yronglin...@gmail.com> --- .../include/clang/Basic/DiagnosticLexKinds.td | 6 + .../clang/Basic/DiagnosticParseKinds.td | 3 - clang/include/clang/Lex/Preprocessor.h | 7 ++ clang/include/clang/Parse/Parser.h | 2 +- clang/lib/Lex/Preprocessor.cpp | 109 +++++++++++++++++- clang/lib/Parse/Parser.cpp | 46 ++------ clang/test/CXX/cpp/cpp.module/p2.cppm | 60 +++++++--- 7 files changed, 172 insertions(+), 61 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index ad6bacfb118d49..25c44bdac67312 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -932,6 +932,12 @@ def warn_module_conflict : Warning< InGroup<ModuleConflict>; // C++20 modules +def err_module_decl_cannot_be_macros : Error< + "the name of a module%select{| partition}0 declaration cannot contains " + "an object-like macro %1, and the macro will not expand" + "%select{|; did you mean '%3'?}2">; +def err_unxepected_paren_in_module_decl : Error< + "unexpected '(' after the name of a module%select{| partition}0 declaration">; def err_header_import_semi_in_macro : Error< "semicolon terminating header import declaration cannot be produced " "by a macro">; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 02a66b4c87e121..fdffb35ea0d955 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1671,9 +1671,6 @@ 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< - "the name of a module%select{| partition}0 declaration cannot contains " - "%select{an object-like|a function-like}1 macro %2, and the macro will not expand">; 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/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index ef2dba7177e1e5..42442f08886b13 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -609,6 +609,13 @@ class Preprocessor { /// it expects a '.' or ';'. bool ModuleImportExpectsIdentifier = false; + /// Whether the module declaration expects an identifier next. Otherwise, + /// it expects a '.' or ';'. + bool ModuleDeclExpectsIdentifier = false; + + /// Whether lexing the name of module partition declaration. + bool ModuleDeclLexingPartitionName = false; + /// The identifier and source location of the currently-active /// \#pragma clang arc_cf_code_audited begin. std::pair<IdentifierInfo *, SourceLocation> PragmaARCCFCodeAuditedInfo; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index c37348cc33461c..daefd4f28f011a 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3812,7 +3812,7 @@ class Parser : public CodeCompletionHandler { bool ParseModuleName( SourceLocation UseLoc, SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path, - bool IsImport, bool IsPartition); + bool IsImport); //===--------------------------------------------------------------------===// // C++11/G++: Type Traits [Type-Traits.html in the GCC manual] diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 5982c9a72d93e9..25ca8ebadf056c 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -55,6 +55,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -867,6 +868,8 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) { !DisableMacroExpansion && (getLangOpts().Modules || getLangOpts().DebuggerSupport) && CurLexerCallback != CLK_CachingLexer) { + ModuleDeclExpectsIdentifier = true; + ModuleDeclLexingPartitionName = false; CurLexerCallback = CLK_LexAfterModuleDecl; } return true; @@ -949,6 +952,8 @@ void Preprocessor::Lex(Token &Result) { } else if (Result.getIdentifierInfo() == getIdentifierInfo("module")) { TrackGMFState.handleModule(StdCXXImportSeqState.afterTopLevelSeq()); ModuleDeclState.handleModule(); + ModuleDeclExpectsIdentifier = true; + ModuleDeclLexingPartitionName = false; CurLexerCallback = CLK_LexAfterModuleDecl; break; } @@ -1363,12 +1368,99 @@ bool Preprocessor::LexAfterModuleDecl(Token &Result) { 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)) + auto EnterTokens = [this](ArrayRef<Token> Toks, bool DisableMacroExpansion) { + auto ToksCopy = std::make_unique<Token[]>(Toks.size()); + std::copy(Toks.begin(), Toks.end(), ToksCopy.get()); + EnterTokenStream(std::move(ToksCopy), Toks.size(), DisableMacroExpansion, + /*IsReinject=*/false); + }; + + // If we not expect an identifier but got an identifier, it's not a part of + // module name. + if (!ModuleDeclExpectsIdentifier && Result.is(tok::identifier)) { + EnterTokens(Result, /*DisableMacroExpansion=*/false); + return false; + } + + // The token sequence + // + // export[opt] module identifier (. identifier)* + // + // indicates a module import directive. We already saw the 'module' + // contextual keyword, so now we're looking for the identifiers. + if (ModuleDeclExpectsIdentifier && Result.is(tok::identifier)) { + auto *MI = getMacroInfo(Result.getIdentifierInfo()); + if (MI && MI->isObjectLike()) { + auto BuildFixItHint = + [&](std::string &Replacement) -> std::optional<FixItHint> { + EnterTokens(Result, /*DisableMacroExpansion=*/false); + if (!CurTokenLexer) + return std::nullopt; + Token Tok; + bool HasUnknownToken = false; + llvm::raw_string_ostream OS(Replacement); + do { + Lex(Tok); + if (const char *Punc = tok::getPunctuatorSpelling(Tok.getKind())) + OS << Punc; + else if (Tok.isLiteral() && Tok.getLiteralData()) + OS << StringRef(Tok.getLiteralData(), Tok.getLength()); + else if (auto *II = Tok.getIdentifierInfo()) + OS << II->getName(); + else + HasUnknownToken = true; + } while (CurTokenLexer && !CurTokenLexer->isAtEnd()); + if (HasUnknownToken) + return std::nullopt; + return FixItHint::CreateReplacement(Result.getLocation(), Replacement); + }; + SourceLocation EndLoc = Result.getLocation(); + std::string Replacement; + auto FixIt = BuildFixItHint(Replacement); + auto DB = Diag(Result, diag::err_module_decl_cannot_be_macros) + << SourceRange(Result.getLocation(), EndLoc) + << ModuleDeclLexingPartitionName << Result.getIdentifierInfo() + << FixIt.has_value(); + if (FixIt) + DB << Replacement << *FixIt; + } + ModuleDeclExpectsIdentifier = false; + CurLexerCallback = CLK_LexAfterModuleDecl; + return true; + } + + // If we're expecting a '.', a ':' or a ';', and we got a '.', then wait until + // we see the next identifier. + if (!ModuleDeclExpectsIdentifier && Result.isOneOf(tok::period, tok::colon)) { + ModuleDeclExpectsIdentifier = true; + ModuleDeclLexingPartitionName = Result.is(tok::colon); + CurLexerCallback = CLK_LexAfterModuleDecl; + return true; + } + + // [cpp.module]/p2: where the pp-tokens (if any) shall not begin with a ( + // preprocessing token [...] + if (!ModuleDeclExpectsIdentifier && Result.is(tok::l_paren)) { + ModuleDeclExpectsIdentifier = false; + Diag(Result, diag::err_unxepected_paren_in_module_decl) + << ModuleDeclLexingPartitionName; + Token Tok; + // We already have a '('. + unsigned NumParens = 1; + while (true) { + LexUnexpandedToken(Tok); + if (Tok.isOneOf(tok::eod, tok::eof, tok::semi, tok::period, tok::colon)) { + EnterTokens(Tok, /*DisableMacroExpansion=*/true); + break; + } + if (Tok.is(tok::l_paren)) + NumParens++; + else if (Tok.is(tok::r_paren) && --NumParens == 0) + break; + } CurLexerCallback = CLK_LexAfterModuleDecl; + return false; + } return true; } @@ -1626,3 +1718,10 @@ const char *Preprocessor::getCheckPoint(FileID FID, const char *Start) const { return nullptr; } + +#if 0 +def err_module_decl_cannot_be_macros : Error< + "the name of a module%select{| partition}0 declaration cannot contains " + "%select{an object-like|a function-like}1 macro %2, and the macro will not expand" + "%select{|; did you mean '%4'?}3">; +#endif \ No newline at end of file diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 2923ac720a6684..af4409ef86bcb3 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2496,10 +2496,8 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) { bool HasError = false; SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; - if (ParseModuleName(ModuleLoc, Path, /*IsImport=*/false, - /*IsPartition=*/false)) + if (ParseModuleName(ModuleLoc, Path, /*IsImport=*/false)) HasError = true; - // Parse the optional module-partition. SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition; if (Tok.is(tok::colon)) { @@ -2508,8 +2506,7 @@ 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, - /*IsPartition=*/true)) + else if (ParseModuleName(ModuleLoc, Partition, /*IsImport=*/false)) HasError = true; } @@ -2575,14 +2572,12 @@ 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, - /*IsPartition=*/true)) + else if (ParseModuleName(ColonLoc, Path, /*IsImport=*/true)) return nullptr; else IsPartition = true; } else { - if (ParseModuleName(ImportLoc, Path, /*IsImport=*/true, - /*IsPartition=*/false)) + if (ParseModuleName(ImportLoc, Path, /*IsImport=*/true)) return nullptr; } @@ -2681,7 +2676,7 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc, bool Parser::ParseModuleName( SourceLocation UseLoc, SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path, - bool IsImport, bool IsPartition) { + bool IsImport) { bool HasMacroInModuleName = false; // Parse the module path. while (true) { @@ -2697,33 +2692,12 @@ bool Parser::ParseModuleName( return true; } - Token Identifier = Tok; - ConsumeToken(); + const auto *MI = PP.getMacroInfo(Tok.getIdentifierInfo()); + HasMacroInModuleName = !IsImport && MI && MI->isObjectLike(); - // P3034R1: Module Declarations Shouldn’t be Macros. - // The function-like macro are only replaced when a '(' follows. - // Therefore, if no '(' following, it's will not treated as a macro - // name, and it's a valid module name. - const auto *MI = PP.getMacroInfo(Identifier.getIdentifierInfo()); - if (!IsImport && MI && - (MI->isObjectLike() || - (MI->isFunctionLike() && Tok.is(tok::l_paren)))) { - HasMacroInModuleName = true; - SourceLocation StartLoc = Identifier.getLocation(); - SourceLocation EndLoc = Identifier.getLocation(); - if (MI->isFunctionLike()) { - SkipUntil(tok::r_paren, tok::period, tok::colon, - StopAtSemi | StopBeforeMatch); - EndLoc = PrevTokLocation; - } - Diag(Identifier, diag::err_module_decl_cannot_be_macros) - << SourceRange(StartLoc, EndLoc) << 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())); - } + // Record this part of the module path. + Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation())); + ConsumeToken(); if (!TryConsumeToken(tok::period)) return HasMacroInModuleName; diff --git a/clang/test/CXX/cpp/cpp.module/p2.cppm b/clang/test/CXX/cpp/cpp.module/p2.cppm index c966b966cd08b7..c13d9f1eee29dc 100644 --- a/clang/test/CXX/cpp/cpp.module/p2.cppm +++ b/clang/test/CXX/cpp/cpp.module/p2.cppm @@ -2,10 +2,15 @@ // 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 +// RUN: %clang_cc1 -std=c++20 %t/A.cppm -triple x86_64-linux-gnu -verify +// RUN: %clang_cc1 -std=c++20 %t/B.cppm -triple x86_64-linux-gnu -verify +// RUN: %clang_cc1 -std=c++20 %t/C.cppm -triple x86_64-linux-gnu -verify +// RUN: %clang_cc1 -std=c++20 %t/D.cppm -triple x86_64-linux-gnu -verify +// RUN: %clang_cc1 -std=c++20 %t/E.cppm -triple x86_64-linux-gnu -verify +// RUN: %clang_cc1 -std=c++20 %t/F.cppm -triple x86_64-linux-gnu -verify +// RUN: %clang_cc1 -std=c++20 %t/G.cppm -triple x86_64-linux-gnu -verify +// RUN: %clang_cc1 -std=c++20 %t/H.cppm -triple x86_64-linux-gnu -verify +// RUN: %clang_cc1 -std=c++20 %t/I.cppm -triple x86_64-linux-gnu -verify //--- version.h #ifndef VERSION_H @@ -16,37 +21,60 @@ #define B b #define C c #define FUNC_LIKE(X) function_like_##X +#define ATTR [[]] #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', and the macro will not expand}} //--- 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', and the macro will not expand}} \ // expected-error {{the name of a module declaration cannot contains an object-like macro 'B', and the macro will not expand}} //--- 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', and the macro will not expand}} \ - // expected-error {{the name of a module declaration cannot contains a function-like macro 'FUNC_LIKE', and the macro will not expand}} \ +export module A.FUNC_LIKE(foo):C; // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand; did you mean 'a'?}} \ + // expected-error {{unexpected '(' after the name of a module declaration}} \ // expected-error {{the name of a module partition declaration cannot contains an object-like macro 'C', and the macro will not expand}} //--- 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', and the macro will not expand}} \ - // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand}} \ - // expected-error {{the name of a module declaration cannot contains a function-like macro 'FUNC_LIKE', and the macro will not expand}} \ - // expected-error {{the name of a module partition declaration cannot contains an object-like macro 'C', and the macro will not expand}} +export module B.A.FUNC_LIKE(bar):C; // expected-error {{the name of a module declaration cannot contains an object-like macro 'B', and the macro will not expand; did you mean 'b'?}} \ + // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand; did you mean 'a'?}} \ + // expected-error {{unexpected '(' after the name of a module declaration}} \ + // expected-error {{the name of a module partition declaration cannot contains an object-like macro 'C', and the macro will not expand; did you mean 'c'?}} //--- E.cppm -export module x; #include "version.h" -export module a.FUNC_LIKE:c // OK, FUNC_LIKE would not be treated as a macro name. +export module a.FUNC_LIKE:c; // OK, FUNC_LIKE would not be treated as a macro name. // expected-no-diagnostics + +//--- F.cppm +#include "version.h" +export module a.FUNC_LIKE:c ATTR; // OK, FUNC_LIKE would not be treated as a macro name. +// expected-no-diagnostics + +//--- G.cppm +#include "version.h" +export module A.FUNC_LIKE(B c:C ATTR // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand; did you mean 'a'?}} \ + // expected-error {{unexpected '(' after the name of a module declaration}} \ + // expected-error {{the name of a module partition declaration cannot contains an object-like macro 'C', and the macro will not expand; did you mean 'c'?}} \ + // expected-error {{expected ';' after module name}} + +//--- H.cppm +#include "version.h" +export module A.FUNC_LIKE(B,). c:C ATTR // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand; did you mean 'a'?}} \ + // expected-error {{unexpected '(' after the name of a module declaration}} \ + // expected-error {{the name of a module partition declaration cannot contains an object-like macro 'C', and the macro will not expand; did you mean 'c'?}} \ + // expected-error {{expected ';' after module name}} + +//--- I.cppm +#include "version.h" +export module A.FUNC_LIKE(B,) c:C ATTR // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand; did you mean 'a'?}} \ + // expected-error {{unexpected '(' after the name of a module declaration}} \ + // expected-error {{expected ';' after module name}} \ + // expected-error {{unknown type name 'c'}} \ + // expected-error {{expected unqualified-id}} >From 8ff13ca6728c4b7acd94cae0aa8f64e9d2219c62 Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Tue, 7 May 2024 01:11:28 +0800 Subject: [PATCH 7/8] Remove dead code Signed-off-by: yronglin <yronglin...@gmail.com> --- clang/lib/Lex/Preprocessor.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 25ca8ebadf056c..b23cfe8ec345ea 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -55,7 +55,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -1718,10 +1717,3 @@ const char *Preprocessor::getCheckPoint(FileID FID, const char *Start) const { return nullptr; } - -#if 0 -def err_module_decl_cannot_be_macros : Error< - "the name of a module%select{| partition}0 declaration cannot contains " - "%select{an object-like|a function-like}1 macro %2, and the macro will not expand" - "%select{|; did you mean '%4'?}3">; -#endif \ No newline at end of file >From bb4a9233d275a3e6458abb35761fb704f508c19d Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Tue, 7 May 2024 01:39:44 +0800 Subject: [PATCH 8/8] Add more test Signed-off-by: yronglin <yronglin...@gmail.com> --- clang/test/CXX/cpp/cpp.module/p2.cppm | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/clang/test/CXX/cpp/cpp.module/p2.cppm b/clang/test/CXX/cpp/cpp.module/p2.cppm index c13d9f1eee29dc..76de2ada5584fc 100644 --- a/clang/test/CXX/cpp/cpp.module/p2.cppm +++ b/clang/test/CXX/cpp/cpp.module/p2.cppm @@ -11,6 +11,7 @@ // RUN: %clang_cc1 -std=c++20 %t/G.cppm -triple x86_64-linux-gnu -verify // RUN: %clang_cc1 -std=c++20 %t/H.cppm -triple x86_64-linux-gnu -verify // RUN: %clang_cc1 -std=c++20 %t/I.cppm -triple x86_64-linux-gnu -verify +// RUN: %clang_cc1 -std=c++20 %t/J.cppm -triple x86_64-linux-gnu -verify //--- version.h #ifndef VERSION_H @@ -22,6 +23,7 @@ #define C c #define FUNC_LIKE(X) function_like_##X #define ATTR [[]] +#define SEMICOLON ; #endif @@ -54,27 +56,32 @@ export module a.FUNC_LIKE:c; // OK, FUNC_LIKE would not be treated as a macro na //--- F.cppm #include "version.h" -export module a.FUNC_LIKE:c ATTR; // OK, FUNC_LIKE would not be treated as a macro name. +export module a.FUNC_LIKE:c ATTRS; // OK, FUNC_LIKE would not be treated as a macro name. // expected-no-diagnostics //--- G.cppm #include "version.h" -export module A.FUNC_LIKE(B c:C ATTR // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand; did you mean 'a'?}} \ +export module A.FUNC_LIKE(B c:C ATTRS // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand; did you mean 'a'?}} \ // expected-error {{unexpected '(' after the name of a module declaration}} \ // expected-error {{the name of a module partition declaration cannot contains an object-like macro 'C', and the macro will not expand; did you mean 'c'?}} \ // expected-error {{expected ';' after module name}} //--- H.cppm #include "version.h" -export module A.FUNC_LIKE(B,). c:C ATTR // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand; did you mean 'a'?}} \ +export module A.FUNC_LIKE(B,). c:C ATTRS // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand; did you mean 'a'?}} \ // expected-error {{unexpected '(' after the name of a module declaration}} \ // expected-error {{the name of a module partition declaration cannot contains an object-like macro 'C', and the macro will not expand; did you mean 'c'?}} \ // expected-error {{expected ';' after module name}} //--- I.cppm #include "version.h" -export module A.FUNC_LIKE(B,) c:C ATTR // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand; did you mean 'a'?}} \ +export module A.FUNC_LIKE(B,) c:C ATTRS // expected-error {{the name of a module declaration cannot contains an object-like macro 'A', and the macro will not expand; did you mean 'a'?}} \ // expected-error {{unexpected '(' after the name of a module declaration}} \ // expected-error {{expected ';' after module name}} \ // expected-error {{unknown type name 'c'}} \ // expected-error {{expected unqualified-id}} + +//--- J.cppm +#include "version.h" +export module unexpanded : unexpanded ATTRS SEMICOLON // OK, ATTRS and SEMICOLON can be expanded. +// expected-no-diagnostics _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits