Another CPP gotcha for the manual

Turns out that c pre-processing removes C style (/*…*/) comments. Of course, it will do this anywhere in the source. The following program can tell if it is compiled *-cpp* or not: module Main where (*/**) :: Double -> Double -> Double (*/**) a b = a / (2 ** b) howCompiled = if use > 1/16 then "normal" else "-cpp" where use = 1 */** 2 + 3 */** 4 main = putStrLn $ "compiled " ++ howCompiled When run: & runhaskell CppTest.hs compiled normal & runhaskell -cpp CppTest.hs compiled -cpp An example in the wild is in the package *wai-extra*, in the file *Network/Wai/Middleware/RequestLogger.hs* where the */* construct appears twice in the comments. Short of defining and implementing our own CPP-like preprocessing (something we might actually consider), I don't think there really is any fix for this, so the bug is that it should appear in the GHC documentation on CPP mode (§4.12.3), along with similar warnings about trailing back-slashes. Note that the way in which a multi-line comment is removed differs between *gcc* and *clang*. In *gcc*, the comment is removed and content of the line before the comment, and contents of the line after the comment are joined into a single line. In *clang*, the two line fragments are kept on separate lines. In both cases extra empty lines are added to keep the line count the same. The consequence of the *gcc* / *clang* difference is that neither the above code, nor wai-extra will compile with *clang*. Note: As far as I can tell this is not a *clang* bug, but a failure of specs: The C definition of comments and their removal is vague, and my guess is *gcc* choose its method based on historical use. The C++ definition makes it clear that comments are whitespace, even once removed, and so the *clang* method is correct. - Mark

An example in the wild is in the package wai-extra, in the file Network/Wai/Middleware/RequestLogger.hs where the */* construct appears twice in the comments.
An even more common case could be the operator '//' of the vector package. cpp also removes C++ style comments. I once almost got crazy finding this kind issue, because the resulting code still type checked. Greetings, Daniel

This does not appear to be the case, at least any more. The way GHC invokes gcc for c pre-processing only removes /*…*/ style comments, not the later // style: module Main where (//) :: Double -> Double -> Double a // b = a / b / b main = print $ 1 // 2 works: & runhaskell -cpp CppTest2.hs 0.25

Hi Mark, On Sun, Nov 03, 2013 at 03:01:32PM -0800, Mark Lentczner wrote:
This does not appear to be the case, at least any more. The way GHC invokes gcc for c pre-processing only removes /*…*/ style comments, not the later // style:
Yes, I can reproduce your behaviour on my system and ghc seems to call cpp with some options, because the default behaviour removes C++ style comments: dan@machine ~> cat cpp.test /* comment */ code // comment dan@machine ~> cpp cpp.test # 1 "cpp.test" # 1 "<command-line>" # 1 "cpp.test" code I can't recall it exactly, if I had the C++ comment issue only with cpphs, because cpp had problems with some Haskell code, or if I also had the issue with cpp itself. I just tried cpphs and its default behaviour removes the C++ style comments: dan@machine ~> cat test.hs (//) :: Double -> Double -> Double a // b = a / b / b main = print $ 1 // 2 dan@machine ~> ghci Prelude> :set -cpp -pgmPcpphs -optP--cpp Prelude> :l test [1 of 1] Compiling Main ( test.hs, interpreted ) test.hs:2:1: parse error (possibly incorrect indentation or mismatched brackets) Failed, modules loaded: none. That's a bit unfortunate, that the default behaviour of ghc using cpp and cpphs differs. Greetings, Daniel

