stdint: Use __extension__ on long long constants

Message ID 20200225072320.Horde.P83S0y7VfCmyChcsW8RVUF4@ssl.uofr.net
State Rejected
Headers

Commit Message

Dennis Lambe Jr. Feb. 25, 2020, 7:23 a.m. UTC
  Most uses of long long in stdint.h are guarded with __extension__ to  
prevent them from issuing warnings with -std=c89 -pedantic. However,  
on 32-bit platforms the 64-bit integer constant macros append LL or  
ULL without marking it as an __extension__.

As a result, GCC issues this warning:

     $ gcc -m32 -std=c89 -pedantic -c -o stdintext.o stdintext.c
     In file included from stdint.h:9:0,
                      from stdintext.c:1:
     stdintext.c:3:23: warning: use of C99 long long integer constant  
[-Wlong-long]
      uint64_t i = UINT64_C(0);

Prefix all ## LL and ## ULL macros with __extension__ to suppress  
these warnings.
---
  stdlib/stdint.h | 12 ++++++------
  1 file changed, 6 insertions(+), 6 deletions(-)
  

Comments

Florian Weimer Feb. 25, 2020, 7:57 a.m. UTC | #1
* Dennis Lambe, Jr.:

> Most uses of long long in stdint.h are guarded with __extension__ to
> prevent them from issuing warnings with -std=c89 -pedantic. However,
> on 32-bit platforms the 64-bit integer constant macros append LL or
> ULL without marking it as an __extension__.
>
> As a result, GCC issues this warning:
>
>     $ gcc -m32 -std=c89 -pedantic -c -o stdintext.o stdintext.c
>     In file included from stdint.h:9:0,
>                      from stdintext.c:1:
>     stdintext.c:3:23: warning: use of C99 long long integer constant
> [-Wlong-long]
>      uint64_t i = UINT64_C(0);
>
> Prefix all ## LL and ## ULL macros with __extension__ to suppress
> these warnings.

I think users who use <stdint.h> in C89 mode expect such warnings
because such usages cannot be made compatible with C89 compilers
without long long support.

Thanks,
Florian
  
Andreas Schwab Feb. 25, 2020, 9:19 a.m. UTC | #2
On Feb 25 2020, Dennis Lambe Jr. wrote:

> diff --git a/stdlib/stdint.h b/stdlib/stdint.h
> index 2df07e485b..9fa45672db 100644
> --- a/stdlib/stdint.h
> +++ b/stdlib/stdint.h
> @@ -106,8 +106,8 @@ typedef __uintmax_t         uintmax_t;
>  #  define __INT64_C(c) c ## L
>  #  define __UINT64_C(c)        c ## UL
>  # else
> -#  define __INT64_C(c) c ## LL
> -#  define __UINT64_C(c)        c ## ULL
> +#  define __INT64_C(c) (__extension__ c ## LL)
> +#  define __UINT64_C(c)        (__extension__ c ## ULL)

The expansion must be a preprocessor expression.

Andreas.
  
Dennis Lambe Jr. Feb. 25, 2020, 2:15 p.m. UTC | #3
Quoting Florian Weimer <fweimer@redhat.com>:

> I think users who use <stdint.h> in C89 mode expect such warnings
> because such usages cannot be made compatible with C89 compilers
> without long long support.

Existing practice suggests differently. Every usage of 'long long' in  
the headers under stdlib/ is preceded by an __extention__ keyword to  
suppress those warnings. This was the only instance I could find of a  
stdlib header not suppressing that warning.
  
Florian Weimer Feb. 25, 2020, 2:17 p.m. UTC | #4
* Dennis Lambe, Jr.:

> Quoting Florian Weimer <fweimer@redhat.com>:
>
>> I think users who use <stdint.h> in C89 mode expect such warnings
>> because such usages cannot be made compatible with C89 compilers
>> without long long support.
>
> Existing practice suggests differently. Every usage of 'long long' in
> the headers under stdlib/ is preceded by an __extention__ keyword to
> suppress those warnings. This was the only instance I could find of a
> stdlib header not suppressing that warning.

None of those are in macros.  These macros are special in the sense that
they require the long long extension only on 32-bit targets.

Thanks,
Florian
  
Dennis Lambe Jr. Feb. 25, 2020, 2:27 p.m. UTC | #5
Quoting Florian Weimer <fweimer@redhat.com>:

>> Quoting Florian Weimer <fweimer@redhat.com>:
>>
>>> I think users who use <stdint.h> in C89 mode expect such warnings
>>> because such usages cannot be made compatible with C89 compilers
>>> without long long support.
>>
>> Existing practice suggests differently. Every usage of 'long long' in
>> the headers under stdlib/ is preceded by an __extention__ keyword to
>> suppress those warnings. This was the only instance I could find of a
>> stdlib header not suppressing that warning.
>
> None of those are in macros.  These macros are special in the sense that
> they require the long long extension only on 32-bit targets.

