[clang] [Clang] Implement P3034R1 Module Declarations Shouldn’t be Macros (PR #90574)
via cfe-commits
cfe-commits at lists.llvm.org
Wed May 29 16:13:58 PDT 2024
https://github.com/yronglin updated https://github.com/llvm/llvm-project/pull/90574
>From 1dcb4c3ac1efaf3a6a4317751e23089a6c8ccac1 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Tue, 30 Apr 2024 17:18:26 +0800
Subject: [PATCH 01/12] =?UTF-8?q?[Clang]=20Implement=20P3034R1=20Module=20?=
=?UTF-8?q?Declarations=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 <yronglin777 at 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 1abc00a25f1f4..40c6bd63e9948 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 fdffb35ea0d95..0d4b526ec6d15 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 adcbe5858bc78..ef66348a83125 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 0000000000000..b439366db3fba
--- /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 0000000000000..4608934290950
--- /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 d71358cc7a571..aa4bb52a57fac 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 at -2 {{expected ';'}} expected-error at -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 at -4 {{unknown attribute 'fancy' ignored}}
+export module z [[fancy]]; // expected-warning {{unknown attribute 'fancy' ignored}}
#elif TEST == 10
-// expected-error-re at -6 {{'maybe_unused' attribute cannot be applied to a module{{$}}}}
-#elif TEST == 1
-// expected-error at -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 873e4c0edeac2..074589ccc2692 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 41204be76eafa..75bbc5366d4a7 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 0996abc240585..8ae9a25caf360 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 <yronglin777 at gmail.com>
Date: Fri, 3 May 2024 20:06:55 +0800
Subject: [PATCH 02/12] Use split-file in test and improve implementation
Signed-off-by: yronglin <yronglin777 at 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 0d4b526ec6d15..6e3223187b699 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 a893e6f4d3d39..5bbb9219552b6 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 e89b4a2c5230e..ef2dba7177e1e 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 81aab8c888ab6..1b429cebde508 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 feea84544d62f..76d5d1190a964 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 2ca2122ac7109..873a72cf9ba20 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 0b70192743a39..b1571494f1e5f 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 ef66348a83125..f1e35028e1ce6 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 b439366db3fba..0000000000000
--- 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 0000000000000..b75dfd7346211
--- /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 4608934290950..0000000000000
--- 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 074589ccc2692..81c645a872d7a 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 75bbc5366d4a7..98c3ad3f4feff 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 <yronglin777 at gmail.com>
Date: Fri, 3 May 2024 20:07:49 +0800
Subject: [PATCH 03/12] Format
Signed-off-by: yronglin <yronglin777 at 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 5bbb9219552b6..645f7ae913fa3 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 b1571494f1e5f..5982c9a72d93e 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 f1e35028e1ce6..2c45e037a1a90 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 <yronglin777 at gmail.com>
Date: Fri, 3 May 2024 21:30:03 +0800
Subject: [PATCH 04/12] Do not treat no '(' following function-like macro as a
macro name
Signed-off-by: yronglin <yronglin777 at 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 6e3223187b699..02a66b4c87e12 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 2c45e037a1a90..2923ac720a668 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 b75dfd7346211..a94451ae6dfba 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 aa4bb52a57fac..14bbc911febfc 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 81c645a872d7a..860ac3d2894e0 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 98c3ad3f4feff..c0082d5150069 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 <yronglin777 at gmail.com>
Date: Fri, 3 May 2024 22:44:11 +0800
Subject: [PATCH 05/12] Add new line at the end of file
Signed-off-by: yronglin <yronglin777 at 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 a94451ae6dfba..c966b966cd08b 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 <yronglin777 at gmail.com>
Date: Tue, 7 May 2024 01:05:12 +0800
Subject: [PATCH 06/12] Move implementation to Preprocessor
Signed-off-by: yronglin <yronglin777 at 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 ad6bacfb118d4..25c44bdac6731 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 02a66b4c87e12..fdffb35ea0d95 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 ef2dba7177e1e..42442f08886b1 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 c37348cc33461..daefd4f28f011 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 5982c9a72d93e..25ca8ebadf056 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 2923ac720a668..af4409ef86bcb 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 c966b966cd08b..c13d9f1eee29d 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 <yronglin777 at gmail.com>
Date: Tue, 7 May 2024 01:11:28 +0800
Subject: [PATCH 07/12] Remove dead code
Signed-off-by: yronglin <yronglin777 at 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 25ca8ebadf056..b23cfe8ec345e 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 <yronglin777 at gmail.com>
Date: Tue, 7 May 2024 01:39:44 +0800
Subject: [PATCH 08/12] Add more test
Signed-off-by: yronglin <yronglin777 at 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 c13d9f1eee29d..76de2ada5584f 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
>From 597b6a184c7b4dbbe5419e5dfaf737f5c52962a8 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Tue, 7 May 2024 01:43:49 +0800
Subject: [PATCH 09/12] Fix test
Signed-off-by: yronglin <yronglin777 at 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 76de2ada5584f..f21c891fe811b 100644
--- a/clang/test/CXX/cpp/cpp.module/p2.cppm
+++ b/clang/test/CXX/cpp/cpp.module/p2.cppm
@@ -22,7 +22,7 @@
#define B b
#define C c
#define FUNC_LIKE(X) function_like_##X
-#define ATTR [[]]
+#define ATTRS [[]]
#define SEMICOLON ;
#endif
>From b3e843bea7f5dcadaeb6b6591696dfa23d4463bb Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Thu, 9 May 2024 00:44:36 +0800
Subject: [PATCH 10/12] Address review comments
Signed-off-by: yronglin <yronglin777 at gmail.com>
---
.../include/clang/Basic/DiagnosticLexKinds.td | 8 ++--
clang/lib/Lex/Preprocessor.cpp | 39 ++-------------
clang/lib/Parse/Parser.cpp | 16 ++-----
clang/test/CXX/cpp/cpp.module/p2.cppm | 48 +++++++++++--------
.../dcl.module/dcl.module.import/p1.cppm | 39 +++++++++++----
clang/test/SemaCXX/modules.cppm | 6 +--
6 files changed, 75 insertions(+), 81 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 25c44bdac6731..6401d1c20b32c 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -933,11 +933,11 @@ def warn_module_conflict : Warning<
// 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">;
+ "the module name in a module%select{| partition}0 declaration cannot contain "
+ "an object-like macro %1, it's consists of one or more identifiers "
+ "separated by '.'">;
def err_unxepected_paren_in_module_decl : Error<
- "unexpected '(' after the name of a module%select{| partition}0 declaration">;
+ "unexpected '(' after the module name in 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/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index b23cfe8ec345e..e2ac204b86f6d 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -1374,7 +1374,7 @@ bool Preprocessor::LexAfterModuleDecl(Token &Result) {
/*IsReinject=*/false);
};
- // If we not expect an identifier but got an identifier, it's not a part of
+ // If we don't 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);
@@ -1385,43 +1385,14 @@ bool Preprocessor::LexAfterModuleDecl(Token &Result) {
//
// export[opt] module identifier (. identifier)*
//
- // indicates a module import directive. We already saw the 'module'
+ // indicates a module 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;
+ Diag(Result, diag::err_module_decl_cannot_be_macros)
+ << Result.getLocation() << ModuleDeclLexingPartitionName
+ << Result.getIdentifierInfo();
}
ModuleDeclExpectsIdentifier = false;
CurLexerCallback = CLK_LexAfterModuleDecl;
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index af4409ef86bcb..4bdf522561f92 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -2494,10 +2494,9 @@ 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))
- HasError = true;
+ return nullptr;
// Parse the optional module-partition.
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition;
if (Tok.is(tok::colon)) {
@@ -2507,7 +2506,7 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) {
<< SourceRange(ColonLoc, Partition.back().second);
// Recover by ignoring the partition name.
else if (ParseModuleName(ModuleLoc, Partition, /*IsImport=*/false))
- HasError = true;
+ return nullptr;
}
// We don't support any module attributes yet; just parse them and diagnose.
@@ -2520,9 +2519,8 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) {
ExpectAndConsumeSemi(diag::err_module_expected_semi);
- return HasError ? nullptr
- : Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path,
- Partition, ImportState);
+ return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, Partition,
+ ImportState);
}
/// Parse a module import declaration. This is essentially the same for
@@ -2677,7 +2675,6 @@ bool Parser::ParseModuleName(
SourceLocation UseLoc,
SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path,
bool IsImport) {
- bool HasMacroInModuleName = false;
// Parse the module path.
while (true) {
if (!Tok.is(tok::identifier)) {
@@ -2692,15 +2689,12 @@ bool Parser::ParseModuleName(
return true;
}
- const auto *MI = PP.getMacroInfo(Tok.getIdentifierInfo());
- HasMacroInModuleName = !IsImport && MI && MI->isObjectLike();
-
// Record this part of the module path.
Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation()));
ConsumeToken();
if (!TryConsumeToken(tok::period))
- return HasMacroInModuleName;
+ return false;
}
}
diff --git a/clang/test/CXX/cpp/cpp.module/p2.cppm b/clang/test/CXX/cpp/cpp.module/p2.cppm
index f21c891fe811b..add88ce0841bb 100644
--- a/clang/test/CXX/cpp/cpp.module/p2.cppm
+++ b/clang/test/CXX/cpp/cpp.module/p2.cppm
@@ -25,63 +25,73 @@
#define ATTRS [[]]
#define SEMICOLON ;
-#endif
+#endif // VERSION_H
//--- A.cppm
+module;
#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}}
+export module VERSION; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'VERSION', it's consists of one or more identifiers separated by '.'}}
//--- B.cppm
+module;
#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}}
+export module A.B; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A', it's consists of one or more identifiers separated by '.'}} \
+ // expected-error {{the module name in a module declaration cannot contain an object-like macro 'B', it's consists of one or more identifiers separated by '.'}}
//--- C.cppm
+module;
#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; 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}}
+export module A.FUNC_LIKE(foo):C; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A', it's consists of one or more identifiers separated by '.'}} \
+ // expected-error {{unexpected '(' after the module name in a module declaration}} \
+ // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C', it's consists of one or more identifiers separated by '.'}}
//--- D.cppm
+module;
#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; 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'?}}
+export module B.A.FUNC_LIKE(bar):C; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'B', it's consists of one or more identifiers separated by '.'}} \
+ // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A', it's consists of one or more identifiers separated by '.'}} \
+ // expected-error {{unexpected '(' after the module name in a module declaration}} \
+ // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C', it's consists of one or more identifiers separated by '.'}}
//--- E.cppm
+module;
#include "version.h"
export module a.FUNC_LIKE:c; // OK, FUNC_LIKE would not be treated as a macro name.
// expected-no-diagnostics
//--- F.cppm
+module;
#include "version.h"
export module a.FUNC_LIKE:c ATTRS; // OK, FUNC_LIKE would not be treated as a macro name.
// expected-no-diagnostics
//--- G.cppm
+module;
#include "version.h"
-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'?}} \
+export module A.FUNC_LIKE(B c:C ATTRS // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A', it's consists of one or more identifiers separated by '.'}} \
+ // expected-error {{unexpected '(' after the module name in a module declaration}} \
+ // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C', it's consists of one or more identifiers separated by '.'}} \
// expected-error {{expected ';' after module name}}
//--- H.cppm
+module;
#include "version.h"
-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'?}} \
+export module A.FUNC_LIKE(B,). c:C ATTRS // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A', it's consists of one or more identifiers separated by '.'}} \
+ // expected-error {{unexpected '(' after the module name in a module declaration}} \
+ // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C', it's consists of one or more identifiers separated by '.'}} \
// expected-error {{expected ';' after module name}}
//--- I.cppm
+module;
#include "version.h"
-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}} \
+export module A.FUNC_LIKE(B,) c:C ATTRS // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A', it's consists of one or more identifiers separated by '.'}} \
+ // expected-error {{unexpected '(' after the module name in a module declaration}} \
// expected-error {{expected ';' after module name}} \
// expected-error {{unknown type name 'c'}} \
// expected-error {{expected unqualified-id}}
//--- J.cppm
+module;
#include "version.h"
export module unexpanded : unexpanded ATTRS SEMICOLON // OK, ATTRS and SEMICOLON can be expanded.
// expected-no-diagnostics
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 860ac3d2894e0..ecad4db32a7e9 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
@@ -6,10 +6,12 @@
// RUN: %clang_cc1 -std=c++20 -emit-module-interface -fmodule-file=x=%t/x.pcm %t/x.y.cppm -o %t/x.y.pcm
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/a.b.cppm -o %t/a.b.pcm
//
-// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm -verify %t/test.cpp \
-// RUN: -DMODULE_NAME=z -DINTERFACE
+// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm -verify %t/test-interface.cpp \
+// RUN: -DINTERFACE
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm \
-// RUN: -fmodule-file=a.b=%t/a.b.pcm -verify %t/test.cpp -DMODULE_NAME=a.b
+// RUN: -fmodule-file=a.b=%t/a.b.pcm -verify %t/test.cpp
+// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm \
+// RUN: -verify %t/test-module-not-found.cpp
// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm -verify %t/test.x.cpp
//--- x.cppm
@@ -34,11 +36,8 @@ int use_2 = b; // ok
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', 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', and the macro will not expand}}
-#endif
+module;
+module a.b;
import x;
@@ -51,6 +50,28 @@ import x.y;
import x.; // expected-error {{expected a module name after 'import'}}
import .x; // expected-error {{expected a module name after 'import'}}
-import blarg; // expected-error {{module 'blarg' not found}}
+int use_4 = c; // ok
+
+
+//--- test-interface.cpp
+module;
+export module z;
+
+import x;
+
+import x [[]];
+import x [[foo]]; // expected-warning {{unknown attribute 'foo' ignored}}
+import x [[noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to a module import}}
+import x [[blarg::noreturn]]; // expected-warning {{unknown attribute 'noreturn' ignored}}
+
+import x.y;
+import x.; // expected-error {{expected a module name after 'import'}}
+import .x; // expected-error {{expected a module name after 'import'}}
int use_4 = c; // ok
+
+//--- test-module-not-found.cpp
+module;
+
+import blarg; // expected-error {{module 'blarg' not found}}
+
diff --git a/clang/test/SemaCXX/modules.cppm b/clang/test/SemaCXX/modules.cppm
index c0082d5150069..267417bf5da2c 100644
--- a/clang/test/SemaCXX/modules.cppm
+++ b/clang/test/SemaCXX/modules.cppm
@@ -82,12 +82,10 @@ 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', and the macro will not expand}}
+export module foo; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'foo'}}
static int m;
int n;
int use_a = a; // expected-error {{use of undeclared identifier 'a'}}
#undef foo
-import foo;
-
-export {} // expected-error {{export declaration can only be used within a module purview}}
+import foo; // expected-error {{imports must immediately follow the module declaration}}
>From ed0e90b60f37fe195c01aad5dc38d902ffe593be Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Sat, 11 May 2024 22:57:10 +0800
Subject: [PATCH 11/12] Address review comments
Signed-off-by: yronglin <yronglin777 at gmail.com>
---
.../include/clang/Basic/DiagnosticLexKinds.td | 3 +-
clang/include/clang/Basic/IdentifierTable.h | 6 ++--
clang/include/clang/Lex/Preprocessor.h | 4 +--
clang/lib/Basic/IdentifierTable.cpp | 2 +-
clang/lib/Lex/Preprocessor.cpp | 35 ++++++++++---------
clang/test/CXX/cpp/cpp.module/p2.cppm | 26 +++++++-------
6 files changed, 39 insertions(+), 37 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 6401d1c20b32c..fd31ea9421e58 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -934,8 +934,7 @@ def warn_module_conflict : Warning<
// C++20 modules
def err_module_decl_cannot_be_macros : Error<
"the module name in a module%select{| partition}0 declaration cannot contain "
- "an object-like macro %1, it's consists of one or more identifiers "
- "separated by '.'">;
+ "an object-like macro %1">;
def err_unxepected_paren_in_module_decl : Error<
"unexpected '(' after the module name in a module%select{| partition}0 declaration">;
def err_header_import_semi_in_macro : Error<
diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h
index 645f7ae913fa3..2735b892af28d 100644
--- a/clang/include/clang/Basic/IdentifierTable.h
+++ b/clang/include/clang/Basic/IdentifierTable.h
@@ -525,10 +525,10 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
}
/// Determine whether this is the contextual keyword \c module.
- bool isModulesDecl() const { return IsModulesDecl; }
+ bool isModulesDeclaration() const { return IsModulesDecl; }
/// Set whether this identifier is the contextual keyword \c module.
- void setModulesDecl(bool I) {
+ void setModulesDeclaration(bool I) {
IsModulesDecl = I;
if (I)
NeedsHandleIdentifier = true;
@@ -758,7 +758,7 @@ class IdentifierTable {
II->setModulesImport(true);
if (Name.equals("module"))
- II->setModulesDecl(true);
+ II->setModulesDeclaration(true);
return *II;
}
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 42442f08886b1..ea01375956974 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -611,10 +611,10 @@ class Preprocessor {
/// Whether the module declaration expects an identifier next. Otherwise,
/// it expects a '.' or ';'.
- bool ModuleDeclExpectsIdentifier = false;
+ bool ModuleDeclarationExpectsIdentifier = false;
/// Whether lexing the name of module partition declaration.
- bool ModuleDeclLexingPartitionName = false;
+ bool ModuleDeclarationLexingPartitionName = false;
/// The identifier and source location of the currently-active
/// \#pragma clang arc_cf_code_audited begin.
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index 76d5d1190a964..6475fc92043cd 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -324,7 +324,7 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
// Add the 'import' and 'module' contextual keyword.
get("import").setModulesImport(true);
- get("module").setModulesDecl(true);
+ get("module").setModulesDeclaration(true);
}
/// Checks if the specified token kind represents a keyword in the
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index e2ac204b86f6d..a943a22db3cd1 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -863,12 +863,12 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
CurLexerCallback = CLK_LexAfterModuleImport;
}
- if ((II.isModulesDecl() || Identifier.is(tok::kw_module)) && !InMacroArgs &&
- !DisableMacroExpansion &&
+ if ((II.isModulesDeclaration() || Identifier.is(tok::kw_module)) &&
+ !InMacroArgs && !DisableMacroExpansion &&
(getLangOpts().Modules || getLangOpts().DebuggerSupport) &&
CurLexerCallback != CLK_CachingLexer) {
- ModuleDeclExpectsIdentifier = true;
- ModuleDeclLexingPartitionName = false;
+ ModuleDeclarationExpectsIdentifier = true;
+ ModuleDeclarationLexingPartitionName = false;
CurLexerCallback = CLK_LexAfterModuleDecl;
}
return true;
@@ -951,8 +951,8 @@ void Preprocessor::Lex(Token &Result) {
} else if (Result.getIdentifierInfo() == getIdentifierInfo("module")) {
TrackGMFState.handleModule(StdCXXImportSeqState.afterTopLevelSeq());
ModuleDeclState.handleModule();
- ModuleDeclExpectsIdentifier = true;
- ModuleDeclLexingPartitionName = false;
+ ModuleDeclarationExpectsIdentifier = true;
+ ModuleDeclarationLexingPartitionName = false;
CurLexerCallback = CLK_LexAfterModuleDecl;
break;
}
@@ -1376,7 +1376,7 @@ bool Preprocessor::LexAfterModuleDecl(Token &Result) {
// If we don't expect an identifier but got an identifier, it's not a part of
// module name.
- if (!ModuleDeclExpectsIdentifier && Result.is(tok::identifier)) {
+ if (!ModuleDeclarationExpectsIdentifier && Result.is(tok::identifier)) {
EnterTokens(Result, /*DisableMacroExpansion=*/false);
return false;
}
@@ -1387,33 +1387,36 @@ bool Preprocessor::LexAfterModuleDecl(Token &Result) {
//
// indicates a module directive. We already saw the 'module'
// contextual keyword, so now we're looking for the identifiers.
- if (ModuleDeclExpectsIdentifier && Result.is(tok::identifier)) {
+ if (ModuleDeclarationExpectsIdentifier && Result.is(tok::identifier)) {
auto *MI = getMacroInfo(Result.getIdentifierInfo());
if (MI && MI->isObjectLike()) {
Diag(Result, diag::err_module_decl_cannot_be_macros)
- << Result.getLocation() << ModuleDeclLexingPartitionName
+ << Result.getLocation() << ModuleDeclarationLexingPartitionName
<< Result.getIdentifierInfo();
}
- ModuleDeclExpectsIdentifier = false;
+ ModuleDeclarationExpectsIdentifier = 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);
+ if (!ModuleDeclarationExpectsIdentifier &&
+ Result.isOneOf(tok::period, tok::colon)) {
+ ModuleDeclarationExpectsIdentifier = true;
+ ModuleDeclarationLexingPartitionName = 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;
+ if (!ModuleDeclarationExpectsIdentifier && Result.is(tok::l_paren)) {
+ ModuleDeclarationExpectsIdentifier = false;
Diag(Result, diag::err_unxepected_paren_in_module_decl)
- << ModuleDeclLexingPartitionName;
+ << ModuleDeclarationLexingPartitionName;
+
+ // Skip until see one of module name separator '.', ':' or ';'.
Token Tok;
// We already have a '('.
unsigned NumParens = 1;
diff --git a/clang/test/CXX/cpp/cpp.module/p2.cppm b/clang/test/CXX/cpp/cpp.module/p2.cppm
index add88ce0841bb..450a68166feb2 100644
--- a/clang/test/CXX/cpp/cpp.module/p2.cppm
+++ b/clang/test/CXX/cpp/cpp.module/p2.cppm
@@ -30,28 +30,28 @@
//--- A.cppm
module;
#include "version.h"
-export module VERSION; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'VERSION', it's consists of one or more identifiers separated by '.'}}
+export module VERSION; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'VERSION'}}
//--- B.cppm
module;
#include "version.h"
-export module A.B; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A', it's consists of one or more identifiers separated by '.'}} \
- // expected-error {{the module name in a module declaration cannot contain an object-like macro 'B', it's consists of one or more identifiers separated by '.'}}
+export module A.B; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A'}} \
+ // expected-error {{the module name in a module declaration cannot contain an object-like macro 'B'}}
//--- C.cppm
module;
#include "version.h"
-export module A.FUNC_LIKE(foo):C; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A', it's consists of one or more identifiers separated by '.'}} \
+export module A.FUNC_LIKE(foo):C; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A'}} \
// expected-error {{unexpected '(' after the module name in a module declaration}} \
- // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C', it's consists of one or more identifiers separated by '.'}}
+ // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C'}}
//--- D.cppm
module;
#include "version.h"
-export module B.A.FUNC_LIKE(bar):C; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'B', it's consists of one or more identifiers separated by '.'}} \
- // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A', it's consists of one or more identifiers separated by '.'}} \
+export module B.A.FUNC_LIKE(bar):C; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'B'}} \
+ // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A'}} \
// expected-error {{unexpected '(' after the module name in a module declaration}} \
- // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C', it's consists of one or more identifiers separated by '.'}}
+ // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C'}}
//--- E.cppm
module;
@@ -68,23 +68,23 @@ export module a.FUNC_LIKE:c ATTRS; // OK, FUNC_LIKE would not be treated as a ma
//--- G.cppm
module;
#include "version.h"
-export module A.FUNC_LIKE(B c:C ATTRS // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A', it's consists of one or more identifiers separated by '.'}} \
+export module A.FUNC_LIKE(B c:C ATTRS // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A'}} \
// expected-error {{unexpected '(' after the module name in a module declaration}} \
- // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C', it's consists of one or more identifiers separated by '.'}} \
+ // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C'}} \
// expected-error {{expected ';' after module name}}
//--- H.cppm
module;
#include "version.h"
-export module A.FUNC_LIKE(B,). c:C ATTRS // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A', it's consists of one or more identifiers separated by '.'}} \
+export module A.FUNC_LIKE(B,). c:C ATTRS // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A'}} \
// expected-error {{unexpected '(' after the module name in a module declaration}} \
- // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C', it's consists of one or more identifiers separated by '.'}} \
+ // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C'}} \
// expected-error {{expected ';' after module name}}
//--- I.cppm
module;
#include "version.h"
-export module A.FUNC_LIKE(B,) c:C ATTRS // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A', it's consists of one or more identifiers separated by '.'}} \
+export module A.FUNC_LIKE(B,) c:C ATTRS // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A'}} \
// expected-error {{unexpected '(' after the module name in a module declaration}} \
// expected-error {{expected ';' after module name}} \
// expected-error {{unknown type name 'c'}} \
>From 45d40a08d42489f635aad0d3de6ecbfedd48b7d1 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Thu, 30 May 2024 07:13:26 +0800
Subject: [PATCH 12/12] Skip unexpect tokens in parser
Signed-off-by: yronglin <yronglin777 at gmail.com>
---
clang/lib/Lex/Preprocessor.cpp | 20 +-----------------
clang/lib/Parse/Parser.cpp | 11 +++++++++-
clang/test/CXX/cpp/cpp.module/p2.cppm | 29 +++++++++------------------
3 files changed, 21 insertions(+), 39 deletions(-)
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index a943a22db3cd1..e9e93867de704 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -865,7 +865,7 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
if ((II.isModulesDeclaration() || Identifier.is(tok::kw_module)) &&
!InMacroArgs && !DisableMacroExpansion &&
- (getLangOpts().Modules || getLangOpts().DebuggerSupport) &&
+ (getLangOpts().CPlusPlusModules || getLangOpts().DebuggerSupport) &&
CurLexerCallback != CLK_CachingLexer) {
ModuleDeclarationExpectsIdentifier = true;
ModuleDeclarationLexingPartitionName = false;
@@ -1415,24 +1415,6 @@ bool Preprocessor::LexAfterModuleDecl(Token &Result) {
ModuleDeclarationExpectsIdentifier = false;
Diag(Result, diag::err_unxepected_paren_in_module_decl)
<< ModuleDeclarationLexingPartitionName;
-
- // Skip until see one of module name separator '.', ':' or ';'.
- 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;
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 4bdf522561f92..bfbac10ac9121 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -2693,8 +2693,17 @@ bool Parser::ParseModuleName(
Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation()));
ConsumeToken();
- if (!TryConsumeToken(tok::period))
+ if (!TryConsumeToken(tok::period)) {
+ // [cpp.module]/p2: where the pp-tokens (if any) shall not begin with a (
+ // preprocessing token [...]
+ //
+ // We already diagnose in preprocessor and just skip to semicolon.
+ if (Tok.is(tok::l_paren)) {
+ SkipUntil(tok::semi, StopBeforeMatch);
+ return true;
+ }
return false;
+ }
}
}
diff --git a/clang/test/CXX/cpp/cpp.module/p2.cppm b/clang/test/CXX/cpp/cpp.module/p2.cppm
index 450a68166feb2..966a88ccfa972 100644
--- a/clang/test/CXX/cpp/cpp.module/p2.cppm
+++ b/clang/test/CXX/cpp/cpp.module/p2.cppm
@@ -39,19 +39,17 @@ export module A.B; // expected-error {{the module name in a module declarat
// expected-error {{the module name in a module declaration cannot contain an object-like macro 'B'}}
//--- C.cppm
-module;
+module; // expected-error {{missing 'module' declaration at end of global module fragment introduced here}}
#include "version.h"
export module A.FUNC_LIKE(foo):C; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A'}} \
- // expected-error {{unexpected '(' after the module name in a module declaration}} \
- // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C'}}
+ // expected-error {{unexpected '(' after the module name in a module declaration}}
//--- D.cppm
-module;
+module; // expected-error {{missing 'module' declaration at end of global module fragment introduced here}}
#include "version.h"
export module B.A.FUNC_LIKE(bar):C; // expected-error {{the module name in a module declaration cannot contain an object-like macro 'B'}} \
// expected-error {{the module name in a module declaration cannot contain an object-like macro 'A'}} \
- // expected-error {{unexpected '(' after the module name in a module declaration}} \
- // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C'}}
+ // expected-error {{unexpected '(' after the module name in a module declaration}}
//--- E.cppm
module;
@@ -66,29 +64,22 @@ export module a.FUNC_LIKE:c ATTRS; // OK, FUNC_LIKE would not be treated as a ma
// expected-no-diagnostics
//--- G.cppm
-module;
+module; // expected-error {{missing 'module' declaration at end of global module fragment introduced here}}
#include "version.h"
export module A.FUNC_LIKE(B c:C ATTRS // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A'}} \
- // expected-error {{unexpected '(' after the module name in a module declaration}} \
- // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C'}} \
- // expected-error {{expected ';' after module name}}
+ // expected-error {{unexpected '(' after the module name in a module declaration}}
//--- H.cppm
-module;
+module; // expected-error {{missing 'module' declaration at end of global module fragment introduced here}}
#include "version.h"
export module A.FUNC_LIKE(B,). c:C ATTRS // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A'}} \
- // expected-error {{unexpected '(' after the module name in a module declaration}} \
- // expected-error {{the module name in a module partition declaration cannot contain an object-like macro 'C'}} \
- // expected-error {{expected ';' after module name}}
+ // expected-error {{unexpected '(' after the module name in a module declaration}}
//--- I.cppm
-module;
+module; // expected-error {{missing 'module' declaration at end of global module fragment introduced here}}
#include "version.h"
export module A.FUNC_LIKE(B,) c:C ATTRS // expected-error {{the module name in a module declaration cannot contain an object-like macro 'A'}} \
- // expected-error {{unexpected '(' after the module name in a module declaration}} \
- // expected-error {{expected ';' after module name}} \
- // expected-error {{unknown type name 'c'}} \
- // expected-error {{expected unqualified-id}}
+ // expected-error {{unexpected '(' after the module name in a module declaration}}
//--- J.cppm
module;
More information about the cfe-commits
mailing list