I've isolated the issue to the handling of if defined on multi-argument macros.
I took a crack at interpreting the cpphs source for this and I think it may be a bug in the conversion of defined expressions here in Language.Preprocessor.CppIfdef here:
convert "defined" [arg] =
case lookupST arg st of
Nothing | all isDigit arg -> return arg
Nothing -> return "0"
Just (a@AntiDefined{}) -> return "0"
Just (a@SymbolReplacement{}) -> return "1"
Just (a@MacroExpansion{}) -> return "1"
It looks like it will macro expand the contents of a defined expression which isn't what GCC does. I don't know if GCC is wrong or if using parameterized macros within
if defined works on single-argument macros.
working1.hs:
{-# LANGUAGE CPP #-}
#define EXAMPLE_MACRO(arg) (\
arg)
#if defined(EXAMPLE_MACRO)
#endif
preprocess it (it works!):
$ cpphs --cpp working1.hs -o $tempfile
$
ifdef works on multiple-argument macros.
working2.hs:
{-# LANGUAGE CPP #-}
#define EXAMPLE_MACRO(arg1,arg2) (\
arg1 > arg2)
#ifdef EXAMPLE_MACRO
#endif
preprocess it (it works!):
$ cpphs --cpp working2.hs -o $tempfile
$
if defined fails on multi-argument macros.
broken2.hs:
{-# LANGUAGE CPP #-}
#define EXAMPLE_MACRO(arg1,arg2) (\
arg1 > arg2)
#if defined(EXAMPLE_MACRO)
#endif
preprocess it (it fails!):
$ cpphs --cpp broken2.hs -o $tempfile
cpphs: macro EXAMPLE_MACRO expected 2 arguments, but was given 0
$
I've posted a StackOverflow question to see if any of them know if this is undefined behavior:
If it is undefined behavior we should stop relying on it in GHC sources. Either way the behavior is inconsistent with GCC which complicates things.
Best,
Alain