[Git][ghc/ghc][wip/fix-26109] 5 commits: README: Add note on ghc.nix

recursion-ninja pushed to branch wip/fix-26109 at Glasgow Haskell Compiler / GHC Commits: 69cc16ca by Marc Scholten at 2025-08-06T15:51:28-04:00 README: Add note on ghc.nix - - - - - 93a2f450 by Daniel Díaz at 2025-08-06T15:52:14-04:00 Link to the "Strict Bindings" docs from the linear types docs Strict Bidings are relevant for the kinds of multiplicity annotations linear lets support. - - - - - 246b7853 by Matthew Pickering at 2025-08-07T06:58:30-04:00 level imports: Check the level of exported identifiers The level imports specification states that exported identifiers have to be at level 0. This patch adds the requird level checks that all explicitly mentioned identifiers occur at level 0. For implicit export specifications (T(..) and module B), only level 0 identifiers are selected for re-export. ghc-proposal: https://github.com/ghc-proposals/ghc-proposals/pull/705 Fixes #26090 - - - - - 358bc4fc by fendor at 2025-08-07T06:59:12-04:00 Bump GHC on darwin CI to 9.10.1 - - - - - 71f622b5 by Recursion Ninja at 2025-08-07T13:14:29-04:00 Resolving issues #20645 and #26109 Correctly sign extending and casting smaller bit width types for LLVM operations: - bitReverse8# - bitReverse16# - bitReverse32# - byteSwap16# - byteSwap32# - pdep8# - pdep16# - pext8# - pext16# - - - - - 26 changed files: - .gitlab/darwin/toolchain.nix - README.md - compiler/GHC/CmmToLlvm/CodeGen.hs - compiler/GHC/Tc/Gen/Export.hs - compiler/GHC/Types/Name/Reader.hs - docs/users_guide/exts/linear_types.rst - docs/users_guide/exts/strict.rst - + testsuite/tests/llvm/should_run/T20645.hs - + testsuite/tests/llvm/should_run/T20645.stdout - testsuite/tests/llvm/should_run/all.T - testsuite/tests/numeric/should_run/foundation.hs - + testsuite/tests/splice-imports/DodgyLevelExport.hs - + testsuite/tests/splice-imports/DodgyLevelExport.stderr - + testsuite/tests/splice-imports/DodgyLevelExportA.hs - + testsuite/tests/splice-imports/LevelImportExports.hs - + testsuite/tests/splice-imports/LevelImportExports.stdout - + testsuite/tests/splice-imports/LevelImportExportsA.hs - testsuite/tests/splice-imports/Makefile - + testsuite/tests/splice-imports/ModuleExport.hs - + testsuite/tests/splice-imports/ModuleExport.stderr - + testsuite/tests/splice-imports/ModuleExportA.hs - + testsuite/tests/splice-imports/ModuleExportB.hs - + testsuite/tests/splice-imports/T26090.hs - + testsuite/tests/splice-imports/T26090.stderr - + testsuite/tests/splice-imports/T26090A.hs - testsuite/tests/splice-imports/all.T Changes: ===================================== .gitlab/darwin/toolchain.nix ===================================== @@ -16,18 +16,17 @@ let ghcBindists = let version = ghc.version; in { aarch64-darwin = hostPkgs.fetchurl { url = "https://downloads.haskell.org/ghc/${version}/ghc-${version}-aarch64-apple-darwin.tar.xz"; - sha256 = "sha256-c1GTMJf3/yiW/t4QL532EswD5JVlgA4getkfsxj4TaA="; + sha256 = "sha256-/6+DtdeossBJIMbjkJwL4h3eJ7rzgNCV+ifoQKOi6AQ="; }; x86_64-darwin = hostPkgs.fetchurl { url = "https://downloads.haskell.org/ghc/${version}/ghc-${version}-x86_64-apple-darwin.tar.xz"; - sha256 = "sha256-LrYniMG0phsvyW6dhQC+3ompvzcxnwAe6GezEqqzoTQ="; + sha256 = "sha256-jPIhiJMOENesUnDUJeIaPatgavc6ZVSTY5NFIAxlC+k="; }; }; ghc = pkgs.stdenv.mkDerivation rec { - # Using 9.6.2 because of #24050 - version = "9.6.2"; + version = "9.10.1"; name = "ghc"; src = ghcBindists.${pkgs.stdenv.hostPlatform.system}; configureFlags = [ ===================================== README.md ===================================== @@ -81,6 +81,10 @@ These steps give you the default build, which includes everything optimised and built in various ways (eg. profiling libs are built). It can take a long time. To customise the build, see the file `HACKING.md`. +## Nix + +If you are looking to use nix to develop on GHC, [check out the wiki for instructions](https://gitlab.haskell.org/ghc/ghc/-/wikis/building/preparation). + Filing bugs and feature requests ================================ ===================================== compiler/GHC/CmmToLlvm/CodeGen.hs ===================================== @@ -230,23 +230,25 @@ genCall t@(PrimTarget (MO_Prefetch_Data localityInt)) [] args statement $ Expr $ Call StdCall fptr (argVars' ++ argSuffix) [] | otherwise = panic $ "prefetch locality level integer must be between 0 and 3, given: " ++ (show localityInt) --- Handle PopCnt, Clz, Ctz, and BSwap that need to only convert arg --- and return types -genCall t@(PrimTarget (MO_PopCnt w)) dsts args = - genCallSimpleCast w t dsts args - -genCall t@(PrimTarget (MO_Pdep w)) dsts args = - genCallSimpleCast2 w t dsts args -genCall t@(PrimTarget (MO_Pext w)) dsts args = - genCallSimpleCast2 w t dsts args -genCall t@(PrimTarget (MO_Clz w)) dsts args = - genCallSimpleCast w t dsts args -genCall t@(PrimTarget (MO_Ctz w)) dsts args = - genCallSimpleCast w t dsts args -genCall t@(PrimTarget (MO_BSwap w)) dsts args = - genCallSimpleCast w t dsts args -genCall t@(PrimTarget (MO_BRev w)) dsts args = - genCallSimpleCast w t dsts args +-- Handle PopCnt, Clz, Ctz, BRev, and BSwap that need to only convert arg and return types +genCall (PrimTarget op@(MO_PopCnt w)) [dst] args = + genCallSimpleCast w op dst args +genCall (PrimTarget op@(MO_Clz w)) [dst] args = + genCallSimpleCast w op dst args +genCall (PrimTarget op@(MO_Ctz w)) [dst] args = + genCallSimpleCast w op dst args +genCall (PrimTarget op@(MO_BRev w)) [dst] args = + genCallSimpleCast w op dst args +genCall (PrimTarget op@(MO_BSwap w)) [dst] args = + genCallSimpleCast w op dst args + +-- Handle Pdep and Pext that (may) require using a type with a larger bit-width +-- than the specified but width. This register width-extension is particualarly +-- necessary for W8 and W16. +genCall (PrimTarget op@(MO_Pdep w)) [dst] args = + genCallCastWithMinWidthOf W32 w op dst args +genCall (PrimTarget op@(MO_Pext w)) [dst] args = + genCallCastWithMinWidthOf W32 w op dst args genCall (PrimTarget (MO_AtomicRMW width amop)) [dst] [addr, n] = runStmtsDecls $ do addrVar <- exprToVarW addr @@ -640,63 +642,35 @@ genCallExtract _ _ _ _ = -- since GHC only really has i32 and i64 types and things like Word8 are backed -- by an i32 and just present a logical i8 range. So we must handle conversions -- from i32 to i8 explicitly as LLVM is strict about types. -genCallSimpleCast :: Width -> ForeignTarget -> [CmmFormal] -> [CmmActual] - -> LlvmM StmtData -genCallSimpleCast w t@(PrimTarget op) [dst] args = do - let width = widthToLlvmInt w - dstTy = cmmToLlvmType $ localRegType dst - - fname <- cmmPrimOpFunctions op - (fptr, _, top3) <- getInstrinct fname width [width] - - (dstV, _dst_ty) <- getCmmReg (CmmLocal dst) - - let (_, arg_hints) = foreignTargetHints t - let args_hints = zip args arg_hints - (argsV, stmts2, top2) <- arg_vars args_hints ([], nilOL, []) - (argsV', stmts4) <- castVars Signed $ zip argsV [width] - (retV, s1) <- doExpr width $ Call StdCall fptr argsV' [] - (retVs', stmts5) <- castVars (cmmPrimOpRetValSignage op) [(retV,dstTy)] - let retV' = singletonPanic "genCallSimpleCast" retVs' - let s2 = Store retV' dstV Nothing [] - - let stmts = stmts2 `appOL` stmts4 `snocOL` - s1 `appOL` stmts5 `snocOL` s2 +genCallSimpleCast :: Width -> CallishMachOp -> CmmFormal -> [CmmActual] + -> LlvmM StmtData +genCallSimpleCast w = genCallCastWithMinWidthOf w w + +-- Handle extension case that the element should be extend to a larger bit-width +-- for the operation and subsequently truncated, of the form: +-- extend arg >>= \a -> call(a) >>= truncate +genCallCastWithMinWidthOf :: Width -> Width -> CallishMachOp -> CmmFormal + -> [CmmActual] -> LlvmM StmtData +genCallCastWithMinWidthOf minW specW op dst args = do + let width = widthToLlvmInt $ max minW specW + argsW = const width <$> args + dstType = cmmToLlvmType $ localRegType dst + signage = cmmPrimOpRetValSignage op + + fname <- cmmPrimOpFunctions op + (fptr, _, top3) <- getInstrinct fname width argsW + (dstV, _dst_ty) <- getCmmReg (CmmLocal dst) + let (_, arg_hints) = foreignTargetHints $ PrimTarget op + let args_hints = zip args arg_hints + (argsV, stmts2, top2) <- arg_vars args_hints ([], nilOL, []) + (argsV', stmts4) <- castVars signage $ zip argsV argsW + (retV, s1) <- doExpr width $ Call StdCall fptr argsV' [] + (retV', stmts5) <- castVar signage retV dstType + let s2 = Store retV' dstV Nothing [] + + let stmts = stmts2 `appOL` stmts4 `snocOL` s1 `snocOL` + stmts5 `snocOL` s2 return (stmts, top2 ++ top3) -genCallSimpleCast _ _ dsts _ = - panic ("genCallSimpleCast: " ++ show (length dsts) ++ " dsts") - --- Handle simple function call that only need simple type casting, of the form: --- truncate arg >>= \a -> call(a) >>= zext --- --- since GHC only really has i32 and i64 types and things like Word8 are backed --- by an i32 and just present a logical i8 range. So we must handle conversions --- from i32 to i8 explicitly as LLVM is strict about types. -genCallSimpleCast2 :: Width -> ForeignTarget -> [CmmFormal] -> [CmmActual] - -> LlvmM StmtData -genCallSimpleCast2 w t@(PrimTarget op) [dst] args = do - let width = widthToLlvmInt w - dstTy = cmmToLlvmType $ localRegType dst - - fname <- cmmPrimOpFunctions op - (fptr, _, top3) <- getInstrinct fname width (const width <$> args) - - (dstV, _dst_ty) <- getCmmReg (CmmLocal dst) - - let (_, arg_hints) = foreignTargetHints t - let args_hints = zip args arg_hints - (argsV, stmts2, top2) <- arg_vars args_hints ([], nilOL, []) - (argsV', stmts4) <- castVars Signed $ zip argsV (const width <$> argsV) - (retV, s1) <- doExpr width $ Call StdCall fptr argsV' [] - (retVs', stmts5) <- castVars (cmmPrimOpRetValSignage op) [(retV,dstTy)] - let retV' = singletonPanic "genCallSimpleCast2" retVs' - let s2 = Store retV' dstV Nothing [] - - let stmts = stmts2 `appOL` stmts4 `snocOL` - s1 `appOL` stmts5 `snocOL` s2 - return (stmts, top2 ++ top3) -genCallSimpleCast2 _ _ dsts _ = - panic ("genCallSimpleCast2: " ++ show (length dsts) ++ " dsts") -- | Create a function pointer from a target. getFunPtrW :: (LMString -> LlvmType) -> ForeignTarget @@ -811,11 +785,42 @@ castVar signage v t | getVarType v == t Signed -> LM_Sext Unsigned -> LM_Zext - cmmPrimOpRetValSignage :: CallishMachOp -> Signage cmmPrimOpRetValSignage mop = case mop of + -- If the result of a Bit-Reverse is treated as signed, + -- an positive input can result in an negative output, i.e.: + -- + -- identity(0x03) = 0x03 = 00000011 + -- breverse(0x03) = 0xC0 = 11000000 + -- + -- Now if an extension is performed after the operation to + -- promote a smaller bit-width value into a larger bit-width + -- type, it is expected that the /bit-wise/ operations will + -- not be treated /numerically/ as signed. + -- + -- To illustrate the difference, consider how a signed extension + -- for the type i16 to i32 differs for out values above: + -- ext_zeroed(i32, breverse(0x03)) = 0x00C0 = 0000000011000000 + -- ext_signed(i32, breverse(0x03)) = 0xFFC0 = 1111111111000000 + -- + -- Here we can see that the former output is the expected result + -- of a bit-wise operation which needs to be promoted to a larger + -- bit-width type. The latter output is not desirable when we must + -- constraining a value into a range of i16 within an i32 type. + -- + -- Hence we always treat the "signage" as unsigned for Bit-Reverse! + MO_BRev _ -> Unsigned + + -- The same reasoning applied to Bit-Reverse above applies to ther other + -- bit-wise operations; do not sign extend a possibly negated number! + MO_BSwap _ -> Unsigned + MO_Clz _ -> Unsigned + MO_Ctz _ -> Unsigned MO_Pdep _ -> Unsigned MO_Pext _ -> Unsigned + MO_PopCnt _ -> Unsigned + + -- All other cases, default to preserving the numeric sign when extending. _ -> Signed -- | Decide what C function to use to implement a CallishMachOp @@ -954,8 +959,25 @@ cmmPrimOpFunctions mop = do W256 -> fsLit "llvm.x86.bmi.pdep.256" W512 -> fsLit "llvm.x86.bmi.pdep.512" | otherwise -> case w of - W8 -> fsLit "hs_pdep8" - W16 -> fsLit "hs_pdep16" + -- Due to the down-casting and up-casting of the operand before and + -- after the Pdep operation, respectively, LLVM will provide a an + -- incorrect result after the entire operation is complete. + -- This is caused by the definition of hs_pdep64 in "cbits/pdep.c". + -- The defined C operation takes a (64-bit) 'StgWord64' as input/output. + -- The result will incorrectly consider upper bits when it should not + -- because those upper bits are outside the value's "logical range," + -- despite being present in the "actual range." + -- The function "hs_pdep32" works correctly for the type 'StgWord' + -- as input/output for the logical range of "i32." Attempting to use a + -- smaller logical range of "i16" or "i8" will produce incorrect results. + -- Hence, the call is made to "hs_pdep32" and truncated afterwards. + -- + -- TODO: Determine if the definition(s) of "hs_pdep8" and "hs_pdep16" + -- can be specialized to return the correct results when cast using + -- a call to 'genCallSimpleCast', removing the need for the function + -- 'genCallCastWithMinWidthOf'. + W8 -> fsLit "hs_pdep32" + W16 -> fsLit "hs_pdep32" W32 -> fsLit "hs_pdep32" W64 -> fsLit "hs_pdep64" W128 -> fsLit "hs_pdep128" @@ -971,8 +993,11 @@ cmmPrimOpFunctions mop = do W256 -> fsLit "llvm.x86.bmi.pext.256" W512 -> fsLit "llvm.x86.bmi.pext.512" | otherwise -> case w of - W8 -> fsLit "hs_pext8" - W16 -> fsLit "hs_pext16" + -- Same issue for "i16" and "i8" values as the Pdep operation above, + -- see that commentary for more details as to why "hs_pext32" is called + -- for bit-widths of 'W8' and 'W16'. + W8 -> fsLit "hs_pext32" + W16 -> fsLit "hs_pext32" W32 -> fsLit "hs_pext32" W64 -> fsLit "hs_pext64" W128 -> fsLit "hs_pext128" ===================================== compiler/GHC/Tc/Gen/Export.hs ===================================== @@ -23,6 +23,7 @@ import GHC.Rename.Module import GHC.Rename.Names import GHC.Rename.Env import GHC.Rename.Unbound ( reportUnboundName ) +import GHC.Rename.Splice import GHC.Unit.Module import GHC.Unit.Module.Imported import GHC.Unit.Module.Warnings @@ -312,7 +313,7 @@ exports_from_avail Nothing rdr_env _imports _this_mod ; addDiagnostic (TcRnMissingExportList $ moduleName _this_mod) ; let avails = - map fix_faminst . gresToAvailInfo + map fix_faminst . gresToAvailInfo . mapMaybe pickLevelZeroGRE . filter isLocalGRE . globalRdrEnvElts $ rdr_env ; return (Nothing, emptyDefaultEnv, avails, []) } where @@ -384,6 +385,7 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod = do { let { exportValid = (mod `elem` imported_modules) || (moduleName this_mod == mod) ; gre_prs = pickGREsModExp mod (globalRdrEnvElts rdr_env) + -- NB: this filters out non level 0 exports ; new_gres = [ gre' | (gre, _) <- gre_prs , gre' <- expand_tyty_gre gre ] @@ -451,6 +453,7 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod let avail = availFromGRE gre name = greName gre + checkThLocalNameNoLift (ieLWrappedUserRdrName l name) occs' <- check_occs occs ie [gre] (export_warn_spans', dont_warn_export', warn_txt_rn) <- process_warning export_warn_spans @@ -499,6 +502,7 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod occs' <- check_occs occs ie [gre] return (Just avail, occs', exp_dflts) + checkThLocalNameNoLift (ieLWrappedUserRdrName l name) (export_warn_spans', dont_warn_export', warn_txt_rn) <- process_warning export_warn_spans dont_warn_export @@ -526,6 +530,7 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod all_gres = par : all_kids all_names = map greName all_gres + checkThLocalNameNoLift (ieLWrappedUserRdrName l name) occs' <- check_occs occs ie all_gres (export_warn_spans', dont_warn_export', warn_txt_rn) <- process_warning export_warn_spans @@ -563,6 +568,7 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod all_gres = par : all_kids all_names = map greName all_gres + checkThLocalNameNoLift (ieLWrappedUserRdrName l name) occs' <- check_occs occs ie all_gres (export_warn_spans', dont_warn_export', warn_txt_rn) <- process_warning export_warn_spans @@ -589,17 +595,19 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod lookup_ie_kids_all :: IE GhcPs -> LIEWrappedName GhcPs -> GlobalRdrElt -> RnM [GlobalRdrElt] - lookup_ie_kids_all ie (L _ rdr) gre = + lookup_ie_kids_all ie (L _loc rdr) gre = do { let name = greName gre gres = findChildren kids_env name - ; addUsedKids (ieWrappedName rdr) gres - ; when (null gres) $ + -- We only choose level 0 exports when filling in part of an export list implicitly. + ; let kids_0 = mapMaybe pickLevelZeroGRE gres + ; addUsedKids (ieWrappedName rdr) kids_0 + ; when (null kids_0) $ if isTyConName name then addTcRnDiagnostic (TcRnDodgyExports gre) else -- This occurs when you export T(..), but -- only import T abstractly, or T is a synonym. addErr (TcRnExportHiddenComponents ie) - ; return gres } + ; return kids_0 } ------------- @@ -696,6 +704,10 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod addUsedKids parent_rdr kid_gres = addUsedGREs ExportDeprecationWarnings (pickGREs parent_rdr kid_gres) + +ieLWrappedUserRdrName :: LIEWrappedName GhcPs -> Name -> LIdOccP GhcRn +ieLWrappedUserRdrName l n = fmap (\rdr -> WithUserRdr rdr n) $ ieLWrappedName l + -- | In what namespaces should we go looking for an import/export item -- that is out of scope, for suggestions in error messages? ieWrappedNameWhatLooking :: IEWrappedName GhcPs -> WhatLooking @@ -800,6 +812,7 @@ lookupChildrenExport parent_gre rdr_items = mapAndReportM doOne rdr_items ; return (L l (IEName noExtField (L (l2l l) ub)), gre)} FoundChild child@(GRE { gre_name = child_nm, gre_par = par }) -> do { checkPatSynParent spec_parent par child_nm + ; checkThLocalNameNoLift (ieLWrappedUserRdrName n child_nm) ; return (replaceLWrappedName n child_nm, child) } IncorrectParent p c gs -> failWithDcErr (parentGRE_name p) (greName c) gs ===================================== compiler/GHC/Types/Name/Reader.hs ===================================== @@ -69,7 +69,7 @@ module GHC.Types.Name.Reader ( lookupGRE_Name, lookupGRE_FieldLabel, getGRE_NameQualifier_maybes, - transformGREs, pickGREs, pickGREsModExp, + transformGREs, pickGREs, pickGREsModExp, pickLevelZeroGRE, -- * GlobalRdrElts availFromGRE, @@ -144,7 +144,7 @@ import GHC.Utils.Panic import GHC.Utils.Binary import Control.DeepSeq -import Control.Monad ( guard ) +import Control.Monad ( guard , (>=>) ) import Data.Data import Data.List ( sort ) import qualified Data.List.NonEmpty as NE @@ -641,7 +641,7 @@ greParent = gre_par greInfo :: GlobalRdrElt -> GREInfo greInfo = gre_info -greLevels :: GlobalRdrElt -> Set.Set ImportLevel +greLevels :: GlobalRdrEltX info -> Set.Set ImportLevel greLevels g = if gre_lcl g then Set.singleton NormalLevel else Set.fromList (bagToList (fmap (is_level . is_decl) (gre_imp g))) @@ -1604,7 +1604,14 @@ pickGREsModExp :: ModuleName -> [GlobalRdrEltX info] -> [(GlobalRdrEltX info,Glo -- -- Used only for the 'module M' item in export list; -- see 'GHC.Tc.Gen.Export.exports_from_avail' -pickGREsModExp mod gres = mapMaybe (pickBothGRE mod) gres +-- This function also only chooses GREs which are at level zero. +pickGREsModExp mod gres = mapMaybe (pickLevelZeroGRE >=> pickBothGRE mod) gres + +pickLevelZeroGRE :: GlobalRdrEltX info -> Maybe (GlobalRdrEltX info) +pickLevelZeroGRE gre = + if NormalLevel `Set.member` greLevels gre + then Just gre + else Nothing -- | isBuiltInSyntax filter out names for built-in syntax They -- just clutter up the environment (esp tuples), and the ===================================== docs/users_guide/exts/linear_types.rst ===================================== @@ -213,6 +213,8 @@ With ``-XStrict``:: -- inferred unrestricted let ~(x, y) = u in … +(See :ref:`strict-bindings`). + Data types ---------- By default, all fields in algebraic data types are linear (even if ===================================== docs/users_guide/exts/strict.rst ===================================== @@ -103,6 +103,9 @@ Note the following points: See `GHC Proposal #229 https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0229-wh...`__ for the precise rules. + +.. _strict-bindings: + Strict bindings ~~~~~~~~~~~~~~~ ===================================== testsuite/tests/llvm/should_run/T20645.hs ===================================== @@ -0,0 +1,17 @@ +-- Minimal reproducer for https://gitlab.haskell.org/ghc/ghc/-/issues/20645 +{-# LANGUAGE MagicHash #-} +{-# LANGUAGE ExtendedLiterals #-} +import GHC.Exts +import GHC.Word +import Numeric (showHex) + +opaqueInt8# :: Int8# -> Int8# +opaqueInt8# x = x +{-# OPAQUE opaqueInt8# #-} + +main :: IO () +main = let !x = opaqueInt8# 109#Int8 + !y = opaqueInt8# 1#Int8 + in putStrLn . flip showHex "" . W# $ pext8# + (word8ToWord# (int8ToWord8# (0#Int8 `subInt8#` x ))) + (word8ToWord# (int8ToWord8# (y `subInt8#` 4#Int8))) ===================================== testsuite/tests/llvm/should_run/T20645.stdout ===================================== @@ -0,0 +1 @@ +49 ===================================== testsuite/tests/llvm/should_run/all.T ===================================== @@ -17,3 +17,4 @@ test('T22487', [normal, normalise_errmsg_fun(ignore_llvm_and_vortex)], compile_a test('T22033', [normal, normalise_errmsg_fun(ignore_llvm_and_vortex)], compile_and_run, ['']) test('T25730', [req_c, unless(arch('x86_64'), skip), normalise_errmsg_fun(ignore_llvm_and_vortex)], compile_and_run, ['T25730C.c']) # T25730C.c contains Intel instrinsics, so only run this test on x86 +test('T20645', [normal, normalise_errmsg_fun(ignore_llvm_and_vortex), when(have_llvm(), extra_ways(["optllvm"]))], compile_and_run, ['']) ===================================== testsuite/tests/numeric/should_run/foundation.hs ===================================== @@ -24,6 +24,7 @@ module Main ( main ) where +import Data.Bits (Bits((.&.), bit)) import Data.Word import Data.Int import GHC.Natural @@ -655,8 +656,8 @@ testPrimops = Group "primop" , testPrimop "ctz32#" Primop.ctz32# Wrapper.ctz32# , testPrimop "ctz64#" Primop.ctz64# Wrapper.ctz64# , testPrimop "ctz#" Primop.ctz# Wrapper.ctz# - , testPrimop "byteSwap16#" Primop.byteSwap16# Wrapper.byteSwap16# - , testPrimop "byteSwap32#" Primop.byteSwap32# Wrapper.byteSwap32# + , testPrimop "byteSwap16#" (16 `LowerBitsAreDefined` Primop.byteSwap16#) (16 `LowerBitsAreDefined` Wrapper.byteSwap16#) + , testPrimop "byteSwap32#" (32 `LowerBitsAreDefined` Primop.byteSwap32#) (32 `LowerBitsAreDefined` Wrapper.byteSwap32#) , testPrimop "byteSwap64#" Primop.byteSwap64# Wrapper.byteSwap64# , testPrimop "byteSwap#" Primop.byteSwap# Wrapper.byteSwap# , testPrimop "bitReverse8#" Primop.bitReverse8# Wrapper.bitReverse8# @@ -672,6 +673,34 @@ testPrimops = Group "primop" , testPrimop "narrow32Word#" Primop.narrow32Word# Wrapper.narrow32Word# ] +-- | A special data-type for representing functions where, +-- since only some number of the lower bits are defined, +-- testing for strict equality in the undefined upper bits is not appropriate! +-- Without using this data-type, false-positive failures will be reported +-- when the undefined bit regions do not match, even though the equality of bits +-- in this undefined region has no bearing on correctness. +data LowerBitsAreDefined = + LowerBitsAreDefined + { definedLowerWidth :: Word + -- ^ The (strictly-non-negative) number of least-significant bits + -- for which the attached function is defined. + , undefinedBehavior :: (Word# -> Word#) + -- ^ Function with undefined behavior for some of its most significant bits. + } + +instance TestPrimop LowerBitsAreDefined where + testPrimop s l r = Property s $ \ (uWord#-> x0) -> + let -- Create a mask to unset all bits in the undefined area, + -- leaving set bits only in the area of defined behavior. + -- Since the upper bits are undefined, + -- if the function defines behavior for the lower N bits, + -- then /only/ the lower N bits are preserved, + -- and the upper WORDSIZE - N bits are discarded. + mask = bit (fromEnum (definedLowerWidth r)) - 1 + valL = wWord# (undefinedBehavior l x0) .&. mask + valR = wWord# (undefinedBehavior r x0) .&. mask + in valL === valR + instance TestPrimop (Char# -> Char# -> Int#) where testPrimop s l r = Property s $ \ (uChar#-> x0) (uChar#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1) ===================================== testsuite/tests/splice-imports/DodgyLevelExport.hs ===================================== @@ -0,0 +1,5 @@ +{-# LANGUAGE ExplicitLevelImports #-} +module DodgyLevelExport ( T(..) ) where + +import quote DodgyLevelExportA +import DodgyLevelExportA (T) ===================================== testsuite/tests/splice-imports/DodgyLevelExport.stderr ===================================== @@ -0,0 +1,4 @@ +DodgyLevelExport.hs:2:27: warning: [GHC-75356] [-Wdodgy-exports (in -Wextra)] + The export item ‘T(..)’ suggests that + ‘T’ has (in-scope) constructors or record fields, but it has none + ===================================== testsuite/tests/splice-imports/DodgyLevelExportA.hs ===================================== @@ -0,0 +1,3 @@ +module DodgyLevelExportA where + +data T = T { a :: Int } ===================================== testsuite/tests/splice-imports/LevelImportExports.hs ===================================== @@ -0,0 +1,6 @@ +{-# LANGUAGE ExplicitLevelImports #-} +module LevelImportExports ( module LevelImportExportsA, T(..) ) where + +import quote LevelImportExportsA +import splice LevelImportExportsA +import LevelImportExportsA(a, T) ===================================== testsuite/tests/splice-imports/LevelImportExports.stdout ===================================== @@ -0,0 +1,6 @@ +[1 of 2] Compiling LevelImportExportsA ( LevelImportExportsA.hs, LevelImportExportsA.o ) +[2 of 2] Compiling LevelImportExports ( LevelImportExports.hs, LevelImportExports.o ) +exports: + LevelImportExportsA.a + LevelImportExportsA.T +defaults: ===================================== testsuite/tests/splice-imports/LevelImportExportsA.hs ===================================== @@ -0,0 +1,6 @@ +module LevelImportExportsA where + +a = 100 +b = 100 + +data T = T { c :: Int } ===================================== testsuite/tests/splice-imports/Makefile ===================================== @@ -24,5 +24,9 @@ SI10_oneshot: "$(TEST_HC)" $(TEST_HC_OPTS) -c InstanceA.hs "$(TEST_HC)" $(TEST_HC_OPTS) -c SI10.hs +LevelImportExports: + "$(TEST_HC)" $(TEST_HC_OPTS) -haddock LevelImportExports.hs + "$(TEST_HC)" --show-iface LevelImportExports.hi | grep -A3 "^exports:" + clean: rm -f *.o *.hi ===================================== testsuite/tests/splice-imports/ModuleExport.hs ===================================== @@ -0,0 +1,4 @@ +module ModuleExport where + +-- Should fail +import ModuleExportA (a) ===================================== testsuite/tests/splice-imports/ModuleExport.stderr ===================================== @@ -0,0 +1,3 @@ +ModuleExport.hs:4:23: error: [GHC-61689] + Module ‘ModuleExportA’ does not export ‘a’. + ===================================== testsuite/tests/splice-imports/ModuleExportA.hs ===================================== @@ -0,0 +1,8 @@ +{-# LANGUAGE ExplicitLevelImports #-} +-- Module export only exports level 0 things (b) +module ModuleExportA (module ModuleExportB) where + +-- Everything at level 1 +import quote ModuleExportB +-- Only b at level 0 +import ModuleExportB (b) ===================================== testsuite/tests/splice-imports/ModuleExportB.hs ===================================== @@ -0,0 +1,6 @@ +module ModuleExportB where + +a = () +b = () + + ===================================== testsuite/tests/splice-imports/T26090.hs ===================================== @@ -0,0 +1,10 @@ +{-# LANGUAGE ExplicitLevelImports, TemplateHaskell #-} +module T26090 ( a --varaible + , T(..) -- WithAll + , S(s) -- With + , R -- Abs + ) where + +import quote T26090A +import T26090A (T(T), S) + ===================================== testsuite/tests/splice-imports/T26090.stderr ===================================== @@ -0,0 +1,16 @@ +T26090.hs:2:17: error: [GHC-28914] + • Level error: ‘a’ is bound at level 1 but used at level 0 + • Available from the imports: + • imported from ‘T26090A’ at 1 at T26090.hs:8:1-20 + +T26090.hs:4:17: error: [GHC-28914] + • Level error: ‘s’ is bound at level 1 but used at level 0 + • Available from the imports: + • imported from ‘T26090A’ at 1 at T26090.hs:8:1-20 + • In the export: S(s) + +T26090.hs:5:17: error: [GHC-28914] + • Level error: ‘R’ is bound at level 1 but used at level 0 + • Available from the imports: + • imported from ‘T26090A’ at 1 at T26090.hs:8:1-20 + ===================================== testsuite/tests/splice-imports/T26090A.hs ===================================== @@ -0,0 +1,14 @@ +{-# LANGUAGE ExplicitLevelImports, TemplateHaskell #-} +module T26090A where + +import Language.Haskell.TH + +a :: Q Exp +a = [| True |] + +data T = T { t :: () } + +data S = S { s :: () } + +data R = R { r :: () } + ===================================== testsuite/tests/splice-imports/all.T ===================================== @@ -48,3 +48,7 @@ test('SI35', test('SI36', [extra_files(["SI36_A.hs", "SI36_B1.hs", "SI36_B2.hs", "SI36_B3.hs", "SI36_C1.hs", "SI36_C2.hs", "SI36_C3.hs"])], multimod_compile_fail, ['SI36', '-v0']) test('T26087', [], multimod_compile_fail, ['T26087A', '']) test('T26088', [], multimod_compile_fail, ['T26088A', '-v0']) +test('T26090', [], multimod_compile_fail, ['T26090', '-v0']) +test('ModuleExport', [], multimod_compile_fail, ['ModuleExport', '-v0']) +test('LevelImportExports', [], makefile_test, []) +test('DodgyLevelExport', [], multimod_compile, ['DodgyLevelExport', '-v0 -Wdodgy-exports']) View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/9fbadea8fb900c08c812a29716c3c40... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/9fbadea8fb900c08c812a29716c3c40... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
recursion-ninja (@recursion-ninja)