https://github.com/yronglin updated 
https://github.com/llvm/llvm-project/pull/153641

>From 62ab3571fd1c528bab72193deaf0171028d4bb39 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin...@gmail.com>
Date: Fri, 15 Aug 2025 02:12:23 +0800
Subject: [PATCH 1/2] [clang] Allow no trivial before C++ module directive

Signed-off-by: yronglin <yronglin...@gmail.com>
---
 clang/include/clang/Lex/Lexer.h               |   3 -
 clang/include/clang/Lex/Preprocessor.h        |  11 +
 clang/include/clang/Lex/Token.h               |  15 +-
 .../clang/Lex/TrivialDirectiveTracer.h        | 388 ++++++++++++++++++
 clang/include/clang/Sema/Sema.h               |   2 +-
 clang/lib/Lex/Lexer.cpp                       |   9 -
 clang/lib/Lex/Preprocessor.cpp                |  46 ++-
 clang/lib/Parse/Parser.cpp                    |   8 +-
 clang/lib/Sema/SemaModule.cpp                 |   6 +-
 clang/test/CXX/module/cpp.pre/module_decl.cpp | 141 ++++++-
 clang/unittests/Lex/LexerTest.cpp             |   4 +-
 11 files changed, 601 insertions(+), 32 deletions(-)
 create mode 100644 clang/include/clang/Lex/TrivialDirectiveTracer.h

diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h
index 06971ff87ab96..423f2ffe2f852 100644
--- a/clang/include/clang/Lex/Lexer.h
+++ b/clang/include/clang/Lex/Lexer.h
@@ -143,9 +143,6 @@ class Lexer : public PreprocessorLexer {
   /// True if this is the first time we're lexing the input file.
   bool IsFirstTimeLexingFile;
 
-  /// True if current lexing token is the first pp-token.
-  bool IsFirstPPToken;
-
   // NewLinePtr - A pointer to new line character '\n' being lexed. For '\r\n',
   // it also points to '\n.'
   const char *NewLinePtr;
diff --git a/clang/include/clang/Lex/Preprocessor.h 
b/clang/include/clang/Lex/Preprocessor.h
index 71b0f8eab3bfa..d51faad255224 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -82,6 +82,7 @@ class PreprocessorLexer;
 class PreprocessorOptions;
 class ScratchBuffer;
 class TargetInfo;
+class TrivialDirectiveTracer;
 
 namespace Builtin {
 class Context;
@@ -353,6 +354,11 @@ class Preprocessor {
   /// First pp-token source location in current translation unit.
   SourceLocation FirstPPTokenLoc;
 
+  /// A preprocessor directive tracer to trace whether the preprocessing
+  /// state changed. These changes would mean most semantically observable
+  /// preprocessor state, particularly anything that is order dependent.
+  TrivialDirectiveTracer *DirTracer = nullptr;
+
   /// A position within a C++20 import-seq.
   class StdCXXImportSeq {
   public:
@@ -609,6 +615,8 @@ class Preprocessor {
       return State == NamedModuleImplementation && !getName().contains(':');
     }
 
+    bool isNotAModuleDecl() const { return State == NotAModuleDecl; }
+
     StringRef getName() const {
       assert(isNamedModule() && "Can't get name from a non named module");
       return Name;
@@ -3091,6 +3099,9 @@ class Preprocessor {
   bool setDeserializedSafeBufferOptOutMap(
       const SmallVectorImpl<SourceLocation> &SrcLocSeqs);
 
+  /// Whether allow C++ module directive.
+  bool hasSeenNoTrivialPPDirective() const;
+
 private:
   /// Helper functions to forward lexing to the actual lexer. They all share 
the
   /// same signature.
diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h
index fc43e72593b94..c493571e00038 100644
--- a/clang/include/clang/Lex/Token.h
+++ b/clang/include/clang/Lex/Token.h
@@ -86,12 +86,10 @@ class Token {
                                 // macro stringizing or charizing operator.
     CommaAfterElided = 0x200, // The comma following this token was elided 
(MS).
     IsEditorPlaceholder = 0x400, // This identifier is a placeholder.
-
-    IsReinjected = 0x800,  // A phase 4 token that was produced before and
-                           // re-added, e.g. via EnterTokenStream. Annotation
-                           // tokens are *not* reinjected.
-    FirstPPToken = 0x1000, // This token is the first pp token in the
-                           // translation unit.
+    IsReinjected = 0x800,        // A phase 4 token that was produced before 
and
+                          // re-added, e.g. via EnterTokenStream. Annotation
+                          // tokens are *not* reinjected.
+    SeenNoTrivialPPDirective = 0x1000,
   };
 
   tok::TokenKind getKind() const { return Kind; }
@@ -321,8 +319,9 @@ class Token {
   /// lexer uses identifier tokens to represent placeholders.
   bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); }
 
-  /// Returns true if this token is the first pp-token.
-  bool isFirstPPToken() const { return getFlag(FirstPPToken); }
+  bool hasSeenNoTrivialPPDirective() const {
+    return getFlag(SeenNoTrivialPPDirective);
+  }
 };
 
 /// Information about the conditional stack (\#if directives)
diff --git a/clang/include/clang/Lex/TrivialDirectiveTracer.h 
b/clang/include/clang/Lex/TrivialDirectiveTracer.h
new file mode 100644
index 0000000000000..9d4e0fdc96daf
--- /dev/null
+++ b/clang/include/clang/Lex/TrivialDirectiveTracer.h
@@ -0,0 +1,388 @@
+//===--- TrivialDirectiveTracer.h -------------------------------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the TrivialDirectiveTracer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LEX_TRIVIAL_DIRECTIVE_TRACER_H
+#define LLVM_CLANG_LEX_TRIVIAL_DIRECTIVE_TRACER_H
+
+#include "clang/Lex/PPCallbacks.h"
+
+namespace clang {
+class Preprocessor;
+
+class TrivialDirectiveTracer : public PPCallbacks {
+  Preprocessor &PP;
+  bool InMainFile = true;
+  bool SeenNoTrivialPPDirective = false;
+
+  void setSeenNoTrivialPPDirective(bool Val);
+
+public:
+  TrivialDirectiveTracer(Preprocessor &P) : PP(P) {}
+
+  bool hasSeenNoTrivialPPDirective() const;
+
+  /// Callback invoked whenever a source file is entered or exited.
+  ///
+  /// \param Loc Indicates the new location.
+  /// \param PrevFID the file that was exited if \p Reason is ExitFile or the
+  /// the file before the new one entered for \p Reason EnterFile.
+  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+                   SrcMgr::CharacteristicKind FileType,
+                   FileID PrevFID = FileID()) override;
+
+  /// Callback invoked whenever the \p Lexer moves to a different file for
+  /// lexing. Unlike \p FileChanged line number directives and other related
+  /// pragmas do not trigger callbacks to \p LexedFileChanged.
+  ///
+  /// \param FID The \p FileID that the \p Lexer moved to.
+  ///
+  /// \param Reason Whether the \p Lexer entered a new file or exited one.
+  ///
+  /// \param FileType The \p CharacteristicKind of the file the \p Lexer moved
+  /// to.
+  ///
+  /// \param PrevFID The \p FileID the \p Lexer was using before the change.
+  ///
+  /// \param Loc The location where the \p Lexer entered a new file from or the
+  /// location that the \p Lexer moved into after exiting a file.
+  void LexedFileChanged(FileID FID, LexedFileChangeReason Reason,
+                        SrcMgr::CharacteristicKind FileType, FileID PrevFID,
+                        SourceLocation Loc) override;
+
+  /// Callback invoked whenever an embed directive has been processed,
+  /// regardless of whether the embed will actually find a file.
+  ///
+  /// \param HashLoc The location of the '#' that starts the embed directive.
+  ///
+  /// \param FileName The name of the file being included, as written in the
+  /// source code.
+  ///
+  /// \param IsAngled Whether the file name was enclosed in angle brackets;
+  /// otherwise, it was enclosed in quotes.
+  ///
+  /// \param File The actual file that may be included by this embed directive.
+  ///
+  /// \param Params The parameters used by the directive.
+  void EmbedDirective(SourceLocation HashLoc, StringRef FileName, bool 
IsAngled,
+                      OptionalFileEntryRef File,
+                      const LexEmbedParametersResult &Params) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+
+  /// Callback invoked whenever an inclusion directive of
+  /// any kind (\c \#include, \c \#import, etc.) has been processed, regardless
+  /// of whether the inclusion will actually result in an inclusion.
+  ///
+  /// \param HashLoc The location of the '#' that starts the inclusion
+  /// directive.
+  ///
+  /// \param IncludeTok The token that indicates the kind of inclusion
+  /// directive, e.g., 'include' or 'import'.
+  ///
+  /// \param FileName The name of the file being included, as written in the
+  /// source code.
+  ///
+  /// \param IsAngled Whether the file name was enclosed in angle brackets;
+  /// otherwise, it was enclosed in quotes.
+  ///
+  /// \param FilenameRange The character range of the quotes or angle brackets
+  /// for the written file name.
+  ///
+  /// \param File The actual file that may be included by this inclusion
+  /// directive.
+  ///
+  /// \param SearchPath Contains the search path which was used to find the 
file
+  /// in the file system. If the file was found via an absolute include path,
+  /// SearchPath will be empty. For framework includes, the SearchPath and
+  /// RelativePath will be split up. For example, if an include of 
"Some/Some.h"
+  /// is found via the framework path
+  /// "path/to/Frameworks/Some.framework/Headers/Some.h", SearchPath will be
+  /// "path/to/Frameworks/Some.framework/Headers" and RelativePath will be
+  /// "Some.h".
+  ///
+  /// \param RelativePath The path relative to SearchPath, at which the include
+  /// file was found. This is equal to FileName except for framework includes.
+  ///
+  /// \param SuggestedModule The module suggested for this header, if any.
+  ///
+  /// \param ModuleImported Whether this include was translated into import of
+  /// \p SuggestedModule.
+  ///
+  /// \param FileType The characteristic kind, indicates whether a file or
+  /// directory holds normal user code, system code, or system code which is
+  /// implicitly 'extern "C"' in C++ mode.
+  ///
+  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+                          StringRef FileName, bool IsAngled,
+                          CharSourceRange FilenameRange,
+                          OptionalFileEntryRef File, StringRef SearchPath,
+                          StringRef RelativePath, const Module 
*SuggestedModule,
+                          bool ModuleImported,
+                          SrcMgr::CharacteristicKind FileType) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+
+  /// Callback invoked whenever there was an explicit module-import
+  /// syntax.
+  ///
+  /// \param ImportLoc The location of import directive token.
+  ///
+  /// \param Path The identifiers (and their locations) of the module
+  /// "path", e.g., "std.vector" would be split into "std" and "vector".
+  ///
+  /// \param Imported The imported module; can be null if importing failed.
+  ///
+  void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path,
+                    const Module *Imported) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+
+  /// Callback invoked when the end of the main file is reached.
+  ///
+  /// No subsequent callbacks will be made.
+  void EndOfMainFile() override { setSeenNoTrivialPPDirective(true); }
+
+  /// Callback invoked when a \#ident or \#sccs directive is read.
+  /// \param Loc The location of the directive.
+  /// \param str The text of the directive.
+  ///
+  void Ident(SourceLocation Loc, StringRef str) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when start reading any pragma directive.
+  void PragmaDirective(SourceLocation Loc,
+                       PragmaIntroducerKind Introducer) override {}
+
+  /// Callback invoked when a \#pragma comment directive is read.
+  void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
+                     StringRef Str) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma mark comment is read.
+  void PragmaMark(SourceLocation Loc, StringRef Trivia) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma detect_mismatch directive is
+  /// read.
+  void PragmaDetectMismatch(SourceLocation Loc, StringRef Name,
+                            StringRef Value) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma clang __debug directive is read.
+  /// \param Loc The location of the debug directive.
+  /// \param DebugType The identifier following __debug.
+  void PragmaDebug(SourceLocation Loc, StringRef DebugType) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma message directive is read.
+  /// \param Loc The location of the message directive.
+  /// \param Namespace The namespace of the message directive.
+  /// \param Kind The type of the message directive.
+  /// \param Str The text of the message directive.
+  void PragmaMessage(SourceLocation Loc, StringRef Namespace,
+                     PragmaMessageKind Kind, StringRef Str) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma gcc diagnostic push directive
+  /// is read.
+  void PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma gcc diagnostic pop directive
+  /// is read.
+  void PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma gcc diagnostic directive is read.
+  void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
+                        diag::Severity mapping, StringRef Str) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Called when an OpenCL extension is either disabled or
+  /// enabled with a pragma.
+  void PragmaOpenCLExtension(SourceLocation NameLoc, const IdentifierInfo 
*Name,
+                             SourceLocation StateLoc, unsigned State) override 
{
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma warning directive is read.
+  void PragmaWarning(SourceLocation Loc, PragmaWarningSpecifier WarningSpec,
+                     ArrayRef<int> Ids) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma warning(push) directive is read.
+  void PragmaWarningPush(SourceLocation Loc, int Level) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma warning(pop) directive is read.
+  void PragmaWarningPop(SourceLocation Loc) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma execution_character_set(push) directive
+  /// is read.
+  void PragmaExecCharsetPush(SourceLocation Loc, StringRef Str) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma execution_character_set(pop) directive
+  /// is read.
+  void PragmaExecCharsetPop(SourceLocation Loc) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma clang assume_nonnull begin directive
+  /// is read.
+  void PragmaAssumeNonNullBegin(SourceLocation Loc) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Callback invoked when a \#pragma clang assume_nonnull end directive
+  /// is read.
+  void PragmaAssumeNonNullEnd(SourceLocation Loc) override {
+    setSeenNoTrivialPPDirective(false);
+  }
+
+  /// Called by Preprocessor::HandleMacroExpandedIdentifier when a
+  /// macro invocation is found.
+  void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
+                    SourceRange Range, const MacroArgs *Args) override;
+
+  /// Hook called whenever a macro definition is seen.
+  void MacroDefined(const Token &MacroNameTok,
+                    const MacroDirective *MD) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+
+  /// Hook called whenever a macro \#undef is seen.
+  /// \param MacroNameTok The active Token
+  /// \param MD A MacroDefinition for the named macro.
+  /// \param Undef New MacroDirective if the macro was defined, null otherwise.
+  ///
+  /// MD is released immediately following this callback.
+  void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
+                      const MacroDirective *Undef) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+
+  /// Hook called whenever the 'defined' operator is seen.
+  /// \param MD The MacroDirective if the name was a macro, null otherwise.
+  void Defined(const Token &MacroNameTok, const MacroDefinition &MD,
+               SourceRange Range) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+
+  /// Hook called whenever an \#if is seen.
+  /// \param Loc the source location of the directive.
+  /// \param ConditionRange The SourceRange of the expression being tested.
+  /// \param ConditionValue The evaluated value of the condition.
+  ///
+  // FIXME: better to pass in a list (or tree!) of Tokens.
+  void If(SourceLocation Loc, SourceRange ConditionRange,
+          ConditionValueKind ConditionValue) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+
+  /// Hook called whenever an \#elif is seen.
+  /// \param Loc the source location of the directive.
+  /// \param ConditionRange The SourceRange of the expression being tested.
+  /// \param ConditionValue The evaluated value of the condition.
+  /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
+  // FIXME: better to pass in a list (or tree!) of Tokens.
+  void Elif(SourceLocation Loc, SourceRange ConditionRange,
+            ConditionValueKind ConditionValue, SourceLocation IfLoc) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+
+  /// Hook called whenever an \#ifdef is seen.
+  /// \param Loc the source location of the directive.
+  /// \param MacroNameTok Information on the token being tested.
+  /// \param MD The MacroDefinition if the name was a macro, null otherwise.
+  void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
+             const MacroDefinition &MD) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+
+  /// Hook called whenever an \#elifdef branch is taken.
+  /// \param Loc the source location of the directive.
+  /// \param MacroNameTok Information on the token being tested.
+  /// \param MD The MacroDefinition if the name was a macro, null otherwise.
+  void Elifdef(SourceLocation Loc, const Token &MacroNameTok,
+               const MacroDefinition &MD) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+  /// Hook called whenever an \#elifdef is skipped.
+  /// \param Loc the source location of the directive.
+  /// \param ConditionRange The SourceRange of the expression being tested.
+  /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
+  // FIXME: better to pass in a list (or tree!) of Tokens.
+  void Elifdef(SourceLocation Loc, SourceRange ConditionRange,
+               SourceLocation IfLoc) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+
+  /// Hook called whenever an \#ifndef is seen.
+  /// \param Loc the source location of the directive.
+  /// \param MacroNameTok Information on the token being tested.
+  /// \param MD The MacroDefiniton if the name was a macro, null otherwise.
+  void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
+              const MacroDefinition &MD) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+
+  /// Hook called whenever an \#elifndef branch is taken.
+  /// \param Loc the source location of the directive.
+  /// \param MacroNameTok Information on the token being tested.
+  /// \param MD The MacroDefinition if the name was a macro, null otherwise.
+  void Elifndef(SourceLocation Loc, const Token &MacroNameTok,
+                const MacroDefinition &MD) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+  /// Hook called whenever an \#elifndef is skipped.
+  /// \param Loc the source location of the directive.
+  /// \param ConditionRange The SourceRange of the expression being tested.
+  /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
+  // FIXME: better to pass in a list (or tree!) of Tokens.
+  void Elifndef(SourceLocation Loc, SourceRange ConditionRange,
+                SourceLocation IfLoc) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+
+  /// Hook called whenever an \#else is seen.
+  /// \param Loc the source location of the directive.
+  /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
+  void Else(SourceLocation Loc, SourceLocation IfLoc) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+
+  /// Hook called whenever an \#endif is seen.
+  /// \param Loc the source location of the directive.
+  /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
+  void Endif(SourceLocation Loc, SourceLocation IfLoc) override {
+    setSeenNoTrivialPPDirective(true);
+  }
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_LEX_TRIVIAL_DIRECTIVE_TRACER_H
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 1dfc276147fd4..b15c9615bebc3 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -9836,7 +9836,7 @@ class Sema final : public SemaBase {
                                  SourceLocation ModuleLoc, ModuleDeclKind MDK,
                                  ModuleIdPath Path, ModuleIdPath Partition,
                                  ModuleImportState &ImportState,
-                                 bool IntroducerIsFirstPPToken);
+                                 bool SeenNoTrivialPPDirective);
 
   /// The parser has processed a global-module-fragment declaration that begins
   /// the definition of the global module fragment of the current module unit.
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 1f695b4a8676c..b282a600c0e56 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -174,8 +174,6 @@ void Lexer::InitLexer(const char *BufStart, const char 
*BufPtr,
   ExtendedTokenMode = 0;
 
   NewLinePtr = nullptr;
-
-  IsFirstPPToken = true;
 }
 
 /// Lexer constructor - Create a new lexer object for the specified buffer
