/libraries/ghc-prim/GHC/Prim/Panic.hs

https://github.com/bgamari/ghc · Haskell · 103 lines · 25 code · 10 blank · 68 comment · 2 complexity · 5aad88da44b65d8ddf5b27cd1ff45ac9 MD5 · raw file

  1. {-# LANGUAGE GHCForeignImportPrim #-}
  2. {-# LANGUAGE UnliftedFFITypes #-}
  3. {-# LANGUAGE MagicHash #-}
  4. {-# LANGUAGE UnboxedTuples #-}
  5. {-# LANGUAGE NoImplicitPrelude #-}
  6. {-# LANGUAGE EmptyCase #-}
  7. -- | Primitive panics.
  8. module GHC.Prim.Panic
  9. ( absentSumFieldError
  10. , panicError
  11. , absentError
  12. )
  13. where
  14. import GHC.Prim
  15. import GHC.Magic
  16. default () -- Double and Integer aren't available yet
  17. {-
  18. Note [Compiler error functions]
  19. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  20. Most error functions (such as pattern match failure) are defined
  21. in base:Control.Exception.Base. But absentError# and absentSumFieldError#
  22. are defined here in the ghc-prim package for two reasons:
  23. * GHC itself generates calls to these functions as a result of
  24. strictness analysis, over which the programmer has no control. So
  25. it is hard to ensure that no such calls exist in the modules
  26. compiled "before" Control.Base.Exception. (E.g. when compiling
  27. with -fdicts-strict.)
  28. * A consequence of defining them in ghc-prim is that the libraries
  29. defining exceptions have not yet been built, so we can't make them
  30. into proper Haskell exceptions.
  31. However, if these functions are ever called, it's a /compiler/ error,
  32. not a user error, so it seems acceptable that they cannot be caught.
  33. One might wonder why absentError doesn't just call panic#.
  34. For absent error we want to combine two parts, one static, one call site
  35. dependent into one error message. While for absentSumFieldError it's a
  36. static string.
  37. The easiest way to combine the two parts for absentError is to use a
  38. format string with `barf` in the RTS passing the *dynamic* part of the
  39. error as argument. There is no need to do any of this for
  40. absentSumFieldError as it's a static string there.
  41. The alternatives would be to:
  42. * Drop the call site specific information from absentError.
  43. The call site specific information is at times very helpful for debugging
  44. so I don't consider this an option.
  45. * Remove the common prefix. We would then need to include the prefix
  46. in the call site specific string we pass to absentError. Increasing
  47. code size for no good reason.
  48. Both of which seem worse than having an stg_absentError function specific to
  49. absentError to me.
  50. -}
  51. -- `stg_panic#` never returns but it can't just return `State# RealWorld` so we
  52. -- indicate that it returns `(# #)` too to make the compiler happy.
  53. -- See Note [Compiler error functions]
  54. foreign import prim "stg_paniczh" panic# :: Addr# -> State# RealWorld -> (# State# RealWorld, (# #) #)
  55. -- See Note [Compiler error functions]
  56. foreign import prim "stg_absentErrorzh" stg_absentError# :: Addr# -> State# RealWorld -> (# State# RealWorld, (# #) #)
  57. -- | Display the CString whose address is given as an argument and exit.
  58. panicError :: Addr# -> a
  59. panicError errmsg =
  60. runRW# (\s ->
  61. case panic# errmsg s of
  62. (# _, _ #) -> -- This bottom is unreachable but we can't
  63. -- use an empty case lest the pattern match
  64. -- checker squawks.
  65. let x = x in x)
  66. -- | Closure introduced by GHC.Stg.Unarise for unused unboxed sum fields.
  67. --
  68. -- See Note [aBSENT_SUM_FIELD_ERROR_ID] in GHC.Core.Make
  69. absentSumFieldError :: a
  70. absentSumFieldError = panicError "entered absent sum field!"#
  71. -- GHC.Core.Make.aBSENT_SUM_FIELD_ERROR_ID gives absentSumFieldError a bottoming
  72. -- demand signature. But if we ever inlined it (to a call to panicError) we'd
  73. -- lose that information. Should not happen because absentSumFieldError is only
  74. -- introduced in Stg.Unarise, long after inlining has stopped, but it seems
  75. -- more direct simply to give it a NOINLINE pragma
  76. {-# NOINLINE absentSumFieldError #-}
  77. -- | Displays "Oops! Entered absent arg" ++ errormsg and exits the program.
  78. {-# NOINLINE absentError #-}
  79. absentError :: Addr# -> a
  80. absentError errmsg =
  81. runRW# (\s ->
  82. case stg_absentError# errmsg s of
  83. (# _, _ #) -> -- This bottom is unreachable but we can't
  84. -- use an empty case lest the pattern match
  85. -- checker squawks.
  86. let x = x in x)