On Mon, 27 Apr 2026 at 20:48, Harald Anlauf wrote:
> Am 27.04.26 um 8:37 PM schrieb Andrew Pinski:
>> On Thu, Apr 16, 2026 at 10:18 AM Christopher Albert <[email protected]> wrote:
>>>
>>> The Fortran preprocessor has never defined target-specific macros such as
>>> __linux__, __unix__, __ELF__, __x86_64__, or __amd64__ that the C
>>> preprocessor provides.  This was caused by the TARGET_OS_CPP_BUILTINS,
>>> TARGET_OBJFMT_CPP_BUILTINS, and TARGET_CPU_CPP_BUILTINS hooks being
>>> disabled since 2008 (marked as "Pandora's Box") because several target
>>> config headers use C-family-only functions.
>>>
>>> Fix by providing Fortran-compatible local helpers for
>>> builtin_define_std, builtin_define_with_value, and
>>> builtin_define_with_int_value (which in the C frontend live in
>>> c-family/c-cppbuiltin.cc and use the C-family-only globals parse_in
>>> and flag_iso), plus wrapper macros for c_dialect_cxx, flag_iso, and
>>> other C-family identifiers referenced by target config headers.  This
>>> allows TARGET_OS_CPP_BUILTINS and TARGET_OBJFMT_CPP_BUILTINS to
>>> execute in the Fortran frontend.
>>>
>>> Unlike the C frontend default (flag_iso=0, GNU extensions mode), the
>>> Fortran wrapper sets flag_iso=1 to suppress user-namespace macros like
>>> bare "unix" and "linux" that would conflict with Fortran identifiers.
>>> Only the reserved-namespace forms (__unix__, __linux__, etc.) are
>>> defined.  Fortran has no -std=cNN equivalent to control this, so the
>>> conservative choice avoids silent identifier replacement.
>>>
>>> For TARGET_CPU_CPP_BUILTINS, which on most architectures expands to a
>>> function in a C-family-only object file (e.g., ix86_target_macros in
>>> i386-c.cc), provide an x86 implementation directly in fortran/cpp.cc
>>> that covers architecture identification and float-size macros.
>>> ISA feature macros (__SSE__, __AVX__, etc.) are not included; if
>>> needed, they could be factored out of i386-c.cc into a shared object.
>>>
>>> Remove the dead __attribute__((target(...))) block from
>>> gfortran.dg/gomp/declare-variant-10.f90: it was guarded by
>>> #if defined(__x86_64__) which was previously always false because
>>> gfortran never defined these macros, and gfortran does not support
>>> C-style __attribute__ syntax.
>>>
>>> Co-authored-by: Kai Tietz <[email protected]>
>>>
>>>          PR fortran/42954
>>>
>>> gcc/fortran/ChangeLog:
>>>
>>>          * cpp.cc (gfc_builtin_define_std): New helper mirroring
>>>          builtin_define_std from c-family/c-cppbuiltin.cc.
>>>          (gfc_builtin_define_with_value): New helper mirroring
>>>          builtin_define_with_value from c-family/c-cppbuiltin.cc.
>>>          (gfc_define_ix86_target_macros): New function providing x86 CPU
>>>          identification macros for the Fortran preprocessor.
>>>          (gfc_darwin_cpp_builtins): New function providing Darwin platform
>>>          macros.
>>>          (cpp_define_builtins): Remove Pandora's Box FIXME.  Add wrapper
>>>          macros for C-family functions and variables used in target config
>>>          headers.  Set flag_iso=1 to suppress bare-name macros.  Enable
>>>          TARGET_OS_CPP_BUILTINS and TARGET_OBJFMT_CPP_BUILTINS.  Call
>>>          gfc_define_ix86_target_macros on x86 targets.
>> 
>> THIS is all wrong and causes too many issues. Please revert this.
>
> I haven't pushed yet, so all should be fine.
>
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>>          * gfortran.dg/gomp/declare-variant-10.f90: Remove dead
>>>          __attribute__((target)) block that is now exposed by newly
>>>          defined target macros.
>>>          * gfortran.dg/pr42954-linux.f90: New test.
>>>          * gfortran.dg/pr42954-x86.f90: New test.
>>>
>>> Signed-off-by: Christopher Albert <[email protected]>
>>> ---
>>>   gcc/fortran/cpp.cc                            | 178 ++++++++++++++++--
>>>   .../gfortran.dg/gomp/declare-variant-10.f90   |   3 -
>>>   gcc/testsuite/gfortran.dg/pr42954-linux.f90   |  24 +++
>>>   gcc/testsuite/gfortran.dg/pr42954-x86.f90     |  10 +
>>>   4 files changed, 194 insertions(+), 21 deletions(-)
>>>   create mode 100644 gcc/testsuite/gfortran.dg/pr42954-linux.f90
>>>   create mode 100644 gcc/testsuite/gfortran.dg/pr42954-x86.f90
>>>
>>> diff --git a/gcc/fortran/cpp.cc b/gcc/fortran/cpp.cc
>>> index 6b5f136e4f3..ada1bc1a211 100644
>>> --- a/gcc/fortran/cpp.cc
>>> +++ b/gcc/fortran/cpp.cc
>>> @@ -157,6 +157,126 @@ void pp_dir_change (cpp_reader *, const char *);
>>>   static int dump_macro (cpp_reader *, cpp_hashnode *, void *);
>>>   static void dump_queued_macros (cpp_reader *);
>>>
>>> +/* Fortran-local helpers that mirror builtin_define_std,
>>> +   builtin_define_with_value, and builtin_define_with_int_value from
>>> +   c-family/c-cppbuiltin.cc.  Those functions use the C-family-only
>>> +   globals parse_in and flag_iso, so they cannot be called directly
>>> +   from the Fortran frontend.  */
>>> +
>>> +/* Given "unix", define __unix, __unix__, and (if DEFINE_USER) unix.  */
>>> +
>>> +static void
>>> +gfc_builtin_define_std (cpp_reader *pfile, const char *macro,
>>> +                       bool define_user)
>>> +{
>>> +  size_t len = strlen (macro);
>>> +  char *buff = (char *) alloca (len + 5);
>>> +  char *p = buff + 2;
>>> +  char *q = p + len;
>>> +
>>> +  memcpy (p, macro, len + 1);
>>> +  if (!(*p == '_' && (p[1] == '_' || ISUPPER (p[1]))))
>>> +    {
>>> +      if (*p != '_')
>>> +       *--p = '_';
>>> +      if (p[1] != '_')
>>> +       *--p = '_';
>>> +    }
>>> +  cpp_define (pfile, p);
>>> +
>>> +  if (p != buff + 2)
>>> +    {
>>> +      if (q[-1] != '_')
>>> +       *q++ = '_';
>>> +      if (q[-2] != '_')
>>> +       *q++ = '_';
>>> +      *q = '\0';
>>> +      cpp_define (pfile, p);
>>> +      if (define_user)
>>> +       cpp_define (pfile, macro);
>>> +    }
>>> +}
>>> +
>>> +/* Define MACRO to EXPANSION; if IS_STR, quote the expansion.  */
>>> +
>>> +static void
>>> +gfc_builtin_define_with_value (cpp_reader *pfile, const char *macro,
>>> +                              const char *expansion, int is_str)
>>> +{
>>> +  size_t mlen = strlen (macro);
>>> +  size_t elen = strlen (expansion);
>>> +  char *buf = (char *) alloca (mlen + elen + 4);
>>> +  if (is_str)
>>> +    sprintf (buf, "%s=\"%s\"", macro, expansion);
>>> +  else
>>> +    sprintf (buf, "%s=%s", macro, expansion);
>>> +  cpp_define (pfile, buf);
>>> +}
>>> +
>>> +/* Provide x86 CPU identification macros for the Fortran preprocessor.
>>> +   TARGET_CPU_CPP_BUILTINS() cannot be called directly because it expands
>>> +   to ix86_target_macros() in i386-c.cc, which is only linked into
>>> +   C-family frontends.  This covers architecture identification and
>>> +   float-size macros.  ISA feature macros (__SSE__, __AVX__, etc.) and
>>> +   arch/tune macros (__znver4__, __skylake__, etc.) from
>>> +   ix86_target_macros_internal() are not included; if needed, they could
>>> +   be factored out of i386-c.cc into a shared object.  */
>>> +
>>> +#ifdef TARGET_80387
>> 
>> Please DON'T add target defines directly to the front-end.
>> Please instead use a config file from the target instead. Like what is
>> done for d, rust, etc. front-ends.
>> Each target should have their a source file which does the cpp_
>> instead of inlining it in the fortran front-end.
>> 
>> Thanks,
>> Andrea
>
> Alright, back to Chris...
>
> Thanks for stepping in quickly!
>
> Harald
>
>>> +static void
>>> +gfc_define_ix86_target_macros (cpp_reader *pfile)
>>> +{
>>> +  if (TARGET_64BIT)
>>> +    {
>>> +      cpp_assert (pfile, "cpu=x86_64");
>>> +      cpp_assert (pfile, "machine=x86_64");
>>> +      cpp_define (pfile, "__amd64");
>>> +      cpp_define (pfile, "__amd64__");
>>> +      cpp_define (pfile, "__x86_64");
>>> +      cpp_define (pfile, "__x86_64__");
>>> +      if (TARGET_X32)
>>> +       {
>>> +         cpp_define (pfile, "_ILP32");
>>> +         cpp_define (pfile, "__ILP32__");
>>> +       }
>>> +    }
>>> +  else
>>> +    {
>>> +      cpp_assert (pfile, "cpu=i386");
>>> +      cpp_assert (pfile, "machine=i386");
>>> +      gfc_builtin_define_std (pfile, "i386", false);
>>> +      cpp_define (pfile, "_ILP32");
>>> +      cpp_define (pfile, "__ILP32__");
>>> +    }
>>> +
>>> +  if (!TARGET_80387)
>>> +    cpp_define (pfile, "_SOFT_FLOAT");
>>> +
>>> +  if (TARGET_LONG_DOUBLE_64)
>>> +    cpp_define (pfile, "__LONG_DOUBLE_64__");
>>> +
>>> +  if (TARGET_LONG_DOUBLE_128)
>>> +    cpp_define (pfile, "__LONG_DOUBLE_128__");
>>> +
>>> +  cpp_define_formatted (pfile, "__SIZEOF_FLOAT80__=%d",
>>> +                       GET_MODE_SIZE (XFmode));
>>> +  cpp_define (pfile, "__SIZEOF_FLOAT128__=16");
>>> +}
>>> +#endif
>>> +
>>> +/* Provide essential Darwin platform macros for the Fortran preprocessor.
>>> +   The full darwin_cpp_builtins() in darwin-c.cc also defines
>>> +   __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ and
>>> +   __CONSTANT_CFSTRINGS__, but those depend on functions only linked
>>> +   into C-family frontends.  */
>>> +
>>> +static void ATTRIBUTE_UNUSED
>>> +gfc_darwin_cpp_builtins (cpp_reader *pfile)
>>> +{
>>> +  cpp_define (pfile, "__MACH__");
>>> +  cpp_define (pfile, "__APPLE__");
>>> +  gfc_builtin_define_with_value (pfile, "__APPLE_CC__", "1", false);
>>> +}
>>>
>>>   static void
>>>   cpp_define_builtins (cpp_reader *pfile)
>>> @@ -177,33 +297,55 @@ cpp_define_builtins (cpp_reader *pfile)
>>>     if (flag_openmp)
>>>       cpp_define (pfile, "_OPENMP=202111");
>>>
>>> -  /* The defines below are necessary for the TARGET_* macros.
>>> -
>>> -     FIXME:  Note that builtin_define_std() actually is a function
>>> -     in c-cppbuiltin.cc which uses flags undefined for Fortran.
>>> -     Let's skip this for now. If needed, one needs to look into it
>>> -     once more.  */
>>> +  /* Wrapper macros for C-family identifiers used in target config
>>> +     headers.  These allow TARGET_OS_CPP_BUILTINS and
>>> +     TARGET_OBJFMT_CPP_BUILTINS to compile in the Fortran frontend.  */
>>>
>>>   # define builtin_define(TXT) cpp_define (pfile, TXT)
>>> -# define builtin_define_std(TXT)
>>> +# define builtin_define_std(TXT) gfc_builtin_define_std (pfile, TXT, 
>>> !flag_iso)
>>> +# define builtin_define_with_value(MACRO, EXPANSION, IS_STR) \
>>> +  gfc_builtin_define_with_value (pfile, MACRO, EXPANSION, IS_STR)
>>> +# define builtin_define_with_int_value(MACRO, VALUE) \
>>> +  cpp_define_formatted (pfile, "%s=" HOST_WIDE_INT_PRINT_DEC, \
>>> +                       MACRO, (HOST_WIDE_INT) (VALUE))
>>>   # define builtin_assert(TXT) cpp_assert (pfile, TXT)
>>> +# define c_dialect_cxx() 0
>>> +# define c_dialect_objc() 0
>>> +# define preprocessing_asm_p() 0
>>> +# define preprocessing_trad_p() 0
>>> +  /* Fortran has no -std=cNN flag to control this.  Set to 1 (ISO mode)
>>> +     so that builtin_define_std() only defines reserved-namespace macros
>>> +     like __unix__ and __linux__, not bare "unix" or "linux" which are
>>> +     valid Fortran identifiers and would cause silent replacement.  */
>>> +# define flag_iso 1
>>> +# define flag_isoc94 0
>>> +# define flag_isoc99 0
>>> +# define flag_isoc11 0
>>> +# define flag_isoc23 0
>>> +# define darwin_cpp_builtins(PFILE) gfc_darwin_cpp_builtins (PFILE)
>>>
>>> -  /* FIXME: Pandora's Box
>>> -    Using the macros below results in multiple breakages:
>>> -     - mingw will fail to compile this file as dependent macros
>>> -       assume to be used in c-cppbuiltin.cc only. Further, they use
>>> -       flags only valid/defined in C (same as noted above).
>>> -       [config/i386/mingw32.h, config/i386/cygming.h]
>>> -     - other platforms (not as popular) break similarly
>>> -       [grep for 'builtin_define_with_int_value' in gcc/config/]
>>> -
>>> -  TARGET_CPU_CPP_BUILTINS ();
>>>     TARGET_OS_CPP_BUILTINS ();
>>> -  TARGET_OBJFMT_CPP_BUILTINS (); */
>>> +  TARGET_OBJFMT_CPP_BUILTINS ();
>>> +
>>> +#ifdef TARGET_80387
>>> +  gfc_define_ix86_target_macros (pfile);
>>> +#endif
>>>
>>>   #undef builtin_define
>>>   #undef builtin_define_std
>>> +#undef builtin_define_with_value
>>> +#undef builtin_define_with_int_value
>>>   #undef builtin_assert
>>> +#undef c_dialect_cxx
>>> +#undef c_dialect_objc
>>> +#undef preprocessing_asm_p
>>> +#undef preprocessing_trad_p
>>> +#undef flag_iso
>>> +#undef flag_isoc94
>>> +#undef flag_isoc99
>>> +#undef flag_isoc11
>>> +#undef flag_isoc23
>>> +#undef darwin_cpp_builtins
>>>   }
>>>
>>>   bool
>>> diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-variant-10.f90 
>>> b/gcc/testsuite/gfortran.dg/gomp/declare-variant-10.f90
>>> index 0e0ab518010..115195e1194 100644
>>> --- a/gcc/testsuite/gfortran.dg/gomp/declare-variant-10.f90
>>> +++ b/gcc/testsuite/gfortran.dg/gomp/declare-variant-10.f90
>>> @@ -64,9 +64,6 @@ contains
>>>       call f18 ()          ! { dg-final { scan-tree-dump-times "f18 
>>> \\\(\\\);" 1 "gimple" } } */
>>>     end subroutine
>>>
>>> -#if defined(__i386__) || defined(__x86_64__)
>>> -  __attribute__((target ("avx512f,avx512bw")))
>>> -#endif
>>>     subroutine test2 ()
>>>       !$omp target
>>>         call f04 () ! { dg-final { scan-tree-dump-times "f03 \\\(\\\);" 1 
>>> "gimple" { target { { i?86-*-* x86_64-*-* } && { ! ilp32 } } } } }
>>> diff --git a/gcc/testsuite/gfortran.dg/pr42954-linux.f90 
>>> b/gcc/testsuite/gfortran.dg/pr42954-linux.f90
>>> new file mode 100644
>>> index 00000000000..bd5efe7a237
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gfortran.dg/pr42954-linux.f90
>>> @@ -0,0 +1,24 @@
>>> +! { dg-do preprocess { target *-*-linux* } }
>>> +! { dg-options "-cpp" }
>>> +!
>>> +! PR fortran/42954 - target macros missing in gfortran -cpp
>>> +
>>> +#ifndef __linux__
>>> +# error __linux__ not defined
>>> +#endif
>>> +
>>> +#ifndef __linux
>>> +# error __linux not defined
>>> +#endif
>>> +
>>> +#ifndef __unix__
>>> +# error __unix__ not defined
>>> +#endif
>>> +
>>> +#ifndef __unix
>>> +# error __unix not defined
>>> +#endif
>>> +
>>> +#ifndef __ELF__
>>> +# error __ELF__ not defined
>>> +#endif
>>> diff --git a/gcc/testsuite/gfortran.dg/pr42954-x86.f90 
>>> b/gcc/testsuite/gfortran.dg/pr42954-x86.f90
>>> new file mode 100644
>>> index 00000000000..0a3b7eac8a2
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gfortran.dg/pr42954-x86.f90
>>> @@ -0,0 +1,10 @@
>>> +! { dg-do preprocess { target { i?86-*-* x86_64-*-* } } }
>>> +! { dg-options "-cpp" }
>>> +!
>>> +! PR fortran/42954 - target macros missing in gfortran -cpp
>>> +
>>> +#if !defined(__i386__) && !defined(__i386) \
>>> +    && !defined(__x86_64__) && !defined(__x86_64) \
>>> +    && !defined(__amd64__) && !defined(__amd64)
>>> +# error x86 target macros not defined
>>> +#endif
>>> --
>>> 2.53.0
>>>
>>

Dear Andrea,

thanks for checking this.

I tried to keep the first version inside the Fortran frontend and overlooked 
the D/Rust frontend pattern you pointed out. I attached a smaller patch that 
adds a Fortran target hook and keeps the target-specific macro definitions in 
target config files.

Could you check whether this structure looks right? If yes, I can extend it 
toward the fuller scope Harald asked for in the Bugzilla thread.

Thanks,
Chris

Attachment: 0001-fortran-add-target-hook-for-Fortran-preprocessor-mac.patch
Description: 0001-fortran-add-target-hook-for-Fortran-preprocessor-mac.patch

Reply via email to