[clang] Revert "[Clang] Implement P3034R1 Module Declarations Shouldn’t be Macros" (PR #99838)

via cfe-commits cfe-commits at lists.llvm.org
Sun Jul 21 22:16:44 PDT 2024


https://github.com/yronglin created https://github.com/llvm/llvm-project/pull/99838

Reverts llvm/llvm-project#90574

>From 3830c428298d0f781e1a82d1885d8903e7169c4d Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Mon, 22 Jul 2024 13:16:19 +0800
Subject: [PATCH] =?UTF-8?q?Revert=20"[Clang]=20Implement=20P3034R1=20Modul?=
 =?UTF-8?q?e=20Declarations=20Shouldn=E2=80=99t=20be=20Macros=20(#9?=
 =?UTF-8?q?=E2=80=A6"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This reverts commit e77a01d79a48e15c94c89e4aa4bd27424a96b49b.
---
 clang/docs/ReleaseNotes.rst                   |   2 -
 .../include/clang/Basic/DiagnosticLexKinds.td |   5 -
 clang/include/clang/Basic/IdentifierTable.h   |  24 +-
 clang/include/clang/Basic/TokenKinds.def      |   3 -
 clang/include/clang/Lex/Preprocessor.h        |  83 +---
 clang/include/clang/Lex/Token.h               |   3 -
 clang/include/clang/Parse/Parser.h            |   2 +-
 clang/lib/Basic/IdentifierTable.cpp           |   3 +-
 .../lib/Frontend/PrintPreprocessedOutput.cpp  |  12 +-
 clang/lib/Lex/PPLexerChange.cpp               |   9 +-
 clang/lib/Lex/Preprocessor.cpp                | 444 ++++++------------
 clang/lib/Lex/TokenConcatenation.cpp          |  10 -
 clang/lib/Parse/ParseDecl.cpp                 |   8 +-
 clang/lib/Parse/Parser.cpp                    |  93 ++--
 clang/test/CXX/cpp/cpp.module/p2.cppm         |  88 ----
 .../basic/basic.link/module-declaration.cpp   |  61 ++-
 .../dcl.module/dcl.module.import/p1.cppm      |  39 +-
 clang/test/SemaCXX/modules.cppm               |  89 ++--
 clang/www/cxx_status.html                     |   2 +-
 19 files changed, 263 insertions(+), 717 deletions(-)
 delete mode 100644 clang/test/CXX/cpp/cpp.module/p2.cppm

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4ab6bd9de8ea9..7ac6ed934290d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -285,8 +285,6 @@ C++2c Feature Support
 
 - Implemented `P2963R3 Ordering of constraints involving fold expressions <https://wg21.link/P2963R3>`_.
 
-- Implemented `P3034R1 Module Declarations Shouldn’t be Macros <https://wg21.link/P3034R1>`_.
-
 
 Resolutions to C++ Defect Reports
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 08ece01009387..12d7b8c0205ee 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -952,11 +952,6 @@ def warn_module_conflict : Warning<
   InGroup<ModuleConflict>;
 
 // 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">;
-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<
   "semicolon terminating header import declaration cannot be produced "
   "by a macro">;
diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h
index f40f74d0355ad..ae9ebd9f59154 100644
--- a/clang/include/clang/Basic/IdentifierTable.h
+++ b/clang/include/clang/Basic/IdentifierTable.h
@@ -180,10 +180,6 @@ 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;
@@ -200,7 +196,7 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
   LLVM_PREFERRED_TYPE(bool)
   unsigned IsFinal : 1;
 
-  // 21 bits left in a 64-bit word.
+  // 22 bits left in a 64-bit word.
 
   // Managed by the language front-end.
   void *FETokenInfo = nullptr;
@@ -216,8 +212,8 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
         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) {}
+        IsMangledOpenMPVariantName(false), IsDeprecatedMacro(false),
+        IsRestrictExpansion(false), IsFinal(false) {}
 
 public:
   IdentifierInfo(const IdentifierInfo &) = delete;
@@ -524,18 +520,6 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
       RecomputeNeedsHandleIdentifier();
   }
 
-  /// Determine whether this is the contextual keyword \c module.
-  bool isModulesDeclaration() const { return IsModulesDecl; }
-
-  /// Set whether this identifier is the contextual keyword \c module.
-  void setModulesDeclaration(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; }
 
@@ -756,8 +740,6 @@ class IdentifierTable {
     // If this is the 'import' contextual keyword, mark it as such.
     if (Name == "import")
       II->setModulesImport(true);
-    else if (Name == "module")
-      II->setModulesDeclaration(true);
 
     return *II;
   }
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 8db18c049b6d0..7f4912b9bcd96 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -1003,9 +1003,6 @@ ANNOTATION(module_include)
 ANNOTATION(module_begin)
 ANNOTATION(module_end)
 