Of course, cpphs solved this problem nearly a decade ago. Regards, Malcolm On 3 Nov 2013, at 17:57, Mark Lentczner wrote:
Turns out that c pre-processing removes C style (/*…*/) comments. Of course, it will do this anywhere in the source. The following program can tell if it is compiled -cpp or not:
module Main where
(*/**) :: Double -> Double -> Double (*/**) a b = a / (2 ** b)
howCompiled = if use > 1/16 then "normal" else "-cpp" where use = 1 */** 2 + 3 */** 4
main = putStrLn $ "compiled " ++ howCompiled
When run:
& runhaskell CppTest.hs compiled normal
& runhaskell -cpp CppTest.hs compiled -cpp
An example in the wild is in the package wai-extra, in the file Network/Wai/Middleware/RequestLogger.hs where the */* construct appears twice in the comments.
Short of defining and implementing our own CPP-like preprocessing (something we might actually consider), I don't think there really is any fix for this, so the bug is that it should appear in the GHC documentation on CPP mode (§4.12.3), along with similar warnings about trailing back-slashes.
Note that the way in which a multi-line comment is removed differs between gcc and clang. In gcc, the comment is removed and content of the line before the comment, and contents of the line after the comment are joined into a single line. In clang, the two line fragments are kept on separate lines. In both cases extra empty lines are added to keep the line count the same.
The consequence of the gcc / clang difference is that neither the above code, nor wai-extra will compile with clang.
Note: As far as I can tell this is not a clang bug, but a failure of specs: The C definition of comments and their removal is vague, and my guess is gcc choose its method based on historical use. The C++ definition makes it clear that comments are whitespace, even once removed, and so the clang method is correct.
- Mark
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs

Hello Malcolm, On 2013-11-04 at 10:28:27 +0100, Malcolm Wallace wrote:
Of course, cpphs solved this problem nearly a decade ago.
Btw, what has been the reason it hasn't been adopted as bundled `cpp` replacement in the GHC distribution in the past? (if it remains a separate executable, its GPL licence shouldn't be an issue -- after all, ghc relies on the gcc executable which is GPL'ed too) cheers, hvr

AFAIK, it is solely the (L)GPL licence issue. GHC central preferred to use/distribute the GPL'd gcc compiler rather than the GPL'd cpphs preprocessor. (No, it made no sense to me either.) Regards, Malcolm On 4 Nov 2013, at 09:40, Herbert Valerio Riedel wrote:
Hello Malcolm,
On 2013-11-04 at 10:28:27 +0100, Malcolm Wallace wrote:
Of course, cpphs solved this problem nearly a decade ago.
Btw, what has been the reason it hasn't been adopted as bundled `cpp` replacement in the GHC distribution in the past? (if it remains a separate executable, its GPL licence shouldn't be an issue -- after all, ghc relies on the gcc executable which is GPL'ed too)
cheers, hvr _______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs

Maybe we should experiment with it a bit more seriously. With cabal 1.18 it's super easy to tell ghc to call an external program for the cpp pass. And that's our current source of problems. On Monday, November 4, 2013, Malcolm Wallace wrote:
AFAIK, it is solely the (L)GPL licence issue. GHC central preferred to use/distribute the GPL'd gcc compiler rather than the GPL'd cpphs preprocessor. (No, it made no sense to me either.)
Regards, Malcolm
On 4 Nov 2013, at 09:40, Herbert Valerio Riedel wrote:
Hello Malcolm,
On 2013-11-04 at 10:28:27 +0100, Malcolm Wallace wrote:
Of course, cpphs solved this problem nearly a decade ago.
Btw, what has been the reason it hasn't been adopted as bundled `cpp` replacement in the GHC distribution in the past? (if it remains a separate executable, its GPL licence shouldn't be an issue -- after all, ghc relies on the gcc executable which is GPL'ed too)
cheers, hvr _______________________________________________ ghc-devs mailing list ghc-devs@haskell.org javascript:; http://www.haskell.org/mailman/listinfo/ghc-devs
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org javascript:; http://www.haskell.org/mailman/listinfo/ghc-devs

I mean, that may be the best near term fix for our problems. Does require Haskell platform to ship with cabal 1.18, but maybe that approach would fix all the cpp woes for the near term. ESP since most cpp use is in cabalized projects anyways. On Monday, November 4, 2013, Carter Schonwald wrote:
Maybe we should experiment with it a bit more seriously. With cabal 1.18 it's super easy to tell ghc to call an external program for the cpp pass. And that's our current source of problems.
On Monday, November 4, 2013, Malcolm Wallace wrote:
AFAIK, it is solely the (L)GPL licence issue. GHC central preferred to use/distribute the GPL'd gcc compiler rather than the GPL'd cpphs preprocessor. (No, it made no sense to me either.)
Regards, Malcolm
On 4 Nov 2013, at 09:40, Herbert Valerio Riedel wrote:
Hello Malcolm,
On 2013-11-04 at 10:28:27 +0100, Malcolm Wallace wrote:
Of course, cpphs solved this problem nearly a decade ago.
Btw, what has been the reason it hasn't been adopted as bundled `cpp` replacement in the GHC distribution in the past? (if it remains a separate executable, its GPL licence shouldn't be an issue -- after all, ghc relies on the gcc executable which is GPL'ed too)
cheers, hvr _______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs

cpphs would be *another* GPL dependency. It doesn't replace gcc, which we need for other reasons, so at the time adopting cpphs didn't solve any problems. Now, arguably it would. I'd still prefer not to add another GPL dependency(*). But I'm not going to argue strongly against it. If we're seriously considering using cpphs, we should carefully measure the impact on compilation time. Cheers, Simon (*) For the pedants, yes I know the difference between GPL and LGPL and the difference between library and executable dependencies. I was a pedant once too :-) On 04/11/2013 09:52, Malcolm Wallace wrote:
AFAIK, it is solely the (L)GPL licence issue. GHC central preferred to use/distribute the GPL'd gcc compiler rather than the GPL'd cpphs preprocessor. (No, it made no sense to me either.)
Regards, Malcolm
On 4 Nov 2013, at 09:40, Herbert Valerio Riedel wrote:
Hello Malcolm,
On 2013-11-04 at 10:28:27 +0100, Malcolm Wallace wrote:
Of course, cpphs solved this problem nearly a decade ago.
Btw, what has been the reason it hasn't been adopted as bundled `cpp` replacement in the GHC distribution in the past? (if it remains a separate executable, its GPL licence shouldn't be an issue -- after all, ghc relies on the gcc executable which is GPL'ed too)
cheers, hvr _______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs

On Sun, Nov 3, 2013 at 11:57 AM, Mark Lentczner
Turns out that c pre-processing removes C style (/*…*/) comments. Of course, it will do this anywhere in the source. The following program can tell if it is compiled -cpp or not:
module Main where
(*/**) :: Double -> Double -> Double (*/**) a b = a / (2 ** b)
howCompiled = if use > 1/16 then "normal" else "-cpp" where use = 1 */** 2 + 3 */** 4
main = putStrLn $ "compiled " ++ howCompiled
When run:
& runhaskell CppTest.hs compiled normal
& runhaskell -cpp CppTest.hs compiled -cpp
An example in the wild is in the package wai-extra, in the file Network/Wai/Middleware/RequestLogger.hs where the */* construct appears twice in the comments.
Short of defining and implementing our own CPP-like preprocessing (something we might actually consider), I don't think there really is any fix for this, so the bug is that it should appear in the GHC documentation on CPP mode (§4.12.3), along with similar warnings about trailing back-slashes.
Note that the way in which a multi-line comment is removed differs between gcc and clang. In gcc, the comment is removed and content of the line before the comment, and contents of the line after the comment are joined into a single line. In clang, the two line fragments are kept on separate lines. In both cases extra empty lines are added to keep the line count the same.
The consequence of the gcc / clang difference is that neither the above code, nor wai-extra will compile with clang.
Note: As far as I can tell this is not a clang bug, but a failure of specs: The C definition of comments and their removal is vague, and my guess is gcc choose its method based on historical use. The C++ definition makes it clear that comments are whitespace, even once removed, and so the clang method is correct.
The effect of feeding CPP with a non-C or non-C++ program isn't defined :-) -- Gaby
participants (7)
-
Carter Schonwald
-
Daniel Trstenjak
-
Gabriel Dos Reis
-
Herbert Valerio Riedel
-
Malcolm Wallace
-
Mark Lentczner
-
Simon Marlow