GHC inlining primitive string literals can affect program output
First noted in #11292, this program, when compiled with `-O1` or higher:
```hs
{-# LANGUAGE MagicHash #-}
module Main (main) where
import GHC.Exts (Addr#, isTrue#)
import GHC.Prim (eqAddr#)
data A = A { runA :: Addr# }
a :: A
a = A "a"#
main :: IO ()
main = print (isTrue# (eqAddr# (runA a) (runA a)))
```
will result in the following after inlining:
```
Main.main2 =
case GHC.Prim.tagToEnum#
@ GHC.Types.Bool (GHC.Prim.eqAddr# "a"# "a"#)
of _ [Occ=Dead] {
GHC.Types.False -> GHC.Show.shows26;
GHC.Types.True -> GHC.Show.shows24
}
```
As a result, there are two of the same string constant with different addresses, which causes `eqAddr#` to return `False`. If compiled without optimizations, `"a"#` is not inlined, and as a result, `eqAddr#` returns `True`.
Two questions:
1. Is this okay semantics-wise? Or is this a necessary risk when working with primitive string literals, and should programmers judiciously use `{-# NOINLINE #-}` with them?
1. Is this okay from a code duplication standpoint? As Reid Barton noted in #11292, `"a"#` is duplicated due to inlining. In this example, not much is duplicated, but if it were a longer string constant, that could result in a noticeable increase in the object file size.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.10.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | #11292 |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"GHC inlining primitive string literals can affect program output","status":"New","operating_system":"","component":"Compiler","related":[11292],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.10.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"First noted in #11292, this program, when compiled with `-O1` or higher:\r\n\r\n{{{#!hs\r\n{-# LANGUAGE MagicHash #-}\r\nmodule Main (main) where\r\n\r\nimport GHC.Exts (Addr#, isTrue#)\r\nimport GHC.Prim (eqAddr#)\r\n\r\ndata A = A { runA :: Addr# }\r\n\r\na :: A\r\na = A \"a\"#\r\n\r\nmain :: IO ()\r\nmain = print (isTrue# (eqAddr# (runA a) (runA a)))\r\n}}}\r\n\r\nwill result in the following after inlining:\r\n\r\n{{{\r\nMain.main2 =\r\n case GHC.Prim.tagToEnum#\r\n @ GHC.Types.Bool (GHC.Prim.eqAddr# \"a\"# \"a\"#)\r\n of _ [Occ=Dead] {\r\n GHC.Types.False -> GHC.Show.shows26;\r\n GHC.Types.True -> GHC.Show.shows24\r\n }\r\n}}}\r\n\r\nAs a result, there are two of the same string constant with different addresses, which causes `eqAddr#` to return `False`. If compiled without optimizations, `\"a\"#` is not inlined, and as a result, `eqAddr#` returns `True`.\r\n\r\nTwo questions:\r\n\r\n1. Is this okay semantics-wise? Or is this a necessary risk when working with primitive string literals, and should programmers judiciously use `{-# NOINLINE #-}` with them?\r\n2. Is this okay from a code duplication standpoint? As Reid Barton noted in #11292, `\"a\"#` is duplicated due to inlining. In this example, not much is duplicated, but if it were a longer string constant, that could result in a noticeable increase in the object file size.","type_of_failure":"OtherFailure","blocking":[]} -->
issue