Re: git: 43703bc489ec - main - stdlib.h: Fix qsort_r compatibility with GCC 12.
Date: Thu, 19 Jan 2023 23:36:05 UTC
On 19 Jan 2023, at 23:31, Jessica Clarke <jrtc27@FreeBSD.org> wrote: > > On 19 Jan 2023, at 23:11, Jessica Clarke <jrtc27@FreeBSD.org> wrote: >> >> On 19 Jan 2023, at 22:49, John Baldwin <jhb@FreeBSD.org> wrote: >>> >>> The branch main has been updated by jhb: >>> >>> URL: https://cgit.FreeBSD.org/src/commit/?id=43703bc489ec504b947b869045c492ed38c1a69c >>> >>> commit 43703bc489ec504b947b869045c492ed38c1a69c >>> Author: John Baldwin <jhb@FreeBSD.org> >>> AuthorDate: 2023-01-19 22:48:52 +0000 >>> Commit: John Baldwin <jhb@FreeBSD.org> >>> CommitDate: 2023-01-19 22:48:52 +0000 >>> >>> stdlib.h: Fix qsort_r compatibility with GCC 12. >>> >>> GCC 12 (unlike GCC 9) does not match a function argument passed to the >>> old qsort_r() API (as is used in the qsort_r_compat test) to a >>> function pointer type via __generic. It treats the function type as a >>> distinct type from a function pointer. As a workaround, add a second >>> definition of qsort_r for GCC 12 which uses the bare function type. >> >> As far as I can tell both versions of GCC behave the same. The >> difference is whether __generic is using _Generic or >> __builtin_choose_expr with __builtin_types_compatible_p, since function >> and function pointer types are not compatible. Clang will take the >> __has_extension path, but GCC will take the builtins path, and so Clang >> works but GCC doesn’t. >> >> As a result of this change you’ve likely broken code that does >> qsort_r(..., &f) as that will have the opposite problem. The right fix >> is to force arg5 to decay, such as by (ab)using the comma operator with >> __generic((0, arg5), ...). I guess that probably belongs in the >> fallback implementation of __generic though, not here, which would give >> the following real fix: >> >> diff --git a/sys/sys/cdefs.h b/sys/sys/cdefs.h >> index 83ba7584e5b9..f7eff4768151 100644 >> --- a/sys/sys/cdefs.h >> +++ b/sys/sys/cdefs.h >> @@ -312,6 +312,9 @@ >> * __generic(). Unlike _Generic(), this macro can only distinguish >> * between a single type, so it requires nested invocations to >> * distinguish multiple cases. >> + * >> + * Note that the comma operator is used to force expr to decay in order to >> + * match _Generic. >> */ >> >> #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \ >> @@ -321,7 +324,7 @@ >> #elif __GNUC_PREREQ__(3, 1) && !defined(__cplusplus) >> #define __generic(expr, t, yes, no) \ >> __builtin_choose_expr( \ >> - __builtin_types_compatible_p(__typeof(expr), t), yes, no) >> + __builtin_types_compatible_p(__typeof((0, expr)), t), yes, no) > > With (expr) instead of expr, of course... And as for why GCC 9 works: It doesn’t. The tests just aren’t built because MK_CXX=no disables MK_TESTS. GCC 12 only hits it because it’s new enough to be able to build libc++ and not force MK_CXX=no. It would be nice to unpick that... Jess > Jess > >> #endif >> >> /* >> >> Does that work instead for you after reverting this commit? >> >> Jess >> >>> Reviewed by: emaste >>> Differential Revision: https://reviews.freebsd.org/D37410 >>> --- >>> include/stdlib.h | 6 ++++++ >>> 1 file changed, 6 insertions(+) >>> >>> diff --git a/include/stdlib.h b/include/stdlib.h >>> index 754e8f5f5fd4..30d24aea1c10 100644 >>> --- a/include/stdlib.h >>> +++ b/include/stdlib.h >>> @@ -352,9 +352,15 @@ void __qsort_r_compat(void *, size_t, size_t, void *, >>> __sym_compat(qsort_r, __qsort_r_compat, FBSD_1.0); >>> #endif >>> #if defined(__generic) && !defined(__cplusplus) >>> +#if __GNUC__ == 12 >>> +#define qsort_r(base, nel, width, arg4, arg5) \ >>> + __generic(arg5, int (void *, const void *, const void *), \ >>> + __qsort_r_compat, qsort_r)(base, nel, width, arg4, arg5) >>> +#else >>> #define qsort_r(base, nel, width, arg4, arg5) \ >>> __generic(arg5, int (*)(void *, const void *, const void *), \ >>> __qsort_r_compat, qsort_r)(base, nel, width, arg4, arg5) >>> +#endif >>> #elif defined(__cplusplus) >>> __END_DECLS >>> extern "C++" {