-// Annotations for C++, Clang and Objective-C named modules.
-ANNOTATION(module_name)
-
 // Annotation for a header_name token that has been looked up and transformed
 // into the name of a header unit.
 ANNOTATION(header_unit)
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 56aef99a3f38a..fc7d0053f2323 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -615,6 +615,10 @@ class Preprocessor {
 
   ModuleDeclSeq ModuleDeclState;
 
+  /// Whether the module import expects an identifier next. Otherwise,
+  /// it expects a '.' or ';'.
+  bool ModuleImportExpectsIdentifier = false;
+
   /// The identifier and source location of the currently-active
   /// \#pragma clang arc_cf_code_audited begin.
   std::pair<IdentifierInfo *, SourceLocation> PragmaARCCFCodeAuditedInfo;
@@ -1740,14 +1744,11 @@ class Preprocessor {
   /// Lex a token, forming a header-name token if possible.
   bool LexHeaderName(Token &Result, bool AllowMacroExpansion = true);
 
-  /// Lex a module name or a partition name.
-  bool LexModuleName(Token &Result, bool IsImport);
-
   /// Lex the parameters for an #embed directive, returns nullopt on error.
   std::optional<LexEmbedParametersResult> LexEmbedParameters(Token &Current,
                                                              bool ForHasEmbed);
+
   bool LexAfterModuleImport(Token &Result);
-  bool LexAfterModuleDecl(Token &Result);
   void CollectPpImportSuffix(SmallVectorImpl<Token> &Toks);
 
   void makeModuleVisible(Module *M, SourceLocation Loc);
@@ -3038,9 +3039,6 @@ 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
@@ -3073,77 +3071,6 @@ struct EmbedAnnotationData {
 /// Registry of pragma handlers added by plugins
 using PragmaHandlerRegistry = llvm::Registry<PragmaHandler>;
 
-/// Represents module or partition name token sequance.
-///
-///     module-name:
-///           module-name-qualifier[opt] identifier
-///
-///     partition-name: [C++20]
-///           : module-name-qualifier[opt] identifier
-///
-///     module-name-qualifier
-///           module-name-qualifier[opt] identifier .
-///
-/// This class can only be created by the preprocessor and guarantees that the
-/// two source array being contiguous in memory and only contains 3 kind of
-/// tokens (identifier, '.' and ':'). And only available when the preprocessor
-/// returns annot_module_name token.
-///
-/// For exmaple:
-///
-/// export module m.n:c.d
-///
-/// The module name array has 3 tokens ['m', '.', 'n'].
-/// The partition name array has 4 tokens [':', 'c', '.', 'd'].
-///
-/// When import a partition in a named module fragment (Eg. import :part1;),
-/// the module name array will be empty, and the partition name array has 2
-/// tokens.
-///
-/// When we meet a private-module-fragment (Eg. module :private;), preprocessor
-/// will not return a annot_module_name token, but will return 2 separate tokens
-/// [':', 'kw_private'].
-
-class ModuleNameInfo {
-  friend class Preprocessor;
-  ArrayRef<Token> ModuleName;
-  ArrayRef<Token> PartitionName;
-
-  ModuleNameInfo(ArrayRef<Token> AnnotToks, std::optional<unsigned> ColonIndex);
-
-public:
-  /// Return the contiguous token array.
-  ArrayRef<Token> getTokens() const {
-    if (ModuleName.empty())
-      return PartitionName;
-    if (PartitionName.empty())
-      return ModuleName;
-    return ArrayRef(ModuleName.begin(), PartitionName.end());
-  }
-  bool hasModuleName() const { return !ModuleName.empty(); }
-  bool hasPartitionName() const { return !PartitionName.empty(); }
-  ArrayRef<Token> getModuleName() const { return ModuleName; }
-  ArrayRef<Token> getPartitionName() const { return PartitionName; }
-  Token getColonToken() const {
-    assert(hasPartitionName() && "Do not have a partition name");
-    return getPartitionName().front();
-  }
-
-  /// Under the standard C++ Modules, the dot is just part of the module name,
-  /// and not a real hierarchy separator. Flatten such module names now.
-  std::string getFlatName() const;
-
-  /// Build a module id path from the contiguous token array, both include
-  /// module name and partition name.
-  void getModuleIdPath(
-      SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path) const;
-
-  /// Build a module id path from \param ModuleName.
-  static void getModuleIdPath(
-      ArrayRef<Token> ModuleName,
-      SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path);
-};
-
 } // namespace clang
 
 #endif // LLVM_CLANG_LEX_PREPROCESSOR_H
diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h
index 2be3ad39529f0..4f29fb7d11415 100644
--- a/clang/include/clang/Lex/Token.h
+++ b/clang/include/clang/Lex/Token.h
@@ -235,9 +235,6 @@ class Token {
     assert(isAnnotation() && "Used AnnotVal on non-annotation token");
     return PtrData;
   }
-  template <class T> T getAnnotationValueAs() const {
-    return static_cast<T>(getAnnotationValue());
-  }
   void setAnnotationValue(void *val) {
     assert(isAnnotation() && "Used AnnotVal on non-annotation token");
     PtrData = val;
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index afcdacf02583a..93e60be512aae 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -3876,7 +3876,7 @@ class Parser : public CodeCompletionHandler {
   }
 
   bool ParseModuleName(
-      SourceLocation UseLoc, ArrayRef<Token> ModuleName,
+      SourceLocation UseLoc,
       SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path,
       bool IsImport);
 
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index 97d830214f890..4f7ccaf4021d6 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -322,9 +322,8 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
   if (LangOpts.IEEE128)
     AddKeyword("__ieee128", tok::kw___float128, KEYALL, LangOpts, *this);
 
-  // Add the 'import' and 'module' contextual keyword.
+  // Add the 'import' contextual keyword.
   get("import").setModulesImport(true);
-  get("module").setModulesDeclaration(true);
 }
 
 /// Checks if the specified token kind represents a keyword in the
diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
index 1fff88ccf0405..0592423c12eca 100644
--- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -758,10 +758,9 @@ void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok,
   // These tokens are not expanded to anything and don't need whitespace before
   // them.
   if (Tok.is(tok::eof) ||
-      (Tok.isAnnotation() && Tok.isNot(tok::annot_header_unit) &&
-       Tok.isNot(tok::annot_module_begin) && Tok.isNot(tok::annot_module_end) &&
-       Tok.isNot(tok::annot_module_name) &&
-       Tok.isNot(tok::annot_repl_input_end) && Tok.isNot(tok::annot_embed)))
+      (Tok.isAnnotation() && !Tok.is(tok::annot_header_unit) &&
+       !Tok.is(tok::annot_module_begin) && !Tok.is(tok::annot_module_end) &&
+       !Tok.is(tok::annot_repl_input_end) && !Tok.is(tok::annot_embed)))
     return;
 
   // EmittedDirectiveOnThisLine takes priority over RequireSameLine.
@@ -952,11 +951,6 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
       PP.Lex(Tok);
       IsStartOfLine = true;
       continue;
-    } else if (Tok.is(tok::annot_module_name)) {
-      auto *Info = static_cast<ModuleNameInfo *>(Tok.getAnnotationValue());
-      *Callbacks->OS << Info->getFlatName();
-      PP.Lex(Tok);
-      continue;
     } else if (Tok.is(tok::annot_header_unit)) {
       // This is a header-name that has been (effectively) converted into a
       // module-name.
diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp
index c3a903917e9ce..8221db46e06ac 100644
--- a/clang/lib/Lex/PPLexerChange.cpp
+++ b/clang/lib/Lex/PPLexerChange.cpp
@@ -122,8 +122,7 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer,
   CurPPLexer = TheLexer;
   CurDirLookup = CurDir;
   CurLexerSubmodule = nullptr;
-  if (CurLexerCallback != CLK_LexAfterModuleImport &&
-      CurLexerCallback != CLK_LexAfterModuleDecl)
+  if (CurLexerCallback != CLK_LexAfterModuleImport)
     CurLexerCallback = TheLexer->isDependencyDirectivesLexer()
                            ? CLK_DependencyDirectivesLexer
                            : CLK_Lexer;
@@ -162,7 +161,8 @@ void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
   PushIncludeMacroStack();
   CurDirLookup = nullptr;
   CurTokenLexer = std::move(TokLexer);
-  CurLexerCallback = CLK_TokenLexer;
+  if (CurLexerCallback != CLK_LexAfterModuleImport)
+    CurLexerCallback = CLK_TokenLexer;
 }
 
 /// EnterTokenStream - Add a "macro" context to the top of the include stack,