@@ -3225,7 +3223,6 @@ std::optional<Token> Lexer::peekNextPPToken() {
   bool atStartOfLine = IsAtStartOfLine;
   bool atPhysicalStartOfLine = IsAtPhysicalStartOfLine;
   bool leadingSpace = HasLeadingSpace;
-  bool isFirstPPToken = IsFirstPPToken;
 
   Token Tok;
   Lex(Tok);
@@ -3236,7 +3233,6 @@ std::optional<Token> Lexer::peekNextPPToken() {
   HasLeadingSpace = leadingSpace;
   IsAtStartOfLine = atStartOfLine;
   IsAtPhysicalStartOfLine = atPhysicalStartOfLine;
-  IsFirstPPToken = isFirstPPToken;
   // Restore the lexer back to non-skipping mode.
   LexingRawMode = false;
 
@@ -3726,11 +3722,6 @@ bool Lexer::Lex(Token &Result) {
     HasLeadingEmptyMacro = false;
   }
 
-  if (IsFirstPPToken) {
-    Result.setFlag(Token::FirstPPToken);
-    IsFirstPPToken = false;
-  }
-
   bool atPhysicalStartOfLine = IsAtPhysicalStartOfLine;
   IsAtPhysicalStartOfLine = false;
   bool isRawLex = isLexingRawMode();
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index e278846f6f36d..dd5ab0e19ecd4 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -50,6 +50,7 @@
 #include "clang/Lex/ScratchBuffer.h"
 #include "clang/Lex/Token.h"
 #include "clang/Lex/TokenLexer.h"
+#include "clang/Lex/TrivialDirectiveTracer.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
@@ -247,8 +248,6 @@ void Preprocessor::DumpToken(const Token &Tok, bool 
DumpFlags) const {
     llvm::errs() << " [LeadingSpace]";
   if (Tok.isExpandDisabled())
     llvm::errs() << " [ExpandDisabled]";
-  if (Tok.isFirstPPToken())
-    llvm::errs() << " [First pp-token]";
   if (Tok.needsCleaning()) {
     const char *Start = SourceMgr.getCharacterData(Tok.getLocation());
     llvm::errs() << " [UnClean='" << StringRef(Start, Tok.getLength())
@@ -577,8 +576,11 @@ void Preprocessor::EnterMainSourceFile() {
     // export module M; // error: module declaration must occur
     //                  //        at the start of the translation unit.
     if (getLangOpts().CPlusPlusModules) {
+      auto Tracer = std::make_unique<TrivialDirectiveTracer>(*this);
+      DirTracer = Tracer.get();
+      addPPCallbacks(std::move(Tracer));
       std::optional<Token> FirstPPTok = CurLexer->peekNextPPToken();
-      if (FirstPPTok && FirstPPTok->isFirstPPToken())
+      if (FirstPPTok)
         FirstPPTokenLoc = FirstPPTok->getLocation();
     }
   }
@@ -940,6 +942,8 @@ void Preprocessor::Lex(Token &Result) {
       StdCXXImportSeqState.handleHeaderName();
       break;
     case tok::kw_export:
+      if (hasSeenNoTrivialPPDirective())
+        Result.setFlag(Token::SeenNoTrivialPPDirective);
       TrackGMFState.handleExport();
       StdCXXImportSeqState.handleExport();
       ModuleDeclState.handleExport();
@@ -968,6 +972,8 @@ void Preprocessor::Lex(Token &Result) {
           }
           break;
         } else if (Result.getIdentifierInfo() == getIdentifierInfo("module")) {
+          if (hasSeenNoTrivialPPDirective())
+            Result.setFlag(Token::SeenNoTrivialPPDirective);
           TrackGMFState.handleModule(StdCXXImportSeqState.afterTopLevelSeq());
           ModuleDeclState.handleModule();
           break;
@@ -1682,3 +1688,37 @@ const char *Preprocessor::getCheckPoint(FileID FID, 
const char *Start) const {
 
   return nullptr;
 }
+
+/// Whether allow C++ module directive.
+bool Preprocessor::hasSeenNoTrivialPPDirective() const {
+  return DirTracer && DirTracer->hasSeenNoTrivialPPDirective();
+}
+
+bool TrivialDirectiveTracer::hasSeenNoTrivialPPDirective() const {
+  return SeenNoTrivialPPDirective;
+}
+
+void TrivialDirectiveTracer::setSeenNoTrivialPPDirective(bool Val) {
+  if (InMainFile && !SeenNoTrivialPPDirective && Val)
+    SeenNoTrivialPPDirective = Val;
+}
+
+void TrivialDirectiveTracer::FileChanged(SourceLocation Loc,
+                                         FileChangeReason Reason,
+                                         SrcMgr::CharacteristicKind FileType,
+                                         FileID PrevFID) {
+  setSeenNoTrivialPPDirective(false);
+}
+
+void TrivialDirectiveTracer::LexedFileChanged(
+    FileID FID, LexedFileChangeReason Reason,
+    SrcMgr::CharacteristicKind FileType, FileID PrevFID, SourceLocation Loc) {
+  InMainFile = FID == PP.getSourceManager().getMainFileID();
+}
+
+void TrivialDirectiveTracer::MacroExpands(const Token &MacroNameTok,
+                                          const MacroDefinition &MD,
+                                          SourceRange Range,
+                                          const MacroArgs *Args) {
+  setSeenNoTrivialPPDirective(!MD.getMacroInfo()->isBuiltinMacro());
+}
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index e57a789251a5b..6e0f22498a147 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -2363,9 +2363,10 @@ Parser::ParseModuleDecl(Sema::ModuleImportState 
&ImportState) {
   // Parse a global-module-fragment, if present.
   if (getLangOpts().CPlusPlusModules && Tok.is(tok::semi)) {
     SourceLocation SemiLoc = ConsumeToken();
-    if (!Introducer.isFirstPPToken()) {
+    if (ImportState != Sema::ModuleImportState::FirstDecl ||
+        Introducer.hasSeenNoTrivialPPDirective()) {
       Diag(StartLoc, diag::err_global_module_introducer_not_at_start)
-        << SourceRange(StartLoc, SemiLoc);
+          << SourceRange(StartLoc, SemiLoc);
       return nullptr;
     }
     if (MDK == Sema::ModuleDeclKind::Interface) {
@@ -2420,7 +2421,8 @@ Parser::ParseModuleDecl(Sema::ModuleImportState 
&ImportState) {
   ExpectAndConsumeSemi(diag::err_module_expected_semi);
 
   return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, Partition,
-                                 ImportState, Introducer.isFirstPPToken());
+                                 ImportState,
+                                 Introducer.hasSeenNoTrivialPPDirective());
 }
 
 Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index ff9f85f960d93..1ecc5c747695f 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -265,10 +265,11 @@ Sema::DeclGroupPtrTy
 Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
                       ModuleDeclKind MDK, ModuleIdPath Path,
                       ModuleIdPath Partition, ModuleImportState &ImportState,
-                      bool IntroducerIsFirstPPToken) {
+                      bool SeenNoTrivialPPDirective) {
   assert(getLangOpts().CPlusPlusModules &&
          "should only have module decl in standard C++ modules");
 
+  bool IsFirstDecl = ImportState == ModuleImportState::FirstDecl;
   bool SeenGMF = ImportState == ModuleImportState::GlobalFragment;
   // If any of the steps here fail, we count that as invalidating C++20
   // module state;
@@ -336,7 +337,8 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, 
SourceLocation ModuleLoc,
 
   // In C++20, A module directive may only appear as the first preprocessing
   // tokens in a file (excluding the global module fragment.).
-  if (getLangOpts().CPlusPlusModules && !IntroducerIsFirstPPToken && !SeenGMF) 
{
+  if (getLangOpts().CPlusPlusModules &&
+      (!IsFirstDecl || SeenNoTrivialPPDirective) && !SeenGMF) {
     Diag(ModuleLoc, diag::err_module_decl_not_at_start);
     SourceLocation BeginLoc = PP.getMainFileFirstPPTokenLoc();
     Diag(BeginLoc, diag::note_global_module_introducer_missing)
diff --git a/clang/test/CXX/module/cpp.pre/module_decl.cpp 
b/clang/test/CXX/module/cpp.pre/module_decl.cpp
index 6238347c167ac..5c29aeff1b632 100644
--- a/clang/test/CXX/module/cpp.pre/module_decl.cpp
+++ b/clang/test/CXX/module/cpp.pre/module_decl.cpp
@@ -1,8 +1,147 @@
 // RUN: rm -rf %t
 // RUN: mkdir -p %t
-// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -verify -o %t/M.pcm
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/line.cpp -verify -o 
%t/line.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/gnu_line_marker.cpp 
-verify -o %t/gnu_line_marker.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/include.cpp -verify -o 
%t/include.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/ident.cpp -verify -o 
%t/ident.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/pragma_comment.cpp 
-verify -o %t/pragma_comment.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/pragma_mark.cpp 
-verify -o %t/pragma_mark.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface 
%t/pragma_detect_mismatch.cpp -verify -o %t/pragma_detect_mismatch.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/pragma_clang_debug.cpp 
-verify -o %t/pragma_clang_debug.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/pragma_message.cpp 
-verify -o %t/pragma_message.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/pragma_gcc_warn.cpp 
-verify -o %t/pragma_gcc_warn.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/pragma_gcc_error.cpp 
-verify -o %t/pragma_gcc_error.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface 
%t/pragma_diag_push_pop.cpp -verify -o %t/pragma_diag_push_pop.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/pragma_diag_ignore.cpp 
-verify -o %t/pragma_diag_ignore.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/pragma_opencl_ext.cpp 
-verify -o %t/pragma_opencl_ext.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/pragma_push_pop.cpp 
-verify -o %t/pragma_push_pop.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface 
%t/pragma_exec_charset.cpp -verify -o %t/pragma_exec_charset.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface 
%t/pragma_clang_assume_nonnull.cpp -verify -o %t/pragma_clang_assume_nonnull.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/marco_expand.cpp 
-DMACRO="" -verify -o %t/marco_expand.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/define.cpp -verify -o 
%t/define.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/undef.cpp -verify -o 
%t/undef.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/defined.cpp -verify -o 
%t/defined.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/has_embed.cpp -verify 
-o %t/has_embed.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/has_include.cpp 
-verify -o %t/has_include.pcm
 
+//--- header.h
+#ifndef HEADER_H
+#define HEADER_H
+
+#endif // HEADER_H
+
+//--- line.cpp
+// expected-no-diagnostics
+#line 3
+export module M;
+
+//--- gnu_line_marker.cpp
+// expected-no-diagnostics
+# 1 __FILE__ 1 3
+export module M;
+
+//--- include.cpp
+#include "header.h" // expected-note {{add 'module;' to the start of the file 
to introduce a global module fragment}}
+export module M; // expected-error {{module declaration must occur at the 
start of the translation unit}}
+
+//--- ident.cpp
+// expected-no-diagnostics
+#ident "$Header:$"
+export module M;
+
+//--- pragma_comment.cpp
+// expected-no-diagnostics
+#pragma comment(lib, "msvcrt.lib")
+export module M;
+
+//--- pragma_mark.cpp
+// expected-no-diagnostics
+#pragma mark LLVM's world
+export module M;
+
+//--- pragma_detect_mismatch.cpp
+// expected-no-diagnostics
+#pragma detect_mismatch("test", "1")
+export module M;
+
+//--- pragma_clang_debug.cpp
+// expected-no-diagnostics
+#pragma clang __debug dump Test
+export module M;
+
+//--- pragma_message.cpp
+#pragma message "test" // expected-warning {{test}}
+export module M;
+
+//--- pragma_gcc_warn.cpp
+#pragma GCC warning "Foo" // expected-warning {{Foo}}
+export module M;
+
+//--- pragma_gcc_error.cpp
+#pragma GCC error "Foo" // expected-error {{Foo}}
+export module M;
+
+//--- pragma_diag_push_pop.cpp
+// expected-no-diagnostics
+#pragma gcc diagnostic push
+#pragma gcc diagnostic pop
+export module M;
+
+//--- pragma_diag_ignore.cpp
+// expected-no-diagnostics
+#pragma GCC diagnostic ignored "-Wframe-larger-than"
+export module M;
+
+//--- pragma_opencl_ext.cpp
+// expected-no-diagnostics
+#pragma OPENCL EXTENSION __cl_clang_variadic_functions : enable
+export module M;
+
+//--- pragma_push_pop.cpp
+// expected-no-diagnostics
+#pragma warning(push)
+#pragma warning(pop)
+export module M;
+
+//--- pragma_exec_charset.cpp
+// expected-no-diagnostics
+#pragma execution_character_set(push, "UTF-8")
+#pragma execution_character_set(pop)
+export module M;
+
+//--- pragma_clang_assume_nonnull.cpp
+// expected-no-diagnostics
+#pragma clang assume_nonnull begin
+#pragma clang assume_nonnull end
+export module M;
+
+//--- marco_expand.cpp
+MACRO // expected-note {{add 'module;' to the start of the file to introduce a 
global module fragment}}
+export module M; // expected-error {{module declaration must occur at the 
start of the translation unit}}
+
+//--- define.cpp
 // This is a comment
 #define I32 int // expected-note {{add 'module;' to the start of the file to 
introduce a global module fragment}}
 export module M; // expected-error {{module declaration must occur at the 
