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