@@ -216,8 +216,7 @@ void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks,
   PushIncludeMacroStack();
   CurDirLookup = nullptr;
   CurTokenLexer = std::move(TokLexer);
-  if (CurLexerCallback != CLK_LexAfterModuleImport &&
-      CurLexerCallback != CLK_LexAfterModuleDecl)
+  if (CurLexerCallback != CLK_LexAfterModuleImport)
     CurLexerCallback = CLK_TokenLexer;
 }
 
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 2726fae344337..63e27e62cffc8 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -860,15 +860,9 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
     ModuleImportLoc = Identifier.getLocation();
     NamedModuleImportPath.clear();
     IsAtImport = true;
+    ModuleImportExpectsIdentifier = true;
     CurLexerCallback = CLK_LexAfterModuleImport;
   }
-
-  if ((II.isModulesDeclaration() || Identifier.is(tok::kw_module)) &&
-      !InMacroArgs && !DisableMacroExpansion &&
-      (getLangOpts().CPlusPlusModules || getLangOpts().DebuggerSupport) &&
-      CurLexerCallback != CLK_CachingLexer) {
-    CurLexerCallback = CLK_LexAfterModuleDecl;
-  }
   return true;
 }
 
@@ -911,7 +905,6 @@ void Preprocessor::Lex(Token &Result) {
     // This token is injected to represent the translation of '#include "a.h"'
     // into "import a.h;". Mimic the notional ';'.
     case tok::annot_module_include:
-    case tok::annot_repl_input_end:
     case tok::semi:
       TrackGMFState.handleSemi();
       StdCXXImportSeqState.handleSemi();
@@ -926,30 +919,12 @@ void Preprocessor::Lex(Token &Result) {
       StdCXXImportSeqState.handleExport();
       ModuleDeclState.handleExport();
       break;
-    case tok::annot_module_name: {
-      auto *Info = static_cast<ModuleNameInfo *>(Result.getAnnotationValue());
-      for (const auto &Tok : Info->getTokens()) {
-        switch (Tok.getKind()) {
-        case tok::identifier:
-          ModuleDeclState.handleIdentifier(Tok.getIdentifierInfo());
-          break;
-        case tok::period:
-          ModuleDeclState.handlePeriod();
-          break;
-        case tok::colon:
-          ModuleDeclState.handleColon();
-          break;
-        default:
-          llvm_unreachable("Unexpected token in module name");
-        }
-      }
-      if (ModuleDeclState.isModuleCandidate())
-        break;
-      TrackGMFState.handleMisc();
-      StdCXXImportSeqState.handleMisc();
-      ModuleDeclState.handleMisc();
+    case tok::colon:
+      ModuleDeclState.handleColon();
+      break;
+    case tok::period:
+      ModuleDeclState.handlePeriod();
       break;
-    }
     case tok::identifier:
       // Check "import" and "module" when there is no open bracket. The two
       // identifiers are not meaningful with open brackets.
@@ -961,17 +936,17 @@ void Preprocessor::Lex(Token &Result) {
             ModuleImportLoc = Result.getLocation();
             NamedModuleImportPath.clear();
             IsAtImport = false;
+            ModuleImportExpectsIdentifier = true;
             CurLexerCallback = CLK_LexAfterModuleImport;
           }
           break;
-        }
-        if (Result.getIdentifierInfo()->isModulesDeclaration()) {
+        } else if (Result.getIdentifierInfo() == getIdentifierInfo("module")) {
           TrackGMFState.handleModule(StdCXXImportSeqState.afterTopLevelSeq());
           ModuleDeclState.handleModule();
-          CurLexerCallback = CLK_LexAfterModuleDecl;
           break;
         }
       }
+      ModuleDeclState.handleIdentifier(Result.getIdentifierInfo());
       if (ModuleDeclState.isModuleCandidate())
         break;
       [[fallthrough]];
@@ -1146,151 +1121,6 @@ void Preprocessor::CollectPpImportSuffix(SmallVectorImpl<Token> &Toks) {
   }
 }
 