start of the translation unit}}
 export I32 i32;
+
+//--- undef.cpp
+#undef FOO // expected-note {{add 'module;' to the start of the file to 
introduce a global module fragment}}
+export module M; // expected-error {{module declaration must occur at the 
start of the translation unit}}
+
+//--- defined.cpp
+#if defined(FOO) // expected-note {{add 'module;' to the start of the file to 
introduce a global module fragment}}
+#endif
+export module M; // expected-error {{module declaration must occur at the 
start of the translation unit}}
+
+//--- has_embed.cpp
+#if __has_embed(__FILE__ ext::token(0xB055)) // expected-note {{add 'module;' 
to the start of the file to introduce a global module fragment}}
+#endif
+export module M; // expected-error {{module declaration must occur at the 
start of the translation unit}}
+
+//--- has_include.cpp
+#if __has_include(<stdio.h>) || __has_include_next(<stdlib.h>) // 
expected-note {{add 'module;' to the start of the file to introduce a global 
module fragment}} \
+                                                               // 
expected-warning {{#include_next in primary source file; will search from start 
of include path}}
+#endif
+export module M; // expected-error {{module declaration must occur at the 
start of the translation unit}}
diff --git a/clang/unittests/Lex/LexerTest.cpp 
b/clang/unittests/Lex/LexerTest.cpp
index 56d73cec1363f..c51cd0d2bfdaa 100644
--- a/clang/unittests/Lex/LexerTest.cpp
+++ b/clang/unittests/Lex/LexerTest.cpp
@@ -795,7 +795,7 @@ TEST_F(LexerTest, CheckFirstPPToken) {
     EXPECT_FALSE(Lexer::getRawToken(PP->getMainFileFirstPPTokenLoc(), Tok,
                                     PP->getSourceManager(), PP->getLangOpts(),
                                     /*IgnoreWhiteSpace=*/false));
-    EXPECT_TRUE(Tok.isFirstPPToken());
+    EXPECT_TRUE(PP->getMainFileFirstPPTokenLoc() == Tok.getLocation());
     EXPECT_TRUE(Tok.is(tok::hash));
   }
 
@@ -811,7 +811,7 @@ TEST_F(LexerTest, CheckFirstPPToken) {
     EXPECT_FALSE(Lexer::getRawToken(PP->getMainFileFirstPPTokenLoc(), Tok,
                                     PP->getSourceManager(), PP->getLangOpts(),
                                     /*IgnoreWhiteSpace=*/false));
-    EXPECT_TRUE(Tok.isFirstPPToken());
+    EXPECT_TRUE(PP->getMainFileFirstPPTokenLoc() == Tok.getLocation());
     EXPECT_TRUE(Tok.is(tok::raw_identifier));
     EXPECT_TRUE(Tok.getRawIdentifier() == "FOO");
   }

>From abc6a89b6dcf78ecef9daf0d48eb3aa579ff9537 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin...@gmail.com>
Date: Fri, 15 Aug 2025 12:11:49 +0800
Subject: [PATCH 2/2] Rename TrivialDirectiveTracer to TrivialPPDirectiveTracer
 and only handle no-trivial pp-directives

Signed-off-by: yronglin <yronglin...@gmail.com>
---
 clang/include/clang/Lex/Preprocessor.h        |   6 +-
 clang/include/clang/Lex/Token.h               |   5 +-
 ...iveTracer.h => TrivialPPDirectiveTracer.h} | 206 ++++++------------
 clang/lib/Lex/Preprocessor.cpp                |  38 ++--
 4 files changed, 86 insertions(+), 169 deletions(-)
 rename clang/include/clang/Lex/{TrivialDirectiveTracer.h => 
TrivialPPDirectiveTracer.h} (65%)

diff --git a/clang/include/clang/Lex/Preprocessor.h 
b/clang/include/clang/Lex/Preprocessor.h
index d51faad255224..e0036152e2e4f 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -82,7 +82,7 @@ class PreprocessorLexer;
 class PreprocessorOptions;
 class ScratchBuffer;
 class TargetInfo;
-class TrivialDirectiveTracer;
+class TrivialPPDirectiveTracer;
 
 namespace Builtin {
 class Context;
@@ -357,7 +357,7 @@ class Preprocessor {
   /// A preprocessor directive tracer to trace whether the preprocessing
   /// state changed. These changes would mean most semantically observable
   /// preprocessor state, particularly anything that is order dependent.
-  TrivialDirectiveTracer *DirTracer = nullptr;
+  TrivialPPDirectiveTracer *DirTracer = nullptr;
 
   /// A position within a C++20 import-seq.
   class StdCXXImportSeq {
@@ -3099,7 +3099,7 @@ class Preprocessor {
   bool setDeserializedSafeBufferOptOutMap(
       const SmallVectorImpl<SourceLocation> &SrcLocSeqs);
 
-  /// Whether allow C++ module directive.
+  /// Whether seen pp-directives which may change the preprocessing state.
   bool hasSeenNoTrivialPPDirective() const;
 
 private:
diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h
index c493571e00038..348670eb86629 100644
--- a/clang/include/clang/Lex/Token.h
+++ b/clang/include/clang/Lex/Token.h
@@ -89,7 +89,8 @@ class Token {
     IsReinjected = 0x800,        // A phase 4 token that was produced before 
and
                           // re-added, e.g. via EnterTokenStream. Annotation
                           // tokens are *not* reinjected.
-    SeenNoTrivialPPDirective = 0x1000,
+    HasSeenNoTrivialPPDirective =
+        0x1000, // Seen any 'no-trivial' pp-directives before current position.
   };
 
   tok::TokenKind getKind() const { return Kind; }
@@ -320,7 +321,7 @@ class Token {
   bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); }
 
   bool hasSeenNoTrivialPPDirective() const {
-    return getFlag(SeenNoTrivialPPDirective);
+    return getFlag(HasSeenNoTrivialPPDirective);
   }
 };
 
diff --git a/clang/include/clang/Lex/TrivialDirectiveTracer.h 
b/clang/include/clang/Lex/TrivialPPDirectiveTracer.h
similarity index 65%
rename from clang/include/clang/Lex/TrivialDirectiveTracer.h
rename to clang/include/clang/Lex/TrivialPPDirectiveTracer.h
index 9d4e0fdc96daf..a9f5fb0393fc7 100644
--- a/clang/include/clang/Lex/TrivialDirectiveTracer.h
+++ b/clang/include/clang/Lex/TrivialPPDirectiveTracer.h
@@ -1,4 +1,4 @@
-//===--- TrivialDirectiveTracer.h -------------------------------*- C++ 
-*-===//
+//===--- TrivialPPDirectiveTracer.h -----------------------------*- C++ 
-*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,39 +6,69 @@
 //
 
//===----------------------------------------------------------------------===//
 //
-//  This file defines the TrivialDirectiveTracer interface.
+//  This file defines the TrivialPPDirectiveTracer interface.
 //
 
//===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_LEX_TRIVIAL_DIRECTIVE_TRACER_H
-#define LLVM_CLANG_LEX_TRIVIAL_DIRECTIVE_TRACER_H
+#ifndef LLVM_CLANG_LEX_TRIVIAL_PPDIRECTIVE_TRACER_H
+#define LLVM_CLANG_LEX_TRIVIAL_PPDIRECTIVE_TRACER_H
 
 #include "clang/Lex/PPCallbacks.h"
 
 namespace clang {
 class Preprocessor;
 
-class TrivialDirectiveTracer : public PPCallbacks {
+/// Consider the following code:
+///
+/// # 1 __FILE__ 1 3
+/// export module a;
+///
+/// According to the wording in
+/// 
[P1857R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1857r3.html):
+///
+///   A module directive may only appear as the first preprocessing tokens in a
+///   file (excluding the global module fragment.)
+///
+/// and the wording in
+/// [[cpp.pre]](https://eel.is/c++draft/cpp.pre#nt:module-file):
+///   module-file:
+///     pp-global-module-fragment[opt] pp-module group[opt]
+///     pp-private-module-fragment[opt]
+///
+/// `#` is the first pp-token in the translation unit, and it was rejected by
+/// clang, but they really should be exempted from this rule. The goal is to 
not
+/// allow any preprocessor conditionals or most state changes, but these don't
+/// fit that.
+///
+/// State change would mean most semantically observable preprocessor state,
+/// particularly anything that is order dependent. Global flags like being a
+/// system header/module shouldn't matter.
+///
+/// We should exempt a brunch of directives, even though it violates the 
current
+/// standard wording.
+///
+/// This class used to trace 'no-trivial' pp-directives in main file, which may
+/// change the preprocessing state.
+///
+/// FIXME: Once the wording of the standard is revised, we need to follow the
+/// wording of the standard. Currently this is just a workaround
+class TrivialPPDirectiveTracer : public PPCallbacks {
   Preprocessor &PP;
+
+  /// Whether preprocessing main file. We only focus on the main file.
   bool InMainFile = true;
+
+  /// Whether one or more conditional, include or other 'no-trivial'
+  /// pp-directives has seen before.
   bool SeenNoTrivialPPDirective = false;
 
-  void setSeenNoTrivialPPDirective(bool Val);
+  void setSeenNoTrivialPPDirective();
 
 public:
-  TrivialDirectiveTracer(Preprocessor &P) : PP(P) {}
+  TrivialPPDirectiveTracer(Preprocessor &P) : PP(P) {}
 
   bool hasSeenNoTrivialPPDirective() const;
 
-  /// Callback invoked whenever a source file is entered or exited.
-  ///
-  /// \param Loc Indicates the new location.
-  /// \param PrevFID the file that was exited if \p Reason is ExitFile or the
-  /// the file before the new one entered for \p Reason EnterFile.
-  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
-                   SrcMgr::CharacteristicKind FileType,
-                   FileID PrevFID = FileID()) override;
-
   /// Callback invoked whenever the \p Lexer moves to a different file for
   /// lexing. Unlike \p FileChanged line number directives and other related
   /// pragmas do not trigger callbacks to \p LexedFileChanged.
@@ -75,7 +105,7 @@ class TrivialDirectiveTracer : public PPCallbacks {
   void EmbedDirective(SourceLocation HashLoc, StringRef FileName, bool 
IsAngled,
                       OptionalFileEntryRef File,
                       const LexEmbedParametersResult &Params) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 
   /// Callback invoked whenever an inclusion directive of
@@ -128,7 +158,7 @@ class TrivialDirectiveTracer : public PPCallbacks {
                           StringRef RelativePath, const Module 
*SuggestedModule,
                           bool ModuleImported,
                           SrcMgr::CharacteristicKind FileType) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 
   /// Callback invoked whenever there was an explicit module-import
@@ -143,126 +173,18 @@ class TrivialDirectiveTracer : public PPCallbacks {
   ///
   void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path,
                     const Module *Imported) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 
   /// Callback invoked when the end of the main file is reached.
   ///
   /// No subsequent callbacks will be made.
-  void EndOfMainFile() override { setSeenNoTrivialPPDirective(true); }
-
-  /// Callback invoked when a \#ident or \#sccs directive is read.
-  /// \param Loc The location of the directive.
-  /// \param str The text of the directive.
-  ///
-  void Ident(SourceLocation Loc, StringRef str) override {
-    setSeenNoTrivialPPDirective(false);
-  }
+  void EndOfMainFile() override { setSeenNoTrivialPPDirective(); }
 
   /// Callback invoked when start reading any pragma directive.
   void PragmaDirective(SourceLocation Loc,
                        PragmaIntroducerKind Introducer) override {}
 
-  /// Callback invoked when a \#pragma comment directive is read.
-  void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
-                     StringRef Str) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma mark comment is read.
-  void PragmaMark(SourceLocation Loc, StringRef Trivia) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma detect_mismatch directive is
-  /// read.
-  void PragmaDetectMismatch(SourceLocation Loc, StringRef Name,
-                            StringRef Value) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma clang __debug directive is read.
-  /// \param Loc The location of the debug directive.
-  /// \param DebugType The identifier following __debug.
-  void PragmaDebug(SourceLocation Loc, StringRef DebugType) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma message directive is read.
-  /// \param Loc The location of the message directive.
-  /// \param Namespace The namespace of the message directive.
-  /// \param Kind The type of the message directive.
-  /// \param Str The text of the message directive.
-  void PragmaMessage(SourceLocation Loc, StringRef Namespace,
-                     PragmaMessageKind Kind, StringRef Str) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma gcc diagnostic push directive
-  /// is read.
-  void PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma gcc diagnostic pop directive
-  /// is read.
-  void PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma gcc diagnostic directive is read.
-  void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
-                        diag::Severity mapping, StringRef Str) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Called when an OpenCL extension is either disabled or
-  /// enabled with a pragma.
-  void PragmaOpenCLExtension(SourceLocation NameLoc, const IdentifierInfo 
*Name,
-                             SourceLocation StateLoc, unsigned State) override 
{
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma warning directive is read.
-  void PragmaWarning(SourceLocation Loc, PragmaWarningSpecifier WarningSpec,
-                     ArrayRef<int> Ids) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma warning(push) directive is read.
-  void PragmaWarningPush(SourceLocation Loc, int Level) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma warning(pop) directive is read.
-  void PragmaWarningPop(SourceLocation Loc) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma execution_character_set(push) directive
-  /// is read.
-  void PragmaExecCharsetPush(SourceLocation Loc, StringRef Str) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma execution_character_set(pop) directive
-  /// is read.
-  void PragmaExecCharsetPop(SourceLocation Loc) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma clang assume_nonnull begin directive
-  /// is read.
-  void PragmaAssumeNonNullBegin(SourceLocation Loc) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
-  /// Callback invoked when a \#pragma clang assume_nonnull end directive
-  /// is read.
-  void PragmaAssumeNonNullEnd(SourceLocation Loc) override {
-    setSeenNoTrivialPPDirective(false);
-  }
-
   /// Called by Preprocessor::HandleMacroExpandedIdentifier when a
   /// macro invocation is found.
   void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
@@ -271,7 +193,7 @@ class TrivialDirectiveTracer : public PPCallbacks {
   /// Hook called whenever a macro definition is seen.
   void MacroDefined(const Token &MacroNameTok,
                     const MacroDirective *MD) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 
   /// Hook called whenever a macro \#undef is seen.
@@ -282,14 +204,14 @@ class TrivialDirectiveTracer : public PPCallbacks {
   /// MD is released immediately following this callback.
   void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
                       const MacroDirective *Undef) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 
   /// Hook called whenever the 'defined' operator is seen.
   /// \param MD The MacroDirective if the name was a macro, null otherwise.
   void Defined(const Token &MacroNameTok, const MacroDefinition &MD,
                SourceRange Range) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 
   /// Hook called whenever an \#if is seen.
@@ -300,7 +222,7 @@ class TrivialDirectiveTracer : public PPCallbacks {
   // FIXME: better to pass in a list (or tree!) of Tokens.
   void If(SourceLocation Loc, SourceRange ConditionRange,
           ConditionValueKind ConditionValue) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 
   /// Hook called whenever an \#elif is seen.
@@ -311,7 +233,7 @@ class TrivialDirectiveTracer : public PPCallbacks {
   // FIXME: better to pass in a list (or tree!) of Tokens.
   void Elif(SourceLocation Loc, SourceRange ConditionRange,
             ConditionValueKind ConditionValue, SourceLocation IfLoc) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 
   /// Hook called whenever an \#ifdef is seen.
@@ -320,7 +242,7 @@ class TrivialDirectiveTracer : public PPCallbacks {
   /// \param MD The MacroDefinition if the name was a macro, null otherwise.
   void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
              const MacroDefinition &MD) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 
   /// Hook called whenever an \#elifdef branch is taken.
@@ -329,7 +251,7 @@ class TrivialDirectiveTracer : public PPCallbacks {
   /// \param MD The MacroDefinition if the name was a macro, null otherwise.
   void Elifdef(SourceLocation Loc, const Token &MacroNameTok,
                const MacroDefinition &MD) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
   /// Hook called whenever an \#elifdef is skipped.
   /// \param Loc the source location of the directive.
@@ -338,7 +260,7 @@ class TrivialDirectiveTracer : public PPCallbacks {
   // FIXME: better to pass in a list (or tree!) of Tokens.
   void Elifdef(SourceLocation Loc, SourceRange ConditionRange,
                SourceLocation IfLoc) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 
   /// Hook called whenever an \#ifndef is seen.
@@ -347,7 +269,7 @@ class TrivialDirectiveTracer : public PPCallbacks {
   /// \param MD The MacroDefiniton if the name was a macro, null otherwise.
   void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
               const MacroDefinition &MD) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 
   /// Hook called whenever an \#elifndef branch is taken.
@@ -356,7 +278,7 @@ class TrivialDirectiveTracer : public PPCallbacks {
   /// \param MD The MacroDefinition if the name was a macro, null otherwise.
   void Elifndef(SourceLocation Loc, const Token &MacroNameTok,
                 const MacroDefinition &MD) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
   /// Hook called whenever an \#elifndef is skipped.
   /// \param Loc the source location of the directive.
@@ -365,24 +287,24 @@ class TrivialDirectiveTracer : public PPCallbacks {
   // FIXME: better to pass in a list (or tree!) of Tokens.
   void Elifndef(SourceLocation Loc, SourceRange ConditionRange,
                 SourceLocation IfLoc) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 
   /// Hook called whenever an \#else is seen.
   /// \param Loc the source location of the directive.
   /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
   void Else(SourceLocation Loc, SourceLocation IfLoc) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 
   /// Hook called whenever an \#endif is seen.
   /// \param Loc the source location of the directive.
   /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
   void Endif(SourceLocation Loc, SourceLocation IfLoc) override {
-    setSeenNoTrivialPPDirective(true);
+    setSeenNoTrivialPPDirective();
   }
 };
 
 } // namespace clang
 
-#endif // LLVM_CLANG_LEX_TRIVIAL_DIRECTIVE_TRACER_H
+#endif // LLVM_CLANG_LEX_TRIVIAL_PPDIRECTIVE_TRACER_H
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index dd5ab0e19ecd4..9797c997301bb 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -50,7 +50,7 @@
 #include "clang/Lex/ScratchBuffer.h"
 #include "clang/Lex/Token.h"
 #include "clang/Lex/TokenLexer.h"
-#include "clang/Lex/TrivialDirectiveTracer.h"
+#include "clang/Lex/TrivialPPDirectiveTracer.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
@@ -576,7 +576,7 @@ void Preprocessor::EnterMainSourceFile() {
     // export module M; // error: module declaration must occur
     //                  //        at the start of the translation unit.
     if (getLangOpts().CPlusPlusModules) {
-      auto Tracer = std::make_unique<TrivialDirectiveTracer>(*this);
+      auto Tracer = std::make_unique<TrivialPPDirectiveTracer>(*this);
       DirTracer = Tracer.get();
       addPPCallbacks(std::move(Tracer));
       std::optional<Token> FirstPPTok = CurLexer->peekNextPPToken();
@@ -943,7 +943,7 @@ void Preprocessor::Lex(Token &Result) {
       break;
     case tok::kw_export:
       if (hasSeenNoTrivialPPDirective())
-        Result.setFlag(Token::SeenNoTrivialPPDirective);
+        Result.setFlag(Token::HasSeenNoTrivialPPDirective);
       TrackGMFState.handleExport();
       StdCXXImportSeqState.handleExport();
       ModuleDeclState.handleExport();
@@ -973,7 +973,7 @@ void Preprocessor::Lex(Token &Result) {
           break;
         } else if (Result.getIdentifierInfo() == getIdentifierInfo("module")) {
           if (hasSeenNoTrivialPPDirective())
-            Result.setFlag(Token::SeenNoTrivialPPDirective);
+            Result.setFlag(Token::HasSeenNoTrivialPPDirective);
           TrackGMFState.handleModule(StdCXXImportSeqState.afterTopLevelSeq());
           ModuleDeclState.handleModule();
           break;
@@ -1689,36 +1689,30 @@ const char *Preprocessor::getCheckPoint(FileID FID, 
const char *Start) const {
   return nullptr;
 }
 
-/// Whether allow C++ module directive.
 bool Preprocessor::hasSeenNoTrivialPPDirective() const {
   return DirTracer && DirTracer->hasSeenNoTrivialPPDirective();
 }
 
-bool TrivialDirectiveTracer::hasSeenNoTrivialPPDirective() const {
+bool TrivialPPDirectiveTracer::hasSeenNoTrivialPPDirective() const {
   return SeenNoTrivialPPDirective;
 }
 
-void TrivialDirectiveTracer::setSeenNoTrivialPPDirective(bool Val) {
-  if (InMainFile && !SeenNoTrivialPPDirective && Val)
-    SeenNoTrivialPPDirective = Val;
+void TrivialPPDirectiveTracer::setSeenNoTrivialPPDirective() {
+  if (InMainFile && !SeenNoTrivialPPDirective)
+    SeenNoTrivialPPDirective = true;
 }
 
-void TrivialDirectiveTracer::FileChanged(SourceLocation Loc,
-                                         FileChangeReason Reason,
-                                         SrcMgr::CharacteristicKind FileType,
-                                         FileID PrevFID) {
-  setSeenNoTrivialPPDirective(false);
-}
-
-void TrivialDirectiveTracer::LexedFileChanged(
+void TrivialPPDirectiveTracer::LexedFileChanged(
     FileID FID, LexedFileChangeReason Reason,
     SrcMgr::CharacteristicKind FileType, FileID PrevFID, SourceLocation Loc) {
   InMainFile = FID == PP.getSourceManager().getMainFileID();
 }
 
-void TrivialDirectiveTracer::MacroExpands(const Token &MacroNameTok,
-                                          const MacroDefinition &MD,
-                                          SourceRange Range,
-                                          const MacroArgs *Args) {
-  setSeenNoTrivialPPDirective(!MD.getMacroInfo()->isBuiltinMacro());
+void TrivialPPDirectiveTracer::MacroExpands(const Token &MacroNameTok,
+                                            const MacroDefinition &MD,
+                                            SourceRange Range,
+                                            const MacroArgs *Args) {
+  // FIXME: Does only enable builtin macro expansion make sense?
+  if (!MD.getMacroInfo()->isBuiltinMacro())
+    setSeenNoTrivialPPDirective();
 }

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to