I see your point here. However, the use of __extension__ before the  
typedefs for int64 types means that you can get away with a lot of  
implicit long long usage via int64 without running into a warning,  
though. So if the user expects that, their expectation is only being  
met inconsistently: they only get a warning if they use the macros,  
not if they use only the typedefs. (this is exactly how I ran into  
this).

Technically we're way outside the standard anyway -- there's no reason  
to expect stdint.h to exist at all on c89 and any code running with  
-pedantic -std=c89 and including stdint.h could be called quirky. I  
just thought it'd be nice to standardize on either "warn" or "don't  
warn" rather than a mix of the two.
  
Dennis Lambe Jr. Feb. 25, 2020, 2:28 p.m. UTC | #6
Quoting Andreas Schwab <schwab@suse.de>:

> On Feb 25 2020, Dennis Lambe Jr. wrote:
>> +#  define __UINT64_C(c)        (__extension__ c ## ULL)
>
> The expansion must be a preprocessor expression.

Oof, yeah, I see what you mean. GCC recognizes the __extension__  
keyword at compile-time, but GCC's preprocessor doesn't recognize it  
and throws an error. This seems like a bug in GCC to me, and I don't  
know how to work around it to accomplish what I'm trying to do with  
this patch. Withdrawn until I can figure it out, unless someone else  
has an idea.

Thanks for taking the time to consider it
  
Andreas Schwab Feb. 25, 2020, 2:37 p.m. UTC | #7
On Feb 25 2020, Dennis Lambe Jr. wrote:

> Existing practice suggests differently. Every usage of 'long long' in  the
> headers under stdlib/ is preceded by an __extention__ keyword to  suppress
> those warnings. This was the only instance I could find of a  stdlib
> header not suppressing that warning.

C89 doesn't have <stdint.h>, so the warning reminds you that you are
doing something invalid.

Andreas.
  
Florian Weimer Feb. 25, 2020, 3:06 p.m. UTC | #8
* Dennis Lambe, Jr.:

> Quoting Andreas Schwab <schwab@suse.de>:
>
>> On Feb 25 2020, Dennis Lambe Jr. wrote:
>>> +#  define __UINT64_C(c)        (__extension__ c ## ULL)
>>
>> The expansion must be a preprocessor expression.
>
> Oof, yeah, I see what you mean. GCC recognizes the __extension__
> keyword at compile-time, but GCC's preprocessor doesn't recognize it
> and throws an error. This seems like a bug in GCC to me, and I don't
> know how to work around it to accomplish what I'm trying to do with
> this patch. Withdrawn until I can figure it out, unless someone else
> has an idea.

The usual trick is to write (__extension__ + c ## ULL), but this
produces a -Wundef warning even in !C89 modes, so I think we'd be off
worse with that.

Thanks,
Florian
  

Patch

diff --git a/stdlib/stdint.h b/stdlib/stdint.h
index 2df07e485b..9fa45672db 100644
--- a/stdlib/stdint.h
+++ b/stdlib/stdint.h
@@ -106,8 +106,8 @@  typedef __uintmax_t         uintmax_t;
  #  define __INT64_C(c) c ## L
  #  define __UINT64_C(c)        c ## UL
  # else
-#  define __INT64_C(c) c ## LL
-#  define __UINT64_C(c)        c ## ULL
+#  define __INT64_C(c) (__extension__ c ## LL)
+#  define __UINT64_C(c)        (__extension__ c ## ULL)
  # endif

  /* Limits of integral types.  */
@@ -251,7 +251,7 @@  typedef __uintmax_t         uintmax_t;
  # if __WORDSIZE == 64
  #  define INT64_C(c)   c ## L
  # else
-#  define INT64_C(c)   c ## LL
+#  define INT64_C(c)   (__extension__ c ## LL)
  # endif

  /* Unsigned.  */
@@ -261,7 +261,7 @@  typedef __uintmax_t         uintmax_t;
  # if __WORDSIZE == 64
  #  define UINT64_C(c)  c ## UL
  # else
-#  define UINT64_C(c)  c ## ULL
+#  define UINT64_C(c)  (__extension__ c ## ULL)
  # endif

  /* Maximal type.  */
@@ -269,8 +269,8 @@  typedef __uintmax_t         uintmax_t;
  #  define INTMAX_C(c)  c ## L
  #  define UINTMAX_C(c) c ## UL
  # else
-#  define INTMAX_C(c)  c ## LL
-#  define UINTMAX_C(c) c ## ULL
+#  define INTMAX_C(c)  (__extension__ c ## LL)
+#  define UINTMAX_C(c) (__extension__ c ## ULL)
  # endif

  #if __GLIBC_USE (IEC_60559_BFP_EXT_C2X)