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
-
93a2f450
by Daniel Díaz at 2025-08-06T15:52:14-04:00
-
246b7853
by Matthew Pickering at 2025-08-07T06:58:30-04:00
-
358bc4fc
by fendor at 2025-08-07T06:59:12-04:00
-
71f622b5
by Recursion Ninja at 2025-08-07T13:14:29-04:00
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:
| ... | ... | @@ -16,18 +16,17 @@ let |
| 16 | 16 | ghcBindists = let version = ghc.version; in {
|
| 17 | 17 | aarch64-darwin = hostPkgs.fetchurl {
|
| 18 | 18 | url = "https://downloads.haskell.org/ghc/${version}/ghc-${version}-aarch64-apple-darwin.tar.xz";
|
| 19 | - sha256 = "sha256-c1GTMJf3/yiW/t4QL532EswD5JVlgA4getkfsxj4TaA=";
|
|
| 19 | + sha256 = "sha256-/6+DtdeossBJIMbjkJwL4h3eJ7rzgNCV+ifoQKOi6AQ=";
|
|
| 20 | 20 | };
|
| 21 | 21 | x86_64-darwin = hostPkgs.fetchurl {
|
| 22 | 22 | url = "https://downloads.haskell.org/ghc/${version}/ghc-${version}-x86_64-apple-darwin.tar.xz";
|
| 23 | - sha256 = "sha256-LrYniMG0phsvyW6dhQC+3ompvzcxnwAe6GezEqqzoTQ=";
|
|
| 23 | + sha256 = "sha256-jPIhiJMOENesUnDUJeIaPatgavc6ZVSTY5NFIAxlC+k=";
|
|
| 24 | 24 | };
|
| 25 | 25 | |
| 26 | 26 | };
|
| 27 | 27 | |
| 28 | 28 | ghc = pkgs.stdenv.mkDerivation rec {
|
| 29 | - # Using 9.6.2 because of #24050
|
|
| 30 | - version = "9.6.2";
|
|
| 29 | + version = "9.10.1";
|
|
| 31 | 30 | name = "ghc";
|
| 32 | 31 | src = ghcBindists.${pkgs.stdenv.hostPlatform.system};
|
| 33 | 32 | configureFlags = [
|
| ... | ... | @@ -81,6 +81,10 @@ These steps give you the default build, which includes everything |
| 81 | 81 | optimised and built in various ways (eg. profiling libs are built).
|
| 82 | 82 | It can take a long time. To customise the build, see the file `HACKING.md`.
|
| 83 | 83 | |
| 84 | +## Nix
|
|
| 85 | + |
|
| 86 | +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).
|
|
| 87 | + |
|
| 84 | 88 | Filing bugs and feature requests
|
| 85 | 89 | ================================
|
| 86 | 90 |
| ... | ... | @@ -230,23 +230,25 @@ genCall t@(PrimTarget (MO_Prefetch_Data localityInt)) [] args |
| 230 | 230 | statement $ Expr $ Call StdCall fptr (argVars' ++ argSuffix) []
|
| 231 | 231 | | otherwise = panic $ "prefetch locality level integer must be between 0 and 3, given: " ++ (show localityInt)
|
| 232 | 232 | |
| 233 | --- Handle PopCnt, Clz, Ctz, and BSwap that need to only convert arg
|
|
| 234 | --- and return types
|
|
| 235 | -genCall t@(PrimTarget (MO_PopCnt w)) dsts args =
|
|
| 236 | - genCallSimpleCast w t dsts args
|
|
| 237 | - |
|
| 238 | -genCall t@(PrimTarget (MO_Pdep w)) dsts args =
|
|
| 239 | - genCallSimpleCast2 w t dsts args
|
|
| 240 | -genCall t@(PrimTarget (MO_Pext w)) dsts args =
|
|
| 241 | - genCallSimpleCast2 w t dsts args
|
|
| 242 | -genCall t@(PrimTarget (MO_Clz w)) dsts args =
|
|
| 243 | - genCallSimpleCast w t dsts args
|
|
| 244 | -genCall t@(PrimTarget (MO_Ctz w)) dsts args =
|
|
| 245 | - genCallSimpleCast w t dsts args
|
|
| 246 | -genCall t@(PrimTarget (MO_BSwap w)) dsts args =
|
|
| 247 | - genCallSimpleCast w t dsts args
|
|
| 248 | -genCall t@(PrimTarget (MO_BRev w)) dsts args =
|
|
| 249 | - genCallSimpleCast w t dsts args
|
|
| 233 | +-- Handle PopCnt, Clz, Ctz, BRev, and BSwap that need to only convert arg and return types
|
|
| 234 | +genCall (PrimTarget op@(MO_PopCnt w)) [dst] args =
|
|
| 235 | + genCallSimpleCast w op dst args
|
|
| 236 | +genCall (PrimTarget op@(MO_Clz w)) [dst] args =
|
|
| 237 | + genCallSimpleCast w op dst args
|
|
| 238 | +genCall (PrimTarget op@(MO_Ctz w)) [dst] args =
|
|
| 239 | + genCallSimpleCast w op dst args
|
|
| 240 | +genCall (PrimTarget op@(MO_BRev w)) [dst] args =
|
|
| 241 | + genCallSimpleCast w op dst args
|
|
| 242 | +genCall (PrimTarget op@(MO_BSwap w)) [dst] args =
|
|
| 243 | + genCallSimpleCast w op dst args
|
|
| 244 | + |
|
| 245 | +-- Handle Pdep and Pext that (may) require using a type with a larger bit-width
|
|
| 246 | +-- than the specified but width. This register width-extension is particualarly
|
|
| 247 | +-- necessary for W8 and W16.
|
|
| 248 | +genCall (PrimTarget op@(MO_Pdep w)) [dst] args =
|
|
| 249 | + genCallCastWithMinWidthOf W32 w op dst args
|
|
| 250 | +genCall (PrimTarget op@(MO_Pext w)) [dst] args =
|
|
| 251 | + genCallCastWithMinWidthOf W32 w op dst args
|
|
| 250 | 252 | |
| 251 | 253 | genCall (PrimTarget (MO_AtomicRMW width amop)) [dst] [addr, n] = runStmtsDecls $ do
|
| 252 | 254 | addrVar <- exprToVarW addr
|
| ... | ... | @@ -640,63 +642,35 @@ genCallExtract _ _ _ _ = |
| 640 | 642 | -- since GHC only really has i32 and i64 types and things like Word8 are backed
|
| 641 | 643 | -- by an i32 and just present a logical i8 range. So we must handle conversions
|
| 642 | 644 | -- from i32 to i8 explicitly as LLVM is strict about types.
|
| 643 | -genCallSimpleCast :: Width -> ForeignTarget -> [CmmFormal] -> [CmmActual]
|
|
| 644 | - -> LlvmM StmtData
|
|
| 645 | -genCallSimpleCast w t@(PrimTarget op) [dst] args = do
|
|
| 646 | - let width = widthToLlvmInt w
|
|
| 647 | - dstTy = cmmToLlvmType $ localRegType dst
|
|
| 648 | - |
|
| 649 | - fname <- cmmPrimOpFunctions op
|
|
| 650 | - (fptr, _, top3) <- getInstrinct fname width [width]
|
|
| 651 | - |
|
| 652 | - (dstV, _dst_ty) <- getCmmReg (CmmLocal dst)
|
|
| 653 | - |
|
| 654 | - let (_, arg_hints) = foreignTargetHints t
|
|
| 655 | - let args_hints = zip args arg_hints
|
|
| 656 | - (argsV, stmts2, top2) <- arg_vars args_hints ([], nilOL, [])
|
|
| 657 | - (argsV', stmts4) <- castVars Signed $ zip argsV [width]
|
|
| 658 | - (retV, s1) <- doExpr width $ Call StdCall fptr argsV' []
|
|
| 659 | - (retVs', stmts5) <- castVars (cmmPrimOpRetValSignage op) [(retV,dstTy)]
|
|
| 660 | - let retV' = singletonPanic "genCallSimpleCast" retVs'
|
|
| 661 | - let s2 = Store retV' dstV Nothing []
|
|
| 662 | - |
|
| 663 | - let stmts = stmts2 `appOL` stmts4 `snocOL`
|
|
| 664 | - s1 `appOL` stmts5 `snocOL` s2
|
|
| 645 | +genCallSimpleCast :: Width -> CallishMachOp -> CmmFormal -> [CmmActual]
|
|
| 646 | + -> LlvmM StmtData
|
|
| 647 | +genCallSimpleCast w = genCallCastWithMinWidthOf w w
|
|
| 648 | + |
|
| 649 | +-- Handle extension case that the element should be extend to a larger bit-width
|
|
| 650 | +-- for the operation and subsequently truncated, of the form:
|
|
| 651 | +-- extend arg >>= \a -> call(a) >>= truncate
|
|
| 652 | +genCallCastWithMinWidthOf :: Width -> Width -> CallishMachOp -> CmmFormal
|
|
| 653 | + -> [CmmActual] -> LlvmM StmtData
|
|
| 654 | +genCallCastWithMinWidthOf minW specW op dst args = do
|
|
| 655 | + let width = widthToLlvmInt $ max minW specW
|
|
| 656 | + argsW = const width <$> args
|
|
| 657 | + dstType = cmmToLlvmType $ localRegType dst
|
|
| 658 | + signage = cmmPrimOpRetValSignage op
|
|
| 659 | + |
|
| 660 | + fname <- cmmPrimOpFunctions op
|
|
| 661 | + (fptr, _, top3) <- getInstrinct fname width argsW
|
|
| 662 | + (dstV, _dst_ty) <- getCmmReg (CmmLocal dst)
|
|
| 663 | + let (_, arg_hints) = foreignTargetHints $ PrimTarget op
|
|
| 664 | + let args_hints = zip args arg_hints
|
|
| 665 | + (argsV, stmts2, top2) <- arg_vars args_hints ([], nilOL, [])
|
|
| 666 | + (argsV', stmts4) <- castVars signage $ zip argsV argsW
|
|
| 667 | + (retV, s1) <- doExpr width $ Call StdCall fptr argsV' []
|
|
| 668 | + (retV', stmts5) <- castVar signage retV dstType
|
|
| 669 | + let s2 = Store retV' dstV Nothing []
|
|
| 670 | + |
|
| 671 | + let stmts = stmts2 `appOL` stmts4 `snocOL` s1 `snocOL`
|
|
| 672 | + stmts5 `snocOL` s2
|
|
| 665 | 673 | return (stmts, top2 ++ top3)
|
| 666 | -genCallSimpleCast _ _ dsts _ =
|
|
| 667 | - panic ("genCallSimpleCast: " ++ show (length dsts) ++ " dsts")
|
|
| 668 | - |
|
| 669 | --- Handle simple function call that only need simple type casting, of the form:
|
|
| 670 | --- truncate arg >>= \a -> call(a) >>= zext
|
|
| 671 | ---
|
|
| 672 | --- since GHC only really has i32 and i64 types and things like Word8 are backed
|
|
| 673 | --- by an i32 and just present a logical i8 range. So we must handle conversions
|
|
| 674 | --- from i32 to i8 explicitly as LLVM is strict about types.
|
|
| 675 | -genCallSimpleCast2 :: Width -> ForeignTarget -> [CmmFormal] -> [CmmActual]
|
|
| 676 | - -> LlvmM StmtData
|
|
| 677 | -genCallSimpleCast2 w t@(PrimTarget op) [dst] args = do
|
|
| 678 | - let width = widthToLlvmInt w
|
|
| 679 | - dstTy = cmmToLlvmType $ localRegType dst
|
|
| 680 | - |
|
| 681 | - fname <- cmmPrimOpFunctions op
|
|
| 682 | - (fptr, _, top3) <- getInstrinct fname width (const width <$> args)
|
|
| 683 | - |
|
| 684 | - (dstV, _dst_ty) <- getCmmReg (CmmLocal dst)
|
|
| 685 | - |
|
| 686 | - let (_, arg_hints) = foreignTargetHints t
|
|
| 687 | - let args_hints = zip args arg_hints
|
|
| 688 | - (argsV, stmts2, top2) <- arg_vars args_hints ([], nilOL, [])
|
|
| 689 | - (argsV', stmts4) <- castVars Signed $ zip argsV (const width <$> argsV)
|
|
| 690 | - (retV, s1) <- doExpr width $ Call StdCall fptr argsV' []
|
|
| 691 | - (retVs', stmts5) <- castVars (cmmPrimOpRetValSignage op) [(retV,dstTy)]
|
|
| 692 | - let retV' = singletonPanic "genCallSimpleCast2" retVs'
|
|
| 693 | - let s2 = Store retV' dstV Nothing []
|
|
| 694 | - |
|
| 695 | - let stmts = stmts2 `appOL` stmts4 `snocOL`
|
|
| 696 | - s1 `appOL` stmts5 `snocOL` s2
|
|
| 697 | - return (stmts, top2 ++ top3)
|
|
| 698 | -genCallSimpleCast2 _ _ dsts _ =
|
|
| 699 | - panic ("genCallSimpleCast2: " ++ show (length dsts) ++ " dsts")
|
|
| 700 | 674 | |
| 701 | 675 | -- | Create a function pointer from a target.
|
| 702 | 676 | getFunPtrW :: (LMString -> LlvmType) -> ForeignTarget
|
| ... | ... | @@ -811,11 +785,42 @@ castVar signage v t | getVarType v == t |
| 811 | 785 | Signed -> LM_Sext
|
| 812 | 786 | Unsigned -> LM_Zext
|
| 813 | 787 | |
| 814 | - |
|
| 815 | 788 | cmmPrimOpRetValSignage :: CallishMachOp -> Signage
|
| 816 | 789 | cmmPrimOpRetValSignage mop = case mop of
|
| 790 | + -- If the result of a Bit-Reverse is treated as signed,
|
|
| 791 | + -- an positive input can result in an negative output, i.e.:
|
|
| 792 | + --
|
|
| 793 | + -- identity(0x03) = 0x03 = 00000011
|
|
| 794 | + -- breverse(0x03) = 0xC0 = 11000000
|
|
| 795 | + --
|
|
| 796 | + -- Now if an extension is performed after the operation to
|
|
| 797 | + -- promote a smaller bit-width value into a larger bit-width
|
|
| 798 | + -- type, it is expected that the /bit-wise/ operations will
|
|
| 799 | + -- not be treated /numerically/ as signed.
|
|
| 800 | + --
|
|
| 801 | + -- To illustrate the difference, consider how a signed extension
|
|
| 802 | + -- for the type i16 to i32 differs for out values above:
|
|
| 803 | + -- ext_zeroed(i32, breverse(0x03)) = 0x00C0 = 0000000011000000
|
|
| 804 | + -- ext_signed(i32, breverse(0x03)) = 0xFFC0 = 1111111111000000
|
|
| 805 | + --
|
|
| 806 | + -- Here we can see that the former output is the expected result
|
|
| 807 | + -- of a bit-wise operation which needs to be promoted to a larger
|
|
| 808 | + -- bit-width type. The latter output is not desirable when we must
|
|
| 809 | + -- constraining a value into a range of i16 within an i32 type.
|
|
| 810 | + --
|
|
| 811 | + -- Hence we always treat the "signage" as unsigned for Bit-Reverse!
|
|
| 812 | + MO_BRev _ -> Unsigned
|
|
| 813 | + |
|
| 814 | + -- The same reasoning applied to Bit-Reverse above applies to ther other
|
|
| 815 | + -- bit-wise operations; do not sign extend a possibly negated number!
|
|
| 816 | + MO_BSwap _ -> Unsigned
|
|
| 817 | + MO_Clz _ -> Unsigned
|
|
| 818 | + MO_Ctz _ -> Unsigned
|
|
| 817 | 819 | MO_Pdep _ -> Unsigned
|
| 818 | 820 | MO_Pext _ -> Unsigned
|
| 821 | + MO_PopCnt _ -> Unsigned
|
|
| 822 | + |
|
| 823 | + -- All other cases, default to preserving the numeric sign when extending.
|
|
| 819 | 824 | _ -> Signed
|
| 820 | 825 | |
| 821 | 826 | -- | Decide what C function to use to implement a CallishMachOp
|
| ... | ... | @@ -954,8 +959,25 @@ cmmPrimOpFunctions mop = do |
| 954 | 959 | W256 -> fsLit "llvm.x86.bmi.pdep.256"
|
| 955 | 960 | W512 -> fsLit "llvm.x86.bmi.pdep.512"
|
| 956 | 961 | | otherwise -> case w of
|
| 957 | - W8 -> fsLit "hs_pdep8"
|
|
| 958 | - W16 -> fsLit "hs_pdep16"
|
|
| 962 | + -- Due to the down-casting and up-casting of the operand before and
|
|
| 963 | + -- after the Pdep operation, respectively, LLVM will provide a an
|
|
| 964 | + -- incorrect result after the entire operation is complete.
|
|
| 965 | + -- This is caused by the definition of hs_pdep64 in "cbits/pdep.c".
|
|
| 966 | + -- The defined C operation takes a (64-bit) 'StgWord64' as input/output.
|
|
| 967 | + -- The result will incorrectly consider upper bits when it should not
|
|
| 968 | + -- because those upper bits are outside the value's "logical range,"
|
|
| 969 | + -- despite being present in the "actual range."
|
|
| 970 | + -- The function "hs_pdep32" works correctly for the type 'StgWord'
|
|
| 971 | + -- as input/output for the logical range of "i32." Attempting to use a
|
|
| 972 | + -- smaller logical range of "i16" or "i8" will produce incorrect results.
|
|
| 973 | + -- Hence, the call is made to "hs_pdep32" and truncated afterwards.
|
|
| 974 | + --
|
|
| 975 | + -- TODO: Determine if the definition(s) of "hs_pdep8" and "hs_pdep16"
|
|
| 976 | + -- can be specialized to return the correct results when cast using
|
|
| 977 | + -- a call to 'genCallSimpleCast', removing the need for the function
|
|
| 978 | + -- 'genCallCastWithMinWidthOf'.
|
|
| 979 | + W8 -> fsLit "hs_pdep32"
|
|
| 980 | + W16 -> fsLit "hs_pdep32"
|
|
| 959 | 981 | W32 -> fsLit "hs_pdep32"
|
| 960 | 982 | W64 -> fsLit "hs_pdep64"
|
| 961 | 983 | W128 -> fsLit "hs_pdep128"
|
| ... | ... | @@ -971,8 +993,11 @@ cmmPrimOpFunctions mop = do |
| 971 | 993 | W256 -> fsLit "llvm.x86.bmi.pext.256"
|
| 972 | 994 | W512 -> fsLit "llvm.x86.bmi.pext.512"
|
| 973 | 995 | | otherwise -> case w of
|
| 974 | - W8 -> fsLit "hs_pext8"
|
|
| 975 | - W16 -> fsLit "hs_pext16"
|
|
| 996 | + -- Same issue for "i16" and "i8" values as the Pdep operation above,
|
|
| 997 | + -- see that commentary for more details as to why "hs_pext32" is called
|
|
| 998 | + -- for bit-widths of 'W8' and 'W16'.
|
|
| 999 | + W8 -> fsLit "hs_pext32"
|
|
| 1000 | + W16 -> fsLit "hs_pext32"
|
|
| 976 | 1001 | W32 -> fsLit "hs_pext32"
|
| 977 | 1002 | W64 -> fsLit "hs_pext64"
|
| 978 | 1003 | W128 -> fsLit "hs_pext128"
|
| ... | ... | @@ -23,6 +23,7 @@ import GHC.Rename.Module |
| 23 | 23 | import GHC.Rename.Names
|
| 24 | 24 | import GHC.Rename.Env
|
| 25 | 25 | import GHC.Rename.Unbound ( reportUnboundName )
|
| 26 | +import GHC.Rename.Splice
|
|
| 26 | 27 | import GHC.Unit.Module
|
| 27 | 28 | import GHC.Unit.Module.Imported
|
| 28 | 29 | import GHC.Unit.Module.Warnings
|
| ... | ... | @@ -312,7 +313,7 @@ exports_from_avail Nothing rdr_env _imports _this_mod |
| 312 | 313 | ; addDiagnostic
|
| 313 | 314 | (TcRnMissingExportList $ moduleName _this_mod)
|
| 314 | 315 | ; let avails =
|
| 315 | - map fix_faminst . gresToAvailInfo
|
|
| 316 | + map fix_faminst . gresToAvailInfo . mapMaybe pickLevelZeroGRE
|
|
| 316 | 317 | . filter isLocalGRE . globalRdrEnvElts $ rdr_env
|
| 317 | 318 | ; return (Nothing, emptyDefaultEnv, avails, []) }
|
| 318 | 319 | where
|
| ... | ... | @@ -384,6 +385,7 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod |
| 384 | 385 | = do { let { exportValid = (mod `elem` imported_modules)
|
| 385 | 386 | || (moduleName this_mod == mod)
|
| 386 | 387 | ; gre_prs = pickGREsModExp mod (globalRdrEnvElts rdr_env)
|
| 388 | + -- NB: this filters out non level 0 exports
|
|
| 387 | 389 | ; new_gres = [ gre'
|
| 388 | 390 | | (gre, _) <- gre_prs
|
| 389 | 391 | , gre' <- expand_tyty_gre gre ]
|
| ... | ... | @@ -451,6 +453,7 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod |
| 451 | 453 | let avail = availFromGRE gre
|
| 452 | 454 | name = greName gre
|
| 453 | 455 | |
| 456 | + checkThLocalNameNoLift (ieLWrappedUserRdrName l name)
|
|
| 454 | 457 | occs' <- check_occs occs ie [gre]
|
| 455 | 458 | (export_warn_spans', dont_warn_export', warn_txt_rn)
|
| 456 | 459 | <- process_warning export_warn_spans
|
| ... | ... | @@ -499,6 +502,7 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod |
| 499 | 502 | occs' <- check_occs occs ie [gre]
|
| 500 | 503 | return (Just avail, occs', exp_dflts)
|
| 501 | 504 | |
| 505 | + checkThLocalNameNoLift (ieLWrappedUserRdrName l name)
|
|
| 502 | 506 | (export_warn_spans', dont_warn_export', warn_txt_rn)
|
| 503 | 507 | <- process_warning export_warn_spans
|
| 504 | 508 | dont_warn_export
|
| ... | ... | @@ -526,6 +530,7 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod |
| 526 | 530 | all_gres = par : all_kids
|
| 527 | 531 | all_names = map greName all_gres
|
| 528 | 532 | |
| 533 | + checkThLocalNameNoLift (ieLWrappedUserRdrName l name)
|
|
| 529 | 534 | occs' <- check_occs occs ie all_gres
|
| 530 | 535 | (export_warn_spans', dont_warn_export', warn_txt_rn)
|
| 531 | 536 | <- process_warning export_warn_spans
|
| ... | ... | @@ -563,6 +568,7 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod |
| 563 | 568 | all_gres = par : all_kids
|
| 564 | 569 | all_names = map greName all_gres
|
| 565 | 570 | |
| 571 | + checkThLocalNameNoLift (ieLWrappedUserRdrName l name)
|
|
| 566 | 572 | occs' <- check_occs occs ie all_gres
|
| 567 | 573 | (export_warn_spans', dont_warn_export', warn_txt_rn)
|
| 568 | 574 | <- process_warning export_warn_spans
|
| ... | ... | @@ -589,17 +595,19 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod |
| 589 | 595 | |
| 590 | 596 | lookup_ie_kids_all :: IE GhcPs -> LIEWrappedName GhcPs -> GlobalRdrElt
|
| 591 | 597 | -> RnM [GlobalRdrElt]
|
| 592 | - lookup_ie_kids_all ie (L _ rdr) gre =
|
|
| 598 | + lookup_ie_kids_all ie (L _loc rdr) gre =
|
|
| 593 | 599 | do { let name = greName gre
|
| 594 | 600 | gres = findChildren kids_env name
|
| 595 | - ; addUsedKids (ieWrappedName rdr) gres
|
|
| 596 | - ; when (null gres) $
|
|
| 601 | + -- We only choose level 0 exports when filling in part of an export list implicitly.
|
|
| 602 | + ; let kids_0 = mapMaybe pickLevelZeroGRE gres
|
|
| 603 | + ; addUsedKids (ieWrappedName rdr) kids_0
|
|
| 604 | + ; when (null kids_0) $
|
|
| 597 | 605 | if isTyConName name
|
| 598 | 606 | then addTcRnDiagnostic (TcRnDodgyExports gre)
|
| 599 | 607 | else -- This occurs when you export T(..), but
|
| 600 | 608 | -- only import T abstractly, or T is a synonym.
|
| 601 | 609 | addErr (TcRnExportHiddenComponents ie)
|
| 602 | - ; return gres }
|
|
| 610 | + ; return kids_0 }
|
|
| 603 | 611 | |
| 604 | 612 | -------------
|
| 605 | 613 | |
| ... | ... | @@ -696,6 +704,10 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod |
| 696 | 704 | addUsedKids parent_rdr kid_gres
|
| 697 | 705 | = addUsedGREs ExportDeprecationWarnings (pickGREs parent_rdr kid_gres)
|
| 698 | 706 | |
| 707 | + |
|
| 708 | +ieLWrappedUserRdrName :: LIEWrappedName GhcPs -> Name -> LIdOccP GhcRn
|
|
| 709 | +ieLWrappedUserRdrName l n = fmap (\rdr -> WithUserRdr rdr n) $ ieLWrappedName l
|
|
| 710 | + |
|
| 699 | 711 | -- | In what namespaces should we go looking for an import/export item
|
| 700 | 712 | -- that is out of scope, for suggestions in error messages?
|
| 701 | 713 | ieWrappedNameWhatLooking :: IEWrappedName GhcPs -> WhatLooking
|
| ... | ... | @@ -800,6 +812,7 @@ lookupChildrenExport parent_gre rdr_items = mapAndReportM doOne rdr_items |
| 800 | 812 | ; return (L l (IEName noExtField (L (l2l l) ub)), gre)}
|
| 801 | 813 | FoundChild child@(GRE { gre_name = child_nm, gre_par = par }) ->
|
| 802 | 814 | do { checkPatSynParent spec_parent par child_nm
|
| 815 | + ; checkThLocalNameNoLift (ieLWrappedUserRdrName n child_nm)
|
|
| 803 | 816 | ; return (replaceLWrappedName n child_nm, child)
|
| 804 | 817 | }
|
| 805 | 818 | IncorrectParent p c gs -> failWithDcErr (parentGRE_name p) (greName c) gs
|
| ... | ... | @@ -69,7 +69,7 @@ module GHC.Types.Name.Reader ( |
| 69 | 69 | lookupGRE_Name,
|
| 70 | 70 | lookupGRE_FieldLabel,
|
| 71 | 71 | getGRE_NameQualifier_maybes,
|
| 72 | - transformGREs, pickGREs, pickGREsModExp,
|
|
| 72 | + transformGREs, pickGREs, pickGREsModExp, pickLevelZeroGRE,
|
|
| 73 | 73 | |
| 74 | 74 | -- * GlobalRdrElts
|
| 75 | 75 | availFromGRE,
|
| ... | ... | @@ -144,7 +144,7 @@ import GHC.Utils.Panic |
| 144 | 144 | import GHC.Utils.Binary
|
| 145 | 145 | |
| 146 | 146 | import Control.DeepSeq
|
| 147 | -import Control.Monad ( guard )
|
|
| 147 | +import Control.Monad ( guard , (>=>) )
|
|
| 148 | 148 | import Data.Data
|
| 149 | 149 | import Data.List ( sort )
|
| 150 | 150 | import qualified Data.List.NonEmpty as NE
|
| ... | ... | @@ -641,7 +641,7 @@ greParent = gre_par |
| 641 | 641 | greInfo :: GlobalRdrElt -> GREInfo
|
| 642 | 642 | greInfo = gre_info
|
| 643 | 643 | |
| 644 | -greLevels :: GlobalRdrElt -> Set.Set ImportLevel
|
|
| 644 | +greLevels :: GlobalRdrEltX info -> Set.Set ImportLevel
|
|
| 645 | 645 | greLevels g =
|
| 646 | 646 | if gre_lcl g then Set.singleton NormalLevel
|
| 647 | 647 | else Set.fromList (bagToList (fmap (is_level . is_decl) (gre_imp g)))
|
| ... | ... | @@ -1604,7 +1604,14 @@ pickGREsModExp :: ModuleName -> [GlobalRdrEltX info] -> [(GlobalRdrEltX info,Glo |
| 1604 | 1604 | --
|
| 1605 | 1605 | -- Used only for the 'module M' item in export list;
|
| 1606 | 1606 | -- see 'GHC.Tc.Gen.Export.exports_from_avail'
|
| 1607 | -pickGREsModExp mod gres = mapMaybe (pickBothGRE mod) gres
|
|
| 1607 | +-- This function also only chooses GREs which are at level zero.
|
|
| 1608 | +pickGREsModExp mod gres = mapMaybe (pickLevelZeroGRE >=> pickBothGRE mod) gres
|
|
| 1609 | + |
|
| 1610 | +pickLevelZeroGRE :: GlobalRdrEltX info -> Maybe (GlobalRdrEltX info)
|
|
| 1611 | +pickLevelZeroGRE gre =
|
|
| 1612 | + if NormalLevel `Set.member` greLevels gre
|
|
| 1613 | + then Just gre
|
|
| 1614 | + else Nothing
|
|
| 1608 | 1615 | |
| 1609 | 1616 | -- | isBuiltInSyntax filter out names for built-in syntax They
|
| 1610 | 1617 | -- just clutter up the environment (esp tuples), and the
|
| ... | ... | @@ -213,6 +213,8 @@ With ``-XStrict``:: |
| 213 | 213 | -- inferred unrestricted
|
| 214 | 214 | let ~(x, y) = u in …
|
| 215 | 215 | |
| 216 | +(See :ref:`strict-bindings`).
|
|
| 217 | + |
|
| 216 | 218 | Data types
|
| 217 | 219 | ----------
|
| 218 | 220 | By default, all fields in algebraic data types are linear (even if
|
| ... | ... | @@ -103,6 +103,9 @@ Note the following points: |
| 103 | 103 | See `GHC Proposal #229 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0229-whitespace-bang-patterns.rst>`__
|
| 104 | 104 | for the precise rules.
|
| 105 | 105 | |
| 106 | + |
|
| 107 | +.. _strict-bindings:
|
|
| 108 | + |
|
| 106 | 109 | Strict bindings
|
| 107 | 110 | ~~~~~~~~~~~~~~~
|
| 108 | 111 |
| 1 | +-- Minimal reproducer for https://gitlab.haskell.org/ghc/ghc/-/issues/20645
|
|
| 2 | +{-# LANGUAGE MagicHash #-}
|
|
| 3 | +{-# LANGUAGE ExtendedLiterals #-}
|
|
| 4 | +import GHC.Exts
|
|
| 5 | +import GHC.Word
|
|
| 6 | +import Numeric (showHex)
|
|
| 7 | + |
|
| 8 | +opaqueInt8# :: Int8# -> Int8#
|
|
| 9 | +opaqueInt8# x = x
|
|
| 10 | +{-# OPAQUE opaqueInt8# #-}
|
|
| 11 | + |
|
| 12 | +main :: IO ()
|
|
| 13 | +main = let !x = opaqueInt8# 109#Int8
|
|
| 14 | + !y = opaqueInt8# 1#Int8
|
|
| 15 | + in putStrLn . flip showHex "" . W# $ pext8#
|
|
| 16 | + (word8ToWord# (int8ToWord8# (0#Int8 `subInt8#` x )))
|
|
| 17 | + (word8ToWord# (int8ToWord8# (y `subInt8#` 4#Int8))) |
| 1 | +49 |
| ... | ... | @@ -17,3 +17,4 @@ test('T22487', [normal, normalise_errmsg_fun(ignore_llvm_and_vortex)], compile_a |
| 17 | 17 | test('T22033', [normal, normalise_errmsg_fun(ignore_llvm_and_vortex)], compile_and_run, [''])
|
| 18 | 18 | test('T25730', [req_c, unless(arch('x86_64'), skip), normalise_errmsg_fun(ignore_llvm_and_vortex)], compile_and_run, ['T25730C.c'])
|
| 19 | 19 | # T25730C.c contains Intel instrinsics, so only run this test on x86
|
| 20 | +test('T20645', [normal, normalise_errmsg_fun(ignore_llvm_and_vortex), when(have_llvm(), extra_ways(["optllvm"]))], compile_and_run, ['']) |
| ... | ... | @@ -24,6 +24,7 @@ module Main |
| 24 | 24 | ( main
|
| 25 | 25 | ) where
|
| 26 | 26 | |
| 27 | +import Data.Bits (Bits((.&.), bit))
|
|
| 27 | 28 | import Data.Word
|
| 28 | 29 | import Data.Int
|
| 29 | 30 | import GHC.Natural
|
| ... | ... | @@ -655,8 +656,8 @@ testPrimops = Group "primop" |
| 655 | 656 | , testPrimop "ctz32#" Primop.ctz32# Wrapper.ctz32#
|
| 656 | 657 | , testPrimop "ctz64#" Primop.ctz64# Wrapper.ctz64#
|
| 657 | 658 | , testPrimop "ctz#" Primop.ctz# Wrapper.ctz#
|
| 658 | - , testPrimop "byteSwap16#" Primop.byteSwap16# Wrapper.byteSwap16#
|
|
| 659 | - , testPrimop "byteSwap32#" Primop.byteSwap32# Wrapper.byteSwap32#
|
|
| 659 | + , testPrimop "byteSwap16#" (16 `LowerBitsAreDefined` Primop.byteSwap16#) (16 `LowerBitsAreDefined` Wrapper.byteSwap16#)
|
|
| 660 | + , testPrimop "byteSwap32#" (32 `LowerBitsAreDefined` Primop.byteSwap32#) (32 `LowerBitsAreDefined` Wrapper.byteSwap32#)
|
|
| 660 | 661 | , testPrimop "byteSwap64#" Primop.byteSwap64# Wrapper.byteSwap64#
|
| 661 | 662 | , testPrimop "byteSwap#" Primop.byteSwap# Wrapper.byteSwap#
|
| 662 | 663 | , testPrimop "bitReverse8#" Primop.bitReverse8# Wrapper.bitReverse8#
|
| ... | ... | @@ -672,6 +673,34 @@ testPrimops = Group "primop" |
| 672 | 673 | , testPrimop "narrow32Word#" Primop.narrow32Word# Wrapper.narrow32Word#
|
| 673 | 674 | ]
|
| 674 | 675 | |
| 676 | +-- | A special data-type for representing functions where,
|
|
| 677 | +-- since only some number of the lower bits are defined,
|
|
| 678 | +-- testing for strict equality in the undefined upper bits is not appropriate!
|
|
| 679 | +-- Without using this data-type, false-positive failures will be reported
|
|
| 680 | +-- when the undefined bit regions do not match, even though the equality of bits
|
|
| 681 | +-- in this undefined region has no bearing on correctness.
|
|
| 682 | +data LowerBitsAreDefined =
|
|
| 683 | + LowerBitsAreDefined
|
|
| 684 | + { definedLowerWidth :: Word
|
|
| 685 | + -- ^ The (strictly-non-negative) number of least-significant bits
|
|
| 686 | + -- for which the attached function is defined.
|
|
| 687 | + , undefinedBehavior :: (Word# -> Word#)
|
|
| 688 | + -- ^ Function with undefined behavior for some of its most significant bits.
|
|
| 689 | + }
|
|
| 690 | + |
|
| 691 | +instance TestPrimop LowerBitsAreDefined where
|
|
| 692 | + testPrimop s l r = Property s $ \ (uWord#-> x0) ->
|
|
| 693 | + let -- Create a mask to unset all bits in the undefined area,
|
|
| 694 | + -- leaving set bits only in the area of defined behavior.
|
|
| 695 | + -- Since the upper bits are undefined,
|
|
| 696 | + -- if the function defines behavior for the lower N bits,
|
|
| 697 | + -- then /only/ the lower N bits are preserved,
|
|
| 698 | + -- and the upper WORDSIZE - N bits are discarded.
|
|
| 699 | + mask = bit (fromEnum (definedLowerWidth r)) - 1
|
|
| 700 | + valL = wWord# (undefinedBehavior l x0) .&. mask
|
|
| 701 | + valR = wWord# (undefinedBehavior r x0) .&. mask
|
|
| 702 | + in valL === valR
|
|
| 703 | + |
|
| 675 | 704 | instance TestPrimop (Char# -> Char# -> Int#) where
|
| 676 | 705 | testPrimop s l r = Property s $ \ (uChar#-> x0) (uChar#-> x1) -> wInt# (l x0 x1) === wInt# (r x0 x1)
|
| 677 | 706 |
| 1 | +{-# LANGUAGE ExplicitLevelImports #-}
|
|
| 2 | +module DodgyLevelExport ( T(..) ) where
|
|
| 3 | + |
|
| 4 | +import quote DodgyLevelExportA
|
|
| 5 | +import DodgyLevelExportA (T) |
| 1 | +DodgyLevelExport.hs:2:27: warning: [GHC-75356] [-Wdodgy-exports (in -Wextra)]
|
|
| 2 | + The export item ‘T(..)’ suggests that
|
|
| 3 | + ‘T’ has (in-scope) constructors or record fields, but it has none
|
|
| 4 | + |
| 1 | +module DodgyLevelExportA where
|
|
| 2 | + |
|
| 3 | +data T = T { a :: Int } |
| 1 | +{-# LANGUAGE ExplicitLevelImports #-}
|
|
| 2 | +module LevelImportExports ( module LevelImportExportsA, T(..) ) where
|
|
| 3 | + |
|
| 4 | +import quote LevelImportExportsA
|
|
| 5 | +import splice LevelImportExportsA
|
|
| 6 | +import LevelImportExportsA(a, T) |
| 1 | +[1 of 2] Compiling LevelImportExportsA ( LevelImportExportsA.hs, LevelImportExportsA.o )
|
|
| 2 | +[2 of 2] Compiling LevelImportExports ( LevelImportExports.hs, LevelImportExports.o )
|
|
| 3 | +exports:
|
|
| 4 | + LevelImportExportsA.a
|
|
| 5 | + LevelImportExportsA.T
|
|
| 6 | +defaults: |
| 1 | +module LevelImportExportsA where
|
|
| 2 | + |
|
| 3 | +a = 100
|
|
| 4 | +b = 100
|
|
| 5 | + |
|
| 6 | +data T = T { c :: Int } |
| ... | ... | @@ -24,5 +24,9 @@ SI10_oneshot: |
| 24 | 24 | "$(TEST_HC)" $(TEST_HC_OPTS) -c InstanceA.hs
|
| 25 | 25 | "$(TEST_HC)" $(TEST_HC_OPTS) -c SI10.hs
|
| 26 | 26 | |
| 27 | +LevelImportExports:
|
|
| 28 | + "$(TEST_HC)" $(TEST_HC_OPTS) -haddock LevelImportExports.hs
|
|
| 29 | + "$(TEST_HC)" --show-iface LevelImportExports.hi | grep -A3 "^exports:"
|
|
| 30 | + |
|
| 27 | 31 | clean:
|
| 28 | 32 | rm -f *.o *.hi |
| 1 | +module ModuleExport where
|
|
| 2 | + |
|
| 3 | +-- Should fail
|
|
| 4 | +import ModuleExportA (a) |
| 1 | +ModuleExport.hs:4:23: error: [GHC-61689]
|
|
| 2 | + Module ‘ModuleExportA’ does not export ‘a’.
|
|
| 3 | + |
| 1 | +{-# LANGUAGE ExplicitLevelImports #-}
|
|
| 2 | +-- Module export only exports level 0 things (b)
|
|
| 3 | +module ModuleExportA (module ModuleExportB) where
|
|
| 4 | + |
|
| 5 | +-- Everything at level 1
|
|
| 6 | +import quote ModuleExportB
|
|
| 7 | +-- Only b at level 0
|
|
| 8 | +import ModuleExportB (b) |
| 1 | +module ModuleExportB where
|
|
| 2 | + |
|
| 3 | +a = ()
|
|
| 4 | +b = ()
|
|
| 5 | + |
|
| 6 | + |
| 1 | +{-# LANGUAGE ExplicitLevelImports, TemplateHaskell #-}
|
|
| 2 | +module T26090 ( a --varaible
|
|
| 3 | + , T(..) -- WithAll
|
|
| 4 | + , S(s) -- With
|
|
| 5 | + , R -- Abs
|
|
| 6 | + ) where
|
|
| 7 | + |
|
| 8 | +import quote T26090A
|
|
| 9 | +import T26090A (T(T), S)
|
|
| 10 | + |
| 1 | +T26090.hs:2:17: error: [GHC-28914]
|
|
| 2 | + • Level error: ‘a’ is bound at level 1 but used at level 0
|
|
| 3 | + • Available from the imports:
|
|
| 4 | + • imported from ‘T26090A’ at 1 at T26090.hs:8:1-20
|
|
| 5 | + |
|
| 6 | +T26090.hs:4:17: error: [GHC-28914]
|
|
| 7 | + • Level error: ‘s’ is bound at level 1 but used at level 0
|
|
| 8 | + • Available from the imports:
|
|
| 9 | + • imported from ‘T26090A’ at 1 at T26090.hs:8:1-20
|
|
| 10 | + • In the export: S(s)
|
|
| 11 | + |
|
| 12 | +T26090.hs:5:17: error: [GHC-28914]
|
|
| 13 | + • Level error: ‘R’ is bound at level 1 but used at level 0
|
|
| 14 | + • Available from the imports:
|
|
| 15 | + • imported from ‘T26090A’ at 1 at T26090.hs:8:1-20
|
|
| 16 | + |
| 1 | +{-# LANGUAGE ExplicitLevelImports, TemplateHaskell #-}
|
|
| 2 | +module T26090A where
|
|
| 3 | + |
|
| 4 | +import Language.Haskell.TH
|
|
| 5 | + |
|
| 6 | +a :: Q Exp
|
|
| 7 | +a = [| True |]
|
|
| 8 | + |
|
| 9 | +data T = T { t :: () }
|
|
| 10 | + |
|
| 11 | +data S = S { s :: () }
|
|
| 12 | + |
|
| 13 | +data R = R { r :: () }
|
|
| 14 | + |
| ... | ... | @@ -48,3 +48,7 @@ test('SI35', |
| 48 | 48 | 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'])
|
| 49 | 49 | test('T26087', [], multimod_compile_fail, ['T26087A', ''])
|
| 50 | 50 | test('T26088', [], multimod_compile_fail, ['T26088A', '-v0'])
|
| 51 | +test('T26090', [], multimod_compile_fail, ['T26090', '-v0'])
|
|
| 52 | +test('ModuleExport', [], multimod_compile_fail, ['ModuleExport', '-v0'])
|
|
| 53 | +test('LevelImportExports', [], makefile_test, [])
|
|
| 54 | +test('DodgyLevelExport', [], multimod_compile, ['DodgyLevelExport', '-v0 -Wdodgy-exports']) |