[Git][ghc/ghc][wip/az/ghc-cpp] 3 commits: Working on dumping the GHC_CPP result
Alan Zimmerman (@alanz)
gitlab at gitlab.haskell.org
Wed Feb 19 23:07:19 UTC 2025
Alan Zimmerman pushed to branch wip/az/ghc-cpp at Glasgow Haskell Compiler / GHC
Commits:
51f5ec69 by Alan Zimmerman at 2025-02-19T22:26:25+00:00
Working on dumping the GHC_CPP result
But We need to keep the BufSpan in a comment
- - - - -
87c55270 by Alan Zimmerman at 2025-02-19T22:40:26+00:00
Keep BufSpan in queued comments in GHC.Parser.Lexer
- - - - -
47c9212a by Alan Zimmerman at 2025-02-19T23:06:23+00:00
Getting close to being able to print the combined tokens
showing what is in and what is out
- - - - -
9 changed files:
- compiler/GHC/Driver/Config/Parser.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Parser/Lexer.x
- compiler/GHC/Parser/PreProcess.hs
- compiler/GHC/SysTools/Cpp.hs
- utils/check-cpp/Main.hs
- utils/check-cpp/PreProcess.hs
Changes:
=====================================
compiler/GHC/Driver/Config/Parser.hs
=====================================
@@ -18,6 +18,7 @@ import GHC.Driver.Config.Diagnostic
import GHC.Parser.Lexer
import qualified GHC.Parser.PreProcess.ParserM as PM
import GHC.Parser.PreProcess.State ( MacroDefines)
+import GHC.Unit.Env (UnitEnv)
-- | Extracts the flags needed for parsing
initParserOpts :: DynFlags -> ParserOpts
@@ -37,6 +38,8 @@ supportedLanguagePragmas = supportedLanguagesAndExtensions . platformArchOS . ta
-- Predefined macros, for use in GHC_CPP @PpState@
-- Derived from the GHC source file `ghcversion.h.in`
+-- predefinedMacros :: DynFlags -> Maybe UnitEnv -> MacroDefines
+-- predefinedMacros df unit_env = Map.fromList
predefinedMacros :: DynFlags -> MacroDefines
predefinedMacros df = Map.fromList
[
=====================================
compiler/GHC/Driver/Flags.hs
=====================================
@@ -466,6 +466,7 @@ data DumpFlag
| Opt_D_dump_occur_anal
| Opt_D_dump_parsed
| Opt_D_dump_parsed_ast
+ | Opt_D_dump_ghc_cpp
| Opt_D_dump_rn
| Opt_D_dump_rn_ast
| Opt_D_dump_simpl
=====================================
compiler/GHC/Driver/Main.hs
=====================================
@@ -305,6 +305,7 @@ import GHC.Cmm.Config (CmmConfig)
import Data.Bifunctor
import qualified GHC.Unit.Home.Graph as HUG
import GHC.Unit.Home.PackageTable
+import GHC.Parser.PreProcess (dumpGhcCpp)
{- **********************************************************************
%* *
@@ -529,6 +530,8 @@ hscParse' mod_summary
FormatHaskell (showAstData NoBlankSrcSpan
NoBlankEpAnnotations
rdr_module)
+ liftIO $ putDumpFileMaybe logger Opt_D_dump_ghc_cpp "After GHC_CPP"
+ FormatHaskell (dumpGhcCpp (initParserStateWithMacros dflags (initParserOpts dflags) buf loc))
liftIO $ putDumpFileMaybe logger Opt_D_source_stats "Source Statistics"
FormatText (ppSourceStats False rdr_module)
@@ -2678,6 +2681,8 @@ hscParseThingWithLocation source linenumber parser str = do
FormatHaskell (ppr thing)
liftIO $ putDumpFileMaybe logger Opt_D_dump_parsed_ast "Parser AST"
FormatHaskell (showAstData NoBlankSrcSpan NoBlankEpAnnotations thing)
+ liftIO $ putDumpFileMaybe logger Opt_D_dump_ghc_cpp "After GHC_CPP"
+ FormatHaskell (dumpGhcCpp (initParserStateWithMacros dflags (initParserOpts dflags) buf loc))
return thing
hscTidy :: HscEnv -> ModGuts -> IO (CgGuts, ModDetails)
@@ -2951,6 +2956,8 @@ writeInterfaceOnlyMode dflags =
-- -----------------------------------------------------------------------------
+-- initParserStateWithMacros :: DynFlags -> Maybe UnitEnv -> ParserOpts -> StringBuffer -> RealSrcLoc -> PState PpState
+-- initParserStateWithMacros df unit_env
initParserStateWithMacros :: DynFlags -> ParserOpts -> StringBuffer -> RealSrcLoc -> PState PpState
initParserStateWithMacros df
= Lexer.initParserState (initPpState { pp_defines = predefinedMacros df
=====================================
compiler/GHC/Driver/Session.hs
=====================================
@@ -1494,6 +1494,8 @@ dynamic_flags_deps = [
(setDumpFlag Opt_D_dump_parsed)
, make_ord_flag defGhcFlag "ddump-parsed-ast"
(setDumpFlag Opt_D_dump_parsed_ast)
+ , make_ord_flag defGhcFlag "ddump-ghc-cpp"
+ (setDumpFlag Opt_D_dump_ghc_cpp)
, make_ord_flag defGhcFlag "dkeep-comments"
(NoArg (setGeneralFlag Opt_KeepRawTokenStream))
, make_ord_flag defGhcFlag "ddump-rn"
=====================================
compiler/GHC/Parser/Lexer.x
=====================================
@@ -3280,7 +3280,7 @@ lexer queueComments cont = do
--trace ("token: " ++ show tok) $ do
if (queueComments && isComment tok)
- then queueComment (L (psRealSpan span) tok) >> lexer queueComments cont
+ then queueComment (L span tok) >> lexer queueComments cont
else cont (L (mkSrcSpanPs span) tok)
-- Use this instead of 'lexer' in GHC.Parser to dump the tokens for debugging.
@@ -3700,7 +3700,7 @@ mkParensLocs ss = (EpaSpan (RealSrcSpan lo Strict.Nothing),
lo = mkRealSrcSpan (realSrcSpanStart ss) (mkRealSrcLoc f sl (sc+1))
lc = mkRealSrcSpan (mkRealSrcLoc f el (ec - 1)) (realSrcSpanEnd ss)
-queueComment :: RealLocated Token -> P p ()
+queueComment :: PsLocated Token -> P p ()
queueComment c = P $ \s -> POk s {
comment_q = commentToAnnotation c : comment_q s
} ()
@@ -3710,7 +3710,7 @@ queueIgnoredToken (L l tok) = do
ll <- getLastLocIncludingComments
let
-- TODO:AZ: make the tok the right type
- comment = mkLEpaComment (psRealSpan l) ll (EpaCppIgnored [L l (show tok)])
+ comment = mkLEpaComment l ll (EpaCppIgnored [L l (show tok)])
push c = P $ \s -> POk s {
comment_q = c : comment_q s
} ()
@@ -3782,7 +3782,7 @@ allocateFinalComments _ss comment_q mheader_comments =
Strict.Nothing -> (Strict.Just (reverse comment_q), [], [])
Strict.Just _ -> (mheader_comments, [], reverse comment_q)
-commentToAnnotation :: RealLocated Token -> LEpaComment
+commentToAnnotation :: PsLocated Token -> LEpaComment
commentToAnnotation (L l (ITdocComment s ll)) = mkLEpaComment l ll (EpaDocComment s)
commentToAnnotation (L l (ITdocOptions s ll)) = mkLEpaComment l ll (EpaDocOptions s)
commentToAnnotation (L l (ITlineComment s ll)) = mkLEpaComment l ll (EpaLineComment s)
@@ -3790,8 +3790,8 @@ commentToAnnotation (L l (ITblockComment s ll)) = mkLEpaComment l ll (EpaBlockCo
commentToAnnotation _ = panic "commentToAnnotation"
-- see Note [PsSpan in Comments]
-mkLEpaComment :: RealSrcSpan -> PsSpan -> EpaCommentTok -> LEpaComment
-mkLEpaComment l ll tok = L (realSpanAsAnchor l) (EpaComment tok (psRealSpan ll))
+mkLEpaComment :: PsSpan -> PsSpan -> EpaCommentTok -> LEpaComment
+mkLEpaComment l ll tok = L (spanAsAnchor (mkSrcSpanPs l)) (EpaComment tok (psRealSpan ll))
-- ---------------------------------------------------------------------
=====================================
compiler/GHC/Parser/PreProcess.hs
=====================================
@@ -10,6 +10,7 @@ module GHC.Parser.PreProcess (
initParserState,
initPragState,
PpState,
+ dumpGhcCpp,
) where
import Data.Map qualified as Map
@@ -25,6 +26,12 @@ import GHC.Parser.PreProcess.ParsePP
import GHC.Parser.PreProcess.State
import GHC.Prelude
import GHC.Types.SrcLoc
+import GHC.Utils.Outputable (SDoc)
+
+-- ---------------------------------------------------------------------
+
+dumpGhcCpp :: PState PpState -> SDoc
+dumpGhcCpp pst = undefined
-- ---------------------------------------------------------------------
=====================================
compiler/GHC/SysTools/Cpp.hs
=====================================
@@ -9,6 +9,7 @@ module GHC.SysTools.Cpp
, getGhcVersionPathName
, applyCDefs
, offsetIncludePaths
+ , cppMacroDefines
)
where
@@ -230,6 +231,16 @@ doCpp logger tmpfs dflags unit_env opts input_fn output_fn = do
, GHC.SysTools.FileOption "" output_fn
])
+-- ---------------------------------------------------------------------------
+-- Define all macros for use in GHC_CPP
+cppMacroDefines :: UnitEnv -> String
+cppMacroDefines unit_env = generatePackageVersionMacros pkgs
+ where
+ unit_state = ue_homeUnitState unit_env
+ uids = explicitUnits unit_state
+ pkgs = mapMaybe (lookupUnit unit_state . fst) uids
+
+
-- ---------------------------------------------------------------------------
-- Macros (cribbed from Cabal)
=====================================
utils/check-cpp/Main.hs
=====================================
@@ -6,12 +6,14 @@ import Data.Data hiding (Fixity)
import Data.List
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.Map as Map
+import Data.Maybe
import Debug.Trace
import GHC
import qualified GHC.Data.EnumSet as EnumSet
import GHC.Data.FastString
import GHC.Data.StringBuffer
import GHC.Driver.Config.Parser hiding (predefinedMacros)
+import GHC.Driver.Env.Types
import GHC.Driver.Errors.Types
import qualified GHC.Driver.Errors.Types as GHC
import qualified GHC.Driver.Session as GHC
@@ -21,8 +23,11 @@ import GHC.Parser.Errors.Ppr ()
import GHC.Parser.Lexer (P (..), ParseResult (..), Token (..))
import qualified GHC.Parser.Lexer as GHC
import qualified GHC.Parser.Lexer as Lexer
+import GHC.SysTools.Cpp
import GHC.Types.Error
import GHC.Types.SrcLoc
+import GHC.Unit.Env
+import GHC.Unit.State
import GHC.Utils.Error
import GHC.Utils.Outputable
@@ -59,17 +64,50 @@ parseString libdir includes str = ghcWrapper libdir $ do
dflags0 <- initDynFlags
let dflags = dflags0{extensionFlags = EnumSet.insert LangExt.GhcCpp (extensionFlags dflags0)}
let pflags = initParserOpts dflags
+ hsc <- getSession
+ liftIO $ putStrLn "-- hsc ----------"
+ liftIO $ putStrLn (show (length (unitPackages (hsc_unit_env hsc))))
+ liftIO $ putStrLn (cppMacroDefines (hsc_unit_env hsc))
liftIO $ putStrLn "-- parsing ----------"
liftIO $ putStrLn str
liftIO $ putStrLn "---------------------"
-- return $ strParserWrapper str dflags "fake_test_file.hs"
- return $ strGetToks dflags includes pflags "fake_test_file.hs" str
+ return $ snd $ strGetToks dflags includes pflags "fake_test_file.hs" str
+
+-- doDump :: LibDir -> String -> IO [Located Token]
+doDump libdir str = ghcWrapper libdir $ do
+ dflags0 <- initDynFlags
+ let dflags = dflags0{extensionFlags = EnumSet.insert LangExt.GhcCpp (extensionFlags dflags0)}
+ let pflags = initParserOpts dflags
+ hsc <- getSession
+ liftIO $ putStrLn "-- parsing ----------"
+ liftIO $ putStrLn str
+ liftIO $ putStrLn "---------------------"
+ -- let (!pst,!toks) = strGetToks dflags [] pflags "fake_test_file.hs" str
+ let !pst = getPState dflags [] pflags "fake_test_file.hs" str
+ liftIO $ putStrLn "-- dumpGhcCpp ----------"
+ liftIO $ putStrLn $ showPprUnsafe $ dumpGhcCpp pst
+ liftIO $ putStrLn "---------------------"
-strGetToks :: DynFlags -> Includes -> Lexer.ParserOpts -> FilePath -> String -> [Located Token]
-strGetToks dflags includes popts filename str = reverse $ lexAll pstate
- where
- -- strGetToks includes popts filename str = reverse $ lexAll (trace ("pstate=" ++ show initState) pstate)
+-- return $ strGetToks dflags includes pflags "fake_test_file.hs" str
+
+unitPackages :: UnitEnv -> [UnitInfo]
+unitPackages unit_env = pkgs
+ where
+ unit_state = ue_homeUnitState unit_env
+ uids = explicitUnits unit_state
+ pkgs = mapMaybe (lookupUnit unit_state . fst) uids
+
+strGetToks ::
+ DynFlags ->
+ Includes ->
+ Lexer.ParserOpts ->
+ FilePath ->
+ String ->
+ (Lexer.PState PpState, [Located Token])
+strGetToks dflags includes popts filename str = (final, reverse toks)
+ where
includeMap = Map.fromList $ map (\(k, v) -> (k, stringToStringBuffer (intercalate "\n" v))) includes
initState =
initPpState
@@ -82,23 +120,76 @@ strGetToks dflags includes popts filename str = reverse $ lexAll pstate
buf = stringToStringBuffer str
-- cpp_enabled = Lexer.GhcCppBit `Lexer.xtest` Lexer.pExtsBitmap popts
+ lexAll :: Lexer.PState PpState -> (Lexer.PState PpState, [Located Token])
lexAll state = case unP (PP.lexerDbg True return) state of
- -- POk _ t@(L _ ITeof) -> [t]
- POk s t@(L _ ITeof) -> trace ("lexall end:s=" ++ show (Lexer.pp s)) [t]
- -- POk s t@(L _ ITeof) -> trace ("lexall end:s=" ++ showPprUnsafe (Lexer.comment_q s)) [t]
- POk state' t -> t : lexAll state'
- -- (trace ("lexAll: " ++ show (unLoc t)) state')
+ POk s t@(L _ ITeof) -> (s, [t])
+ POk state' t -> (ss, t : rest)
+ where
+ (ss, rest) = lexAll state'
PFailed pst -> error $ "failed" ++ showErrorMessages (GHC.GhcPsMessage <$> GHC.getPsErrorMessages pst)
+ (final, toks) = lexAll pstate
+
+getPState ::
+ DynFlags ->
+ Includes ->
+ Lexer.ParserOpts ->
+ FilePath ->
+ String ->
+ Lexer.PState PpState
+getPState dflags includes popts filename str = pstate
+ where
+ includeMap = Map.fromList $ map (\(k, v) -> (k, stringToStringBuffer (intercalate "\n" v))) includes
+ initState =
+ initPpState
+ { pp_includes = includeMap
+ , pp_defines = predefinedMacros dflags
+ , pp_scope = (PpScope True) :| []
+ }
+ pstate = Lexer.initParserState initState popts buf loc
+ loc = mkRealSrcLoc (mkFastString filename) 1 1
+ buf = stringToStringBuffer str
+ -- cpp_enabled = Lexer.GhcCppBit `Lexer.xtest` Lexer.pExtsBitmap popts
--- _ -> [L (mkSrcSpanPs (last_loc state)) ITeof]
+ -- lexAll :: Lexer.PState PpState -> (Lexer.PState PpState, [Located Token])
+ -- lexAll state = case unP (PP.lexerDbg True return) state of
+ -- POk s t@(L _ ITeof) -> (s, [t])
+ -- POk state' t -> (ss, t : rest)
+ -- where
+ -- (ss, rest) = lexAll state'
+ -- PFailed pst -> error $ "failed" ++ showErrorMessages (GHC.GhcPsMessage <$> GHC.getPsErrorMessages pst)
+ -- (final, toks) = lexAll pstate
-showErrorMessages :: Messages GhcMessage -> String
-showErrorMessages msgs =
- renderWithContext defaultSDocContext $
- vcat $
- pprMsgEnvelopeBagWithLocDefault $
- getMessages $
- msgs
+-- ---------------------------------------------------------------------
+
+parseWith ::
+ DynFlags ->
+ FilePath ->
+ P PpState w ->
+ String ->
+ Either GHC.ErrorMessages (Lexer.PState PpState, w)
+parseWith dflags fileName parser s =
+ case runParser parser dflags fileName s of
+ PFailed pst ->
+ Left (GhcPsMessage <$> GHC.getPsErrorMessages pst)
+ POk pst pmod ->
+ Right (pst, pmod)
+
+runParser :: P PpState a -> DynFlags -> FilePath -> String -> ParseResult PpState a
+runParser parser flags filename str = unP parser parseState
+ where
+ location = mkRealSrcLoc (mkFastString filename) 1 1
+ buffer = stringToStringBuffer str
+ parseState = initParserState (initParserOpts flags) buffer location
+
+-- ---------------------------------------------------------------------
+
+-- showErrorMessages :: Messages GhcMessage -> String
+-- showErrorMessages msgs =
+-- renderWithContext defaultSDocContext $
+-- vcat $
+-- pprMsgEnvelopeBagWithLocDefault $
+-- getMessages $
+-- msgs
-- strParserWrapper ::
-- -- | Haskell module source text (full Unicode is supported)
@@ -201,6 +292,11 @@ printToks toks = mapM_ go toks
libdirNow :: LibDir
libdirNow = "/home/alanz/mysrc/git.haskell.org/worktree/bisect/_build/stage1/lib"
+dump :: [String] -> IO ()
+dump strings = do
+ let test = intercalate "\n" strings
+ doDump libdirNow test
+
doTest :: [String] -> IO ()
doTest strings = doTestWithIncludes [] strings
@@ -458,6 +554,7 @@ t16 = do
, "x = 5"
, "#endif"
]
+
-- x = 1
t17 :: IO ()
@@ -470,4 +567,18 @@ t17 = do
, "x = 5"
, "#endif"
]
+
-- x = 1
+
+t18 :: IO ()
+t18 = do
+ dump
+ [ "#define FOO(A,B) A + B"
+ , "#define FOO(A,B,C) A + B + C"
+ , "#if FOO(1,FOO(3,4)) == 8"
+ , "-- a comment"
+ , "x = 1"
+ , "#else"
+ , "x = 5"
+ , "#endif"
+ ]
=====================================
utils/check-cpp/PreProcess.hs
=====================================
@@ -1,24 +1,106 @@
module PreProcess where
+import Control.Monad.IO.Class
+import Data.Data hiding (Fixity)
+import Data.List
+import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.Map as Map
+import Data.Maybe
+import Debug.Trace
import GHC
+import qualified GHC.Data.EnumSet as EnumSet
import GHC.Data.FastString
import qualified GHC.Data.Strict as Strict
import GHC.Data.StringBuffer
+import GHC.Driver.Config.Parser hiding (predefinedMacros)
+import GHC.Driver.Env.Types
+import GHC.Driver.Errors.Types
+import qualified GHC.Driver.Errors.Types as GHC
+import qualified GHC.Driver.Session as GHC
+import GHC.Hs.Dump
+import qualified GHC.LanguageExtensions as LangExt
import GHC.Parser.Errors.Ppr ()
+import GHC.Parser.Lexer (P (..), PState (..), ParseResult (..), Token (..))
+import qualified GHC.Parser.Lexer as GHC
import qualified GHC.Parser.Lexer as Lexer
+import GHC.SysTools.Cpp
+import GHC.Types.Error
import GHC.Types.SrcLoc
-
-import GHC.Parser.Lexer (P (..), PState (..), ParseResult (..), Token (..))
+import GHC.Unit.Env
+import GHC.Unit.State
+import GHC.Utils.Error
+import GHC.Utils.Outputable
import Macro
import ParsePP
+import qualified ParserM as PM
import State
import Debug.Trace
-- ---------------------------------------------------------------------
+dumpGhcCpp :: PState PpState -> SDoc
+dumpGhcCpp pst = text $ sep ++ defines ++ sep ++ comments ++ sep ++ orig ++ sep ++ final ++ sep
+ -- ++ show startLoc ++ sep ++ show bare_toks ++ sep
+ where
+ -- Note: pst is the state /before/ the parser runs, so we can use it to lex.
+ (pst_final, bare_toks) = lexAll pst
+ defines = showDefines (pp_defines (pp pst_final))
+ sep = "\n------------------------------\n"
+ comments = showPprUnsafe (Lexer.comment_q pst_final)
+ buf = (buffer pst){cur = 0}
+ orig = lexemeToString buf (len buf)
+ startLoc = mkRealSrcLoc (srcLocFile (psRealLoc $ loc pst)) 1 1
+ buf1 = (buffer pst){cur = 0}
+ toks = GHC.addSourceToTokens startLoc buf1 bare_toks
+ final = renderCombinedToks toks (Lexer.comment_q pst_final)
+
+renderCombinedToks :: [(Located Token, String)] -> [LEpaComment] -> String
+renderCombinedToks toks ctoks = show toks1 ++ show ctoks
+ where
+ toks1 = map (\(L l _, s) -> (l,s)) toks
+ ctoks1 = map (\(L l t) -> (l, ghcCommentText t)) ctoks
+
+
+ghcCommentText :: EpaComment -> String
+ghcCommentText (GHC.EpaComment (EpaDocComment s) _) = exactPrintHsDocString s
+ghcCommentText (GHC.EpaComment (EpaDocOptions s) _) = s
+ghcCommentText (GHC.EpaComment (EpaLineComment s) _) = s
+ghcCommentText (GHC.EpaComment (EpaBlockComment s) _) = s
+ghcCommentText (GHC.EpaComment (EpaCppIgnored [L _ s]) _)= s
+ghcCommentText (GHC.EpaComment (EpaCppIgnored _) _) = ""
+
+showDefines :: MacroDefines -> String
+showDefines defines = Map.foldlWithKey' (\acc k d -> acc ++ "\n" ++ renderDefine k d) "" defines
+ where
+ renderDefine :: String -> (Map.Map (Maybe Int) ((Maybe MacroArgs), MacroDef)) -> String
+ renderDefine k defs = Map.foldl' (\acc d -> acc ++ "\n" ++ renderArity k d) "" defs
+
+ renderArity :: String -> ((Maybe MacroArgs), MacroDef) -> String
+ renderArity n (Nothing, rhs) =
+ "#define " ++ n ++ " " ++ (intercalate " " (map PM.t_str rhs))
+ renderArity n (Just args, rhs) =
+ "#define " ++ n ++ "(" ++ (intercalate "," args) ++ ") " ++ (intercalate " " (map PM.t_str rhs))
+
+lexAll :: Lexer.PState PpState -> (Lexer.PState PpState, [Located Token])
+lexAll state = case unP (lexerDbg True return) state of
+ POk s t@(L _ ITeof) -> (s, [t])
+ POk state' t -> (ss, t : rest)
+ where
+ (ss, rest) = lexAll state'
+ PFailed pst -> error $ "failed" ++ showErrorMessages (GHC.GhcPsMessage <$> GHC.getPsErrorMessages pst)
+
+showErrorMessages :: Messages GhcMessage -> String
+showErrorMessages msgs =
+ renderWithContext defaultSDocContext $
+ vcat $
+ pprMsgEnvelopeBagWithLocDefault $
+ getMessages $
+ msgs
+
+-- ---------------------------------------------------------------------
+
-- | Set parser options for parsing OPTIONS pragmas
initPragState :: Lexer.ParserOpts -> StringBuffer -> RealSrcLoc -> PState PpState
initPragState = Lexer.initPragState initPpState
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/34185e2710b8503ffe53130caa6fc37279d85bf4...47c9212acf34c50c8a372edc20d6222a616abf85
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/34185e2710b8503ffe53130caa6fc37279d85bf4...47c9212acf34c50c8a372edc20d6222a616abf85
You're receiving this email because of your account on gitlab.haskell.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20250219/1d3f75f2/attachment-0001.html>
More information about the ghc-commits
mailing list