-ModuleNameInfo::ModuleNameInfo(ArrayRef<Token> AnnotToks,
-                               std::optional<unsigned> ColonIndex) {
-  assert(!AnnotToks.empty() && "Named module token cannot be empty.");
-  if (!ColonIndex.has_value())
-    ColonIndex = AnnotToks.size();
-  ModuleName = ArrayRef(AnnotToks.begin(), AnnotToks.begin() + *ColonIndex);
-  PartitionName = ArrayRef(AnnotToks.begin() + *ColonIndex, AnnotToks.end());
-  assert(ModuleName.end() == PartitionName.begin());
-}
-
-std::string ModuleNameInfo::getFlatName() const {
-  std::string FlatModuleName;
-  for (auto &Tok : getTokens()) {
-    switch (Tok.getKind()) {
-    case tok::identifier:
-      FlatModuleName += Tok.getIdentifierInfo()->getName();
-      break;
-    case tok::period:
-      FlatModuleName += '.';
-      break;
-    case tok::colon:
-      FlatModuleName += ':';
-      break;
-    default:
-      llvm_unreachable("Unexpected token in module name");
-    }
-  }
-  return FlatModuleName;
-}
-
-void ModuleNameInfo::getModuleIdPath(
-    SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path) const {
-  return getModuleIdPath(getTokens(), Path);
-}
-
-void ModuleNameInfo::getModuleIdPath(
-    ArrayRef<Token> ModuleName,
-    SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path) {
-  for (const auto &Tok : ModuleName) {
-    if (Tok.is(tok::identifier))
-      Path.push_back(
-          std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation()));
-  }
-}
-
-/// Lex a module name or a partition name.
-///
-///     module-name:
-///           module-name-qualifier[opt] identifier
-///
-///     partition-name: [C++20]
-///           : module-name-qualifier[opt] identifier
-///
-///     module-name-qualifier
-///           module-name-qualifier[opt] identifier .
-bool Preprocessor::LexModuleName(Token &Result, bool IsImport) {
-  bool ExpectsIdentifier = true, IsLexingPartition = false;
-  SmallVector<Token, 8> ModuleName;
-  std::optional<unsigned> ColonTokIndex;
-  auto LexNextToken = [&](Token &Tok) {
-    if (IsImport)
-      Lex(Tok);
-    else
-      LexUnexpandedToken(Tok);
-  };
-
-  while (true) {
-    LexNextToken(Result);
-    if (ExpectsIdentifier && Result.is(tok::identifier)) {
-      auto *MI = getMacroInfo(Result.getIdentifierInfo());
-      if (getLangOpts().CPlusPlusModules && !IsImport && MI &&
-          MI->isObjectLike()) {
-        Diag(Result, diag::err_module_decl_cannot_be_macros)
-            << Result.getLocation() << IsLexingPartition
-            << Result.getIdentifierInfo();
-      }
-      ModuleName.push_back(Result);
-      ExpectsIdentifier = false;
-      continue;
-    }
-
-    if (!ExpectsIdentifier && Result.is(tok::period)) {
-      ModuleName.push_back(Result);
-      ExpectsIdentifier = true;
-      continue;
-    }
-
-    // Module partition only allowed in C++20 Modules.
-    if (getLangOpts().CPlusPlusModules && Result.is(tok::colon)) {
-      // Handle the form like: import :P;
-      // If the token after ':' is not an identifier, this is a invalid module
-      // name.
-      if (ModuleName.empty()) {
-        Token Tmp;
-        LexNextToken(Tmp);
-        EnterToken(Tmp, /*IsReiject=*/false);
-        // A private-module-fragment:
-        // export module :private;
-        if (!IsImport && Tmp.is(tok::kw_private))
-          return true;
-        // import :N;
-        if (IsImport && Tmp.isNot(tok::identifier))
-          return false;
-      } else if (!ExpectsIdentifier) {
-        ExpectsIdentifier = true;
-      }
-      IsLexingPartition = true;
-      ColonTokIndex = ModuleName.size();
-      ModuleName.push_back(Result);
-      continue;
-    }
-
-    // [cpp.module]/p2: where the pp-tokens (if any) shall not begin with a (
-    // preprocessing token [...]
-    //
-    // We only emit diagnostic in the preprocessor, and in the parser we skip
-    // invalid tokens and recover from errors.
-    if (getLangOpts().CPlusPlusModules && !ExpectsIdentifier &&
-        Result.is(tok::l_paren))
-      Diag(Result, diag::err_unxepected_paren_in_module_decl)
-          << IsLexingPartition;
-    break;
-  }
-
-  // Put the last token back to stream, it's not a valid part of module name.
-  // We lexed it unexpanded but it might be a valid macro expansion
-  Result.clearFlag(Token::DisableExpand);
-  auto ToksCopy = std::make_unique<Token[]>(1);
-  *ToksCopy.get() = Result;
-  EnterTokenStream(std::move(ToksCopy), 1,
-                   /*DisableMacroExpansion=*/false,
-                   /*IsReinject=*/false);
-
-  if (ModuleName.empty())
-    return false;
-  Result.startToken();
-  Result.setKind(tok::annot_module_name);
-  Result.setLocation(ModuleName.front().getLocation());
-  Result.setAnnotationEndLoc(ModuleName.back().getLocation());
-  auto AnnotToks = ArrayRef(ModuleName).copy(getPreprocessorAllocator());
-  ModuleNameInfo *Info =
-      new (getPreprocessorAllocator()) ModuleNameInfo(AnnotToks, ColonTokIndex);
-  Result.setAnnotationValue(static_cast<void *>(Info));
-  return true;
-}
 
 /// Lex a token following the 'import' contextual keyword.
 ///
@@ -1315,17 +1145,6 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
   // Figure out what kind of lexer we actually have.
   recomputeCurLexerKind();
 
-  // Allocate a holding buffer for a sequence of tokens and introduce it into
-  // the token stream.
-  auto EnterTokens = [this](ArrayRef<Token> Toks) {
-    auto ToksCopy = std::make_unique<Token[]>(Toks.size());
-    std::copy(Toks.begin(), Toks.end(), ToksCopy.get());
-    EnterTokenStream(std::move(ToksCopy), Toks.size(),
-                     /*DisableMacroExpansion*/ true, /*IsReinject*/ false);
-  };
-
-  SmallVector<Token, 32> Suffix;
-
   // Lex the next token. The header-name lexing rules are used at the start of
   // a pp-import.
   //
@@ -1336,108 +1155,122 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
     if (LexHeaderName(Result))
       return true;
 
-    // Check for a header-name.
-    if (Result.is(tok::header_name)) {
-      // Enter the header-name token into the token stream; a Lex action cannot
-      // both return a token and cache tokens (doing so would corrupt the token
-      // cache if the call to Lex comes from CachingLex / PeekAhead).
-      Suffix.push_back(Result);
-
-      // Consume the pp-import-suffix and expand any macros in it now. We'll add
-      // it back into the token stream later.
-      CollectPpImportSuffix(Suffix);
-      if (Suffix.back().isNot(tok::semi)) {
-        // This is not a pp-import after all.
-        EnterTokens(Suffix);
-        return false;
-      }
+    if (Result.is(tok::colon) && ModuleDeclState.isNamedModule()) {
+      std::string Name = ModuleDeclState.getPrimaryName().str();
+      Name += ":";
+      NamedModuleImportPath.push_back(
+          {getIdentifierInfo(Name), Result.getLocation()});
+      CurLexerCallback = CLK_LexAfterModuleImport;
+      return true;
+    }
+  } else {
+    Lex(Result);
+  }
 
-      // C++2a [cpp.module]p1:
-      //   The ';' preprocessing-token terminating a pp-import shall not have
-      //   been produced by macro replacement.
-      SourceLocation SemiLoc = Suffix.back().getLocation();
-      if (SemiLoc.isMacroID())
-        Diag(SemiLoc, diag::err_header_import_semi_in_macro);
-
-      // Reconstitute the import token.
-      Token ImportTok;
-      ImportTok.startToken();
-      ImportTok.setKind(tok::kw_import);
-      ImportTok.setLocation(ModuleImportLoc);
-      ImportTok.setIdentifierInfo(getIdentifierInfo("import"));
-      ImportTok.setLength(6);
-
-      auto Action = HandleHeaderIncludeOrImport(
-          /*HashLoc*/ SourceLocation(), ImportTok, Suffix.front(), SemiLoc);
-      switch (Action.Kind) {
-      case ImportAction::None:
-        break;
+  // Allocate a holding buffer for a sequence of tokens and introduce it into
+  // the token stream.
+  auto EnterTokens = [this](ArrayRef<Token> Toks) {
+    auto ToksCopy = std::make_unique<Token[]>(Toks.size());
+    std::copy(Toks.begin(), Toks.end(), ToksCopy.get());
+    EnterTokenStream(std::move(ToksCopy), Toks.size(),
+                     /*DisableMacroExpansion*/ true, /*IsReinject*/ false);
+  };
 
-      case ImportAction::ModuleBegin:
-        // Let the parser know we're textually entering the module.
-        Suffix.emplace_back();
-        Suffix.back().startToken();
-        Suffix.back().setKind(tok::annot_module_begin);
-        Suffix.back().setLocation(SemiLoc);
-        Suffix.back().setAnnotationEndLoc(SemiLoc);
-        Suffix.back().setAnnotationValue(Action.ModuleForHeader);
-        [[fallthrough]];
-
-      case ImportAction::ModuleImport:
-      case ImportAction::HeaderUnitImport:
-      case ImportAction::SkippedModuleImport:
-        // We chose to import (or textually enter) the file. Convert the
-        // header-name token into a header unit annotation token.
-        Suffix[0].setKind(tok::annot_header_unit);
-        Suffix[0].setAnnotationEndLoc(Suffix[0].getLocation());
-        Suffix[0].setAnnotationValue(Action.ModuleForHeader);
-        // FIXME: Call the moduleImport callback?
-        break;
-      case ImportAction::Failure:
-        assert(TheModuleLoader.HadFatalFailure &&
-               "This should be an early exit only to a fatal error");
-        Result.setKind(tok::eof);
-        CurLexer->cutOffLexing();
-        EnterTokens(Suffix);
-        return true;
-      }
+  bool ImportingHeader = Result.is(tok::header_name);
+  // Check for a header-name.
+  SmallVector<Token, 32> Suffix;
+  if (ImportingHeader) {
+    // Enter the header-name token into the token stream; a Lex action cannot
+    // both return a token and cache tokens (doing so would corrupt the token
+    // cache if the call to Lex comes from CachingLex / PeekAhead).
+    Suffix.push_back(Result);
 
+    // Consume the pp-import-suffix and expand any macros in it now. We'll add
+    // it back into the token stream later.
+    CollectPpImportSuffix(Suffix);
+    if (Suffix.back().isNot(tok::semi)) {
+      // This is not a pp-import after all.
       EnterTokens(Suffix);
       return false;
     }
-  } else {
-    Lex(Result);
-  }
 
-  if (Result.isOneOf(tok::identifier, tok::colon)) {
-    EnterToken(Result, /*IsReinject=*/false);
-    if (!LexModuleName(Result, /*IsImport=*/true))
+    // C++2a [cpp.module]p1:
+    //   The ';' preprocessing-token terminating a pp-import shall not have
+    //   been produced by macro replacement.
+    SourceLocation SemiLoc = Suffix.back().getLocation();
+    if (SemiLoc.isMacroID())
+      Diag(SemiLoc, diag::err_header_import_semi_in_macro);
+
+    // Reconstitute the import token.
+    Token ImportTok;
+    ImportTok.startToken();
+    ImportTok.setKind(tok::kw_import);
+    ImportTok.setLocation(ModuleImportLoc);
+    ImportTok.setIdentifierInfo(getIdentifierInfo("import"));
+    ImportTok.setLength(6);
+
+    auto Action = HandleHeaderIncludeOrImport(
+        /*HashLoc*/ SourceLocation(), ImportTok, Suffix.front(), SemiLoc);
+    switch (Action.Kind) {
+    case ImportAction::None:
+      break;
+
+    case ImportAction::ModuleBegin:
+      // Let the parser know we're textually entering the module.
+      Suffix.emplace_back();
+      Suffix.back().startToken();
+      Suffix.back().setKind(tok::annot_module_begin);
+      Suffix.back().setLocation(SemiLoc);
+      Suffix.back().setAnnotationEndLoc(SemiLoc);
+      Suffix.back().setAnnotationValue(Action.ModuleForHeader);
+      [[fallthrough]];
+
+    case ImportAction::ModuleImport:
+    case ImportAction::HeaderUnitImport:
+    case ImportAction::SkippedModuleImport:
+      // We chose to import (or textually enter) the file. Convert the
+      // header-name token into a header unit annotation token.
+      Suffix[0].setKind(tok::annot_header_unit);
+      Suffix[0].setAnnotationEndLoc(Suffix[0].getLocation());
+      Suffix[0].setAnnotationValue(Action.ModuleForHeader);
+      // FIXME: Call the moduleImport callback?
+      break;
+    case ImportAction::Failure:
+      assert(TheModuleLoader.HadFatalFailure &&
+             "This should be an early exit only to a fatal error");
+      Result.setKind(tok::eof);
+      CurLexer->cutOffLexing();
+      EnterTokens(Suffix);
       return true;
-    auto *Info = Result.getAnnotationValueAs<ModuleNameInfo *>();
-    if (getLangOpts().CPlusPlusModules) {
-      // Under the standard C++ Modules, the dot is just part of the module
-      // name, and not a real hierarchy separator. Flatten such module names
-      // now.
-      //
-      // FIXME: Is this the right level to be performing this transformation?
-      std::string FlatModuleName;
-      if (Info->getTokens().front().is(tok::colon)) {
-        // Import a module partition allowed in C++20 Modules.
-        // We can import a partition in named module TU.
-        if (NamedModuleImportPath.empty() && ModuleDeclState.isNamedModule())
-          FlatModuleName = llvm::Twine(ModuleDeclState.getPrimaryName())
-                               .concat(Info->getFlatName())
-                               .str();
-        else
-          return true;
-      } else {
-        FlatModuleName = Info->getFlatName();
-      }
-      NamedModuleImportPath.emplace_back(getIdentifierInfo(FlatModuleName),
-                                         Result.getLocation());
-    } else {
-      Info->getModuleIdPath(NamedModuleImportPath);
     }
+
+    EnterTokens(Suffix);
+    return false;
+  }
+
+  // The token sequence
+  //
+  //   import identifier (. identifier)*
+  //
+  // indicates a module import directive. We already saw the 'import'
+  // contextual keyword, so now we're looking for the identifiers.
+  if (ModuleImportExpectsIdentifier && Result.getKind() == tok::identifier) {
+    // We expected to see an identifier here, and we did; continue handling
+    // identifiers.
+    NamedModuleImportPath.push_back(
+        std::make_pair(Result.getIdentifierInfo(), Result.getLocation()));
+    ModuleImportExpectsIdentifier = false;
+    CurLexerCallback = CLK_LexAfterModuleImport;
+    return true;
+  }
+
+  // If we're expecting a '.' or a ';', and we got a '.', then wait until we
+  // see the next identifier. (We can also see a '[[' that begins an
+  // attribute-specifier-seq here under the Standard C++ Modules.)
+  if (!ModuleImportExpectsIdentifier && Result.getKind() == tok::period) {
+    ModuleImportExpectsIdentifier = true;
+    CurLexerCallback = CLK_LexAfterModuleImport;
+    return true;
   }
 
   // If we didn't recognize a module name at all, this is not a (valid) import.
@@ -1458,6 +1291,24 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
     SemiLoc = Suffix.back().getLocation();
   }
 
+  // Under the standard C++ Modules, the dot is just part of the module name,
+  // and not a real hierarchy separator. Flatten such module names now.
+  //
+  // FIXME: Is this the right level to be performing this transformation?
+  std::string FlatModuleName;
+  if (getLangOpts().CPlusPlusModules) {
+    for (auto &Piece : NamedModuleImportPath) {
+      // If the FlatModuleName ends with colon, it implies it is a partition.
+      if (!FlatModuleName.empty() && FlatModuleName.back() != ':')
+        FlatModuleName += ".";
+      FlatModuleName += Piece.first->getName();
+    }
+    SourceLocation FirstPathLoc = NamedModuleImportPath[0].second;
+    NamedModuleImportPath.clear();
+    NamedModuleImportPath.push_back(
+        std::make_pair(getIdentifierInfo(FlatModuleName), FirstPathLoc));
+  }
+
   Module *Imported = nullptr;
   // We don't/shouldn't load the standard c++20 modules when preprocessing.
   if (getLangOpts().Modules && !isInImportingCXXNamedModules()) {
@@ -1479,33 +1330,6 @@ 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();
-  return LexModuleName(Result, /*IsImport=*/false);
-}
-
 void Preprocessor::makeModuleVisible(Module *M, SourceLocation Loc) {
   CurSubmoduleState->VisibleModules.setVisible(
       M, Loc, [](Module *) {},
diff --git a/clang/lib/Lex/TokenConcatenation.cpp b/clang/lib/Lex/TokenConcatenation.cpp
index cdb636923b9e9..865879d180533 100644
--- a/clang/lib/Lex/TokenConcatenation.cpp
+++ b/clang/lib/Lex/TokenConcatenation.cpp
@@ -160,13 +160,6 @@ static char GetFirstChar(const Preprocessor &PP, const Token &Tok) {
 bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
                                      const Token &PrevTok,
                                      const Token &Tok) const {
-  // If previous token is a module name, we need avoid concat it with current
-  // token, otherwise, there will has an extra space between 'M' and ';' for the
-  // following code:
-  //
-  // import M;
-  if (PrevTok.is(tok::annot_module_name))
-    return false;
   // Conservatively assume that every annotation token that has a printable
   // form requires whitespace.
   if (PrevTok.isAnnotation())
@@ -197,9 +190,6 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
       return true;
     ConcatInfo &= ~aci_avoid_equal;
   }
-
-  if (Tok.is(tok::annot_module_name))
-    return true;
   if (Tok.isAnnotation()) {
     // Modules annotation can show up when generated automatically for includes.
     assert(Tok.isOneOf(tok::annot_module_include, tok::annot_module_begin,
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 577527d0318f2..7ce9a9cea1c7a 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3958,13 +3958,7 @@ void Parser::ParseDeclarationSpecifiers(
 
       // We're done with the declaration-specifiers.
       goto DoneWithDeclSpec;
-    case tok::annot_module_name: {
-      PP.EnterTokenStream(
-          Tok.getAnnotationValueAs<ModuleNameInfo *>()->getTokens(),
-          /*DisableMacroExpansion=*/true, /*IsReinject=*/false);
-      ConsumeAnyToken();
-      [[fallthrough]];
-    }
+
       // typedef-name
     case tok::kw___super:
     case tok::kw_decltype:
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index afb2e1e416168..5ebe71e496a2e 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -2511,28 +2511,18 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) {
   }
 
   SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
-  if (Tok.isNot(tok::annot_module_name)) {
-    Diag(Tok, diag::err_module_expected_ident) << /*IsImport=*/false;
-    SkipUntil(tok::semi, StopBeforeMatch);
-    return nullptr;
-  }
-
-  auto *Info = Tok.getAnnotationValueAs<ModuleNameInfo *>();
-  ConsumeAnnotationToken();
-  if (ParseModuleName(ModuleLoc, Info->getModuleName(), Path,
-                      /*IsImport=*/false))
+  if (ParseModuleName(ModuleLoc, Path, /*IsImport*/ false))
     return nullptr;
 
   // Parse the optional module-partition.
   SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition;
-  if (Info->hasPartitionName()) {
-    SourceLocation ColonLoc = Info->getColonToken().getLocation();
+  if (Tok.is(tok::colon)) {
+    SourceLocation ColonLoc = ConsumeToken();
     if (!getLangOpts().CPlusPlusModules)
       Diag(ColonLoc, diag::err_unsupported_module_partition)
           << SourceRange(ColonLoc, Partition.back().second);
     // Recover by ignoring the partition name.
-    else if (ParseModuleName(ModuleLoc, Info->getPartitionName(), Partition,
-                             /*IsImport=*/false))
+    else if (ParseModuleName(ModuleLoc, Partition, /*IsImport*/ false))
       return nullptr;
   }
 
@@ -2591,32 +2581,18 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
     // This is a header import that the preprocessor mapped to a module import.
     HeaderUnit = reinterpret_cast<Module *>(Tok.getAnnotationValue());
     ConsumeAnnotationToken();
-  } else {
-    if (Tok.isNot(tok::annot_module_name)) {
-      if (Tok.is(tok::code_completion)) {
-        cutOffParsing();
-        Actions.CodeCompletion().CodeCompleteModuleImport(ImportLoc, Path);
-        return nullptr;
-      }
-      Diag(Tok, diag::err_module_expected_ident) << /*IsImport=*/true;
-      SkipUntil(tok::semi, StopBeforeMatch);
+  } else if (Tok.is(tok::colon)) {
+    SourceLocation ColonLoc = ConsumeToken();
+    if (!getLangOpts().CPlusPlusModules)
+      Diag(ColonLoc, diag::err_unsupported_module_partition)
+          << SourceRange(ColonLoc, Path.back().second);
+    // Recover by leaving partition empty.
+    else if (ParseModuleName(ColonLoc, Path, /*IsImport*/ true))
       return nullptr;
-    }
-    auto *Info = Tok.getAnnotationValueAs<ModuleNameInfo *>();
-    ConsumeAnnotationToken();
-    if (Info->hasPartitionName()) {
-      SourceLocation ColonLoc = Info->getColonToken().getLocation();
-      if (!getLangOpts().CPlusPlusModules)
-        Diag(ColonLoc, diag::err_unsupported_module_partition)
-            << SourceRange(ColonLoc, Path.back().second);
-      // Recover by leaving partition empty.
-      else if (ParseModuleName(ColonLoc, Info->getPartitionName(), Path,
-                               /*IsImport=*/true))
-        return nullptr;
-      else
-        IsPartition = true;
-    } else if (ParseModuleName(ImportLoc, Info->getModuleName(), Path,
-                               /*IsImport=*/true))
+    else
+      IsPartition = true;
+  } else {
+    if (ParseModuleName(ImportLoc, Path, /*IsImport*/ true))
       return nullptr;
   }
 
@@ -2713,31 +2689,32 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
 ///         module-name-qualifier:
 ///           module-name-qualifier[opt] identifier '.'
 bool Parser::ParseModuleName(
-    SourceLocation UseLoc, ArrayRef<Token> ModuleName,
+    SourceLocation UseLoc,
     SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path,
     bool IsImport) {
-  ModuleNameInfo::getModuleIdPath(ModuleName, Path);
-  // Eg. import A.B.
-  if (ModuleName.back().isNot(tok::identifier)) {
-    if (Tok.is(tok::code_completion)) {
-      cutOffParsing();
-      Actions.CodeCompletion().CodeCompleteModuleImport(UseLoc, Path);
+  // Parse the module path.
+  while (true) {
+    if (!Tok.is(tok::identifier)) {
+      if (Tok.is(tok::code_completion)) {
+        cutOffParsing();
+        Actions.CodeCompletion().CodeCompleteModuleImport(UseLoc, Path);
+        return true;
+      }
+
+      Diag(Tok, diag::err_module_expected_ident) << IsImport;
+      SkipUntil(tok::semi);
       return true;
     }
-    Diag(ModuleName.back(), diag::err_module_expected_ident) << IsImport;
-    SkipUntil(tok::semi, StopBeforeMatch);
-    return true;
-  }
 
-  // [cpp.module]/p2: where the pp-tokens (if any) shall not begin with a (
-  // preprocessing token [...]
-  //
-  // Skip unitl ';' to recovery.
-  if (getLangOpts().CPlusPlusModules && Tok.is(tok::l_paren)) {
-    SkipUntil(tok::semi, StopBeforeMatch);
-    return true;
+    // Record this part of the module path.
+    Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation()));
+    ConsumeToken();
+
+    if (Tok.isNot(tok::period))
+      return false;
+
+    ConsumeToken();
   }
-  return false;
 }
 
 /// Try recover parser when module annotation appears where it must not
diff --git a/clang/test/CXX/cpp/cpp.module/p2.cppm b/clang/test/CXX/cpp/cpp.module/p2.cppm
deleted file mode 100644
index 966a88ccfa972..0000000000000
--- a/clang/test/CXX/cpp/cpp.module/p2.cppm
+++ /dev/null
@@ -1,88 +0,0 @@
-// RUN: rm -rf %t
-// RUN: mkdir -p %t
-// RUN: split-file %s %t
-
-// 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
-// RUN: %clang_cc1 -std=c++20 %t/J.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
-#define ATTRS [[]]
-#define SEMICOLON ;
-
-#endif // VERSION_H
-
-//--- 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'}}
-
-//--- 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'}} \
-                        // expected-error {{the module name in a module declaration cannot contain an object-like macro 'B'}}
-
-//--- C.cppm
-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}}
-
-//--- D.cppm
-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}}
-
-//--- 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;                               // 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}}
-
-//--- H.cppm
-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}}
-
-//--- I.cppm
-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}}
-
-//--- 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/basic/basic.link/module-declaration.cpp b/clang/test/CXX/module/basic/basic.link/module-declaration.cpp
index 14bbc911febfc..d71358cc7a571 100644
--- a/clang/test/CXX/module/basic/basic.link/module-declaration.cpp
+++ b/clang/test/CXX/module/basic/basic.link/module-declaration.cpp
@@ -8,19 +8,27 @@
 // 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/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
+// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify -x c++ %t/M.cpp \
+// RUN:            -DTEST=1 -DEXPORT= -DMODULE_NAME=z
+// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x=%t/x.pcm -fmodule-file=x.y=%t/x.y.pcm -verify -x c++ %t/M.cpp \
+// RUN:            -DTEST=2 -DEXPORT= -DMODULE_NAME=x
 //
 // 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/M3.cpp
-// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M4.cpp
+// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \
+// RUN:            -DTEST=3 -DEXPORT=export -DMODULE_NAME=z
+// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \
+// RUN:            -DTEST=4 -DEXPORT=export -DMODULE_NAME=x
 //
 // Miscellaneous syntax.
-// 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
+// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \
+// RUN:            -DTEST=7 -DEXPORT=export -DMODULE_NAME='z elderberry'
+// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \
+// RUN:            -DTEST=8 -DEXPORT=export -DMODULE_NAME='z [[]]'
+// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \
+// RUN:            -DTEST=9 -DEXPORT=export -DMODULE_NAME='z [[fancy]]'
+// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -verify %t/M.cpp \
+// RUN:            -DTEST=10 -DEXPORT=export -DMODULE_NAME='z [[maybe_unused]]'
 
 //--- x.cppm
 export module x;
@@ -30,26 +38,17 @@ int a, b;
 export module x.y;
 int c;
 
-//--- M1.cpp
-module z; // expected-error {{module 'z' not found}}
-
-//--- M2.cpp
-module x; // expected-no-diagnostics
-
-//--- M3.cpp
-export module z; // expected-no-diagnostics
-
-//--- M4.cpp
-export module x; // expected-no-diagnostics
-
-//--- M5.cpp
-export module z elderberry; // expected-error {{expected ';'}} expected-error {{a type specifier is required}}
-
-//--- M6.cpp
-export module z [[]]; // expected-no-diagnostics
-
-//--- M7.cpp
-export module z [[fancy]]; // expected-warning {{unknown attribute 'fancy' ignored}}
-
-//--- M8.cpp
-export module z [[maybe_unused]]; // expected-error-re {{'maybe_unused' attribute cannot be applied to a module{{$}}}}
+//--- M.cpp
+
+EXPORT module MODULE_NAME;
+#if TEST == 7
+// expected-error at -2 {{expected ';'}} expected-error at -2 {{a type specifier is required}}
+#elif TEST == 9
+// expected-warning at -4 {{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}}
+#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 ecad4db32a7e9..873e4c0edeac2 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,12 +6,10 @@
 // RUN: %clang_cc1 -std=c++20 -emit-module-interface -fmodule-file=x=%t/x.pcm %t/x.y.cppm -o %t/x.y.pcm
 // RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/a.b.cppm -o %t/a.b.pcm
 //
-// RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm -verify %t/test-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 -verify %t/test.cpp \
+// RUN:            -DMODULE_NAME=z -DINTERFACE
 // RUN: %clang_cc1 -std=c++20 -I%t -fmodule-file=x.y=%t/x.y.pcm -fmodule-file=x=%t/x.pcm \
-// RUN:            -fmodule-file=a.b=%t/a.b.pcm -verify %t/test.cpp
-// 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:            -fmodule-file=a.b=%t/a.b.pcm -verify %t/test.cpp -DMODULE_NAME=a.b
 // 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
@@ -36,26 +34,11 @@ int use_2 = b; // ok
 int use_3 = c; // expected-error {{use of undeclared identifier 'c'}}
 
 //--- test.cpp
-module;
-module a.b;
-
-import x;
-
-import x [[]];
-import x [[foo]]; // expected-warning {{unknown attribute 'foo' ignored}}
-import x [[noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to a module import}}
-import x [[blarg::noreturn]]; // expected-warning {{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-interface.cpp
-module;
-export module z;
+#ifdef INTERFACE
+export module MODULE_NAME;
+#else
+module MODULE_NAME;
+#endif
 
 import x;
 
@@ -68,10 +51,6 @@ 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}}
 
+int use_4 = c; // ok
diff --git a/clang/test/SemaCXX/modules.cppm b/clang/test/SemaCXX/modules.cppm
index 267417bf5da2c..41204be76eafa 100644
--- a/clang/test/SemaCXX/modules.cppm
+++ b/clang/test/SemaCXX/modules.cppm
@@ -1,17 +1,19 @@
-// RUN: rm -rf %t
-// RUN: mkdir -p %t
-// RUN: split-file %s %t
+// 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: %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
+#if TEST == 0 || TEST == 2
+// expected-no-diagnostics
+#endif
 
-//--- A.cppm
 export module foo;
+
 static int m;
+
 int n;
+
+#if TEST == 0
 export {
   int a;
   int b;
@@ -25,43 +27,7 @@ export void f() {}
 
 export struct T {
 } t;
-// 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;
+#elif TEST == 3
 int use_a = a; // expected-error {{use of undeclared identifier 'a'}}
 
 #undef foo
@@ -80,12 +46,29 @@ 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
 
-//--- E.cppm
-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'}}
+#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
 
-#undef foo
-import foo; // expected-error {{imports must immediately follow the module declaration}}
+// FIXME: Exports of declarations without external linkage are disallowed.
+// Exports of declarations with non-external-linkage types are disallowed.
+
+// Cannot export within another export. This isn't precisely covered by the
+// language rules right now, but (per personal correspondence between zygoloid
+// and gdr) is the intent.
+#if TEST == 1
+export { // expected-note {{export block begins here}}
+  extern "C++" {
+  namespace NestedExport {
+  export { // expected-error {{export declaration appears within another export declaration}}
+    int q;
+  }
+  } // namespace NestedExport
+  }
+}
+#endif
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 1f69a4e8a5620..a6ded8be3ae9e 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="unreleased" align="center">Clang 19</td>
+  <td class="none" align="center">No</td>
  </tr>
  <tr>
   <td>Trivial infinite loops are not Undefined Behavior</td>



More information about the cfe-commits mailing list