From patchwork Tue Nov 18 21:27:47 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Myers X-Patchwork-Id: 124676 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 47F6338515E9 for ; Tue, 18 Nov 2025 21:33:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 47F6338515E9 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=IhNmdn2U X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id B8864385AC1C for ; Tue, 18 Nov 2025 21:27:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B8864385AC1C Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org B8864385AC1C Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1763501274; cv=none; b=kIfzyw+oV157PPAe0DyIGlrJ2ZFAjIfa+5fynVe1qSTQ9ImZpkW24xwH8gIXFsiNBQmjLrrSgcNxBjSSZBp6piGSXZdH9r/e8ub2osDuVzVn4nxOlr6855oJYMWzJndLMH906aS5GPf+onYomZw27eVoCITaFvd4UXF2O0My7W0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1763501274; c=relaxed/simple; bh=KHFs9pZKjwiLyyjJwWDLbgqi6tMKzdyfaKrTOKx8D6M=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=Rfzmwut8GovcjiM+LGEf613heDqJGrrEp++yIxEH2zlIuUOoyw3FWudY+HAroIv9+66EIQ6s3O6t3rI09FNjjgAM1iBXgTopcfNK7Cz7d1Ws/wMpZam3YKMs4eixq9H6iK6D09YR5C5yLYyogVBlMXnxU13pDTTnU7nA0cvrl5c= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B8864385AC1C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1763501274; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=cJcAulI1GMzb3Cv10piWrJHjISGHd32MoKQqzbO396M=; b=IhNmdn2U0QYZyXqo9V9ECv7aAV0BMqDsU5Wg66IfhQaLQbbnP2eMNrsPpBvxcHplryBPk9 UaWkaUfg/YtysUxydzNLANNCbIWkxZgN9x0NQrxP7Yz3XBhb67QtcEF0Hcp4+wyh8qB14t ij2Gy+dgpG7ypRiAhAvwF5BVB3K3O9M= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-161-4IEbOYvbPmC45MJha1LOOQ-1; Tue, 18 Nov 2025 16:27:52 -0500 X-MC-Unique: 4IEbOYvbPmC45MJha1LOOQ-1 X-Mimecast-MFC-AGG-ID: 4IEbOYvbPmC45MJha1LOOQ_1763501272 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-477563e531cso54075185e9.1 for ; Tue, 18 Nov 2025 13:27:52 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763501271; x=1764106071; h=mime-version:message-id:subject:to:from:date:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=cJcAulI1GMzb3Cv10piWrJHjISGHd32MoKQqzbO396M=; b=b9V56OUACHQtJctvW2LTEhr2uuG8mAyrTML/CImnunNZYMYvkqqlbGHxdUuc8EJ8aE ZDf1JxwwjAQfH8A/0s2s4nwda4OsiQYMweGsue9n4pQowrobBYNIwGGV/P5thfsIGAMp BIK0Qg/jotg7BoFHYtFn9RydaxSYtTcv8f2zifFfOuHrT+ts0oD32w4yoCbQQPskb+4i abQ8isBIIv0mq1Icb95r+l3j5skHibs1AS4LhV8Etm5JmuujmV993fkBqJ5Q8/ihSBUA 66BC3rw+HILHK/0lfuLdC8y5skgN009GVR/DtRXVCgpe6RlgdnklrJIY9fELGWsSqgYl 1/HQ== X-Gm-Message-State: AOJu0Yy4e6vCJCQUOuFvDkcXQk+RcIjdn43iyRpt8246Yp0LOrGGUbLO uBK3DrFiEDKFL+kv8Nc4PHOoJmNmXK9mcerE0sr1pNV0bvyxTvpnyft0zgoY6hof82qlrHgC1ab Mm7E5P3sWxXj7tI+gZ+hO3IsRhjKj0HdFl+AYW/RZB+M6fEoxQXDTTpfw4QBlQo0ofJJLR+8PzS /wf8ouUpXa3vSs1ID16H6i4Qy1STF3sNv4OPQuk9IAKtV2Kw== X-Gm-Gg: ASbGncvL0AtfxFypMXbrbJLFEbhsNpXzGl55ZSgjngksDcQ58RPN3epKe1CeBYBMfN8 KjcPTtOpbwNmVSaGI2/HFxzyGgb5xDgF0Z+t6T0u61FCOCUmVbN+C+vmHwBc3z3Ee/ZaCfXKcmo 2/Tf7IaJw2DM5croMiNSKQlGWQMMCftRgDVeWKcII+Xnp8lqRU/efxP3bB/7995gBcdf3DTFqw2 1xQo3OnftG9sY2LwTIILCwX4DW0nMTQ9jGUu77B619Ovv8lNCZFZp8EFiXwkl2wUnAXhC9u8g67 Tpp78MX/iK0xoA/1gyyi8Y21io4/inneryrJjjD1Rd8v7hdYguDKqRxScvc6AwJRj6mgVmLNnEG 8zUZth69YAYYNQu7nesMzm40sdmZnwq7FATAxoFZ6 X-Received: by 2002:a05:600c:1387:b0:45b:47e1:ef6d with SMTP id 5b1f17b1804b1-4778feb2507mr166761655e9.36.1763501271113; Tue, 18 Nov 2025 13:27:51 -0800 (PST) X-Google-Smtp-Source: AGHT+IHng0GZ4xCWg1FPD4lKJqLTkGaMIW0DuyavGaTY092AXKe61EqZercWmeo9z+Ty+FU9pL7XYw== X-Received: by 2002:a05:600c:1387:b0:45b:47e1:ef6d with SMTP id 5b1f17b1804b1-4778feb2507mr166761385e9.36.1763501270323; Tue, 18 Nov 2025 13:27:50 -0800 (PST) Received: from digraph.polyomino.org.uk (digraph.polyomino.org.uk. [2001:8b0:bf73:93f7::51bb:e332]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-42ca01b074csm13580546f8f.34.2025.11.18.13.27.49 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Nov 2025 13:27:49 -0800 (PST) Received: from jsm28 (helo=localhost) by digraph.polyomino.org.uk with local-esmtp (Exim 4.97) (envelope-from ) id 1vLTEp-000000013Kh-3gHY for libc-alpha@sourceware.org; Tue, 18 Nov 2025 21:27:47 +0000 Date: Tue, 18 Nov 2025 21:27:47 +0000 (UTC) From: Joseph Myers To: libc-alpha@sourceware.org Subject: Implement C23 const-preserving standard library macros Message-ID: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: VDInjnKoatiMWfP-W3owVvlnZtHjenk1Ddl-sIp82Ak_1763501272 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org C23 makes various standard library functions, that return a pointer into an input array, into macros that return a pointer to const when the relevant argument passed to the macro is a pointer to const. (The requirement is for macros, with the existing function types applying when macro expansion is suppressed. When a null pointer constant is passed, such as integer 0, that's the same as a pointer to non-const.) Implement this feature. This only applies to C, not C++, since such macros are not an appropriate way of doing this for C++ and all the affected functions other than bsearch have overloads to implement an equivalent feature for C++ anyway. Nothing is done to apply such a change to any non-C23 functions with the same property of returning a pointer into an input array. The feature is also disabled when _LIBC is defined, since there are various places in glibc that either redefine these identifiers as macros, or define the functions themselves, and would need changing to work in the presence of these macro definitions. A natural question is whether we should in fact change those places and not disable the macro definitions for _LIBC. If so, we'd need a solution for the places in glibc that define the macro *before* including the relevant header (in order in effect to disable the header declaration of the function by renaming that declaration). One testcase has #undef added to avoid conflicting with this feature and another has const added; -Wno-discarded-qualifiers is added for building zic (but could be removed once there's a new upstream tzcode release that's const-safe with this C23 change and glibc has updated to code from that new release). Probably other places in glibc proper would need const added if we remove the _LIBC conditionals. Another question would be whether some GCC extension should be added to support this feature better with macros that only expand each argument once. Tested for x86_64. diff --git a/NEWS b/NEWS index a2618545d5..ced41e71d2 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,12 @@ Major new features: arguments to support expressions with a comma inside a compound literal initializer not surrounded by parentheses. +* For ISO C23, the functions bsearch, memchr, strchr, strpbrk, strrchr, + strstr, wcschr, wcspbrk, wcsrchr, wcsstr and wmemchr that return + pointers into their input arrays now have definitions as macros that + return a pointer to a const-qualified type when the input argument is + a pointer to a const-qualified type. + * The C23 typedef names long_double_t, _Float32_t, _Float64_t, and (on platforms supporting _Float128) _Float128_t, introduced in TS 18661-3:2015, have been added to . diff --git a/debug/tst-backtrace.h b/debug/tst-backtrace.h index e1c0a82777..a48ac0f4a8 100644 --- a/debug/tst-backtrace.h +++ b/debug/tst-backtrace.h @@ -43,6 +43,6 @@ volatile int x; static inline bool match (const char *sym, const char *name) { - char *p = strchr (sym, '('); + const char *p = strchr (sym, '('); return p != NULL && strstr (p, name) != NULL; } diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h index 3e874282df..32fcdb7c82 100644 --- a/misc/sys/cdefs.h +++ b/misc/sys/cdefs.h @@ -828,6 +828,18 @@ _Static_assert (0, "IEEE 128-bits long double requires redirection on this platf # define __HAVE_GENERIC_SELECTION 0 #endif +#if __HAVE_GENERIC_SELECTION +/* If PTR is a pointer to const, return CALL cast to type CTYPE, + otherwise return CALL. Pointers to types with non-const qualifiers + are not valid. This should not be defined for C++, as macros are + not an appropriate way of implementing such qualifier-generic + operations for C++. */ +# define __glibc_const_generic(PTR, CTYPE, CALL) \ + _Generic (0 ? (PTR) : (void *) 1, \ + const void *: (CTYPE) (CALL), \ + void *: (CALL)) +#endif + #if __GNUC_PREREQ (10, 0) /* Designates a 1-based positional argument ref-index of pointer type that can be used to access size-index elements of the pointed-to diff --git a/stdlib/Makefile b/stdlib/Makefile index 176a79572b..545211dfbf 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -280,6 +280,7 @@ tests := \ tst-canon-bz26341 \ tst-concurrent-exit \ tst-concurrent-quick_exit \ + tst-const \ tst-cxa_atexit \ tst-environ \ tst-environ-change-1 \ diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h index 8416bd4446..a770420053 100644 --- a/stdlib/stdlib.h +++ b/stdlib/stdlib.h @@ -965,6 +965,12 @@ extern void *bsearch (const void *__key, const void *__base, # include #endif +#if __GLIBC_USE (ISOC23) && defined __glibc_const_generic && !defined _LIBC +# define bsearch(KEY, BASE, NMEMB, SIZE, COMPAR) \ + __glibc_const_generic (BASE, const void *, \ + bsearch (KEY, BASE, NMEMB, SIZE, COMPAR)) +#endif + /* Sort NMEMB elements of BASE, of SIZE bytes each, using COMPAR to perform the comparisons. */ extern void qsort (void *__base, size_t __nmemb, size_t __size, diff --git a/stdlib/tst-const.c b/stdlib/tst-const.c new file mode 100644 index 0000000000..4064f41399 --- /dev/null +++ b/stdlib/tst-const.c @@ -0,0 +1,54 @@ +/* Test bsearch const-generic macro. + Copyright (C) 2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +void *vp; +const void *cvp; +int *ip; +const int *cip; +size_t sz; +int (*compar) (const void *, const void *); + +#define CHECK_TYPE(EXPR, TYPE) \ + _Static_assert (_Generic (EXPR, TYPE: 1), "type check") + +static int +do_test (void) +{ + /* This is a compilation test. */ + CHECK_TYPE (bsearch (cvp, cvp, sz, sz, compar), const void *); + CHECK_TYPE (bsearch (cvp, vp, sz, sz, compar), void *); + CHECK_TYPE (bsearch (vp, cvp, sz, sz, compar), const void *); + CHECK_TYPE (bsearch (vp, vp, sz, sz, compar), void *); + CHECK_TYPE (bsearch (cvp, cip, sz, sz, compar), const void *); + CHECK_TYPE (bsearch (cvp, ip, sz, sz, compar), void *); + CHECK_TYPE (bsearch (vp, cip, sz, sz, compar), const void *); + CHECK_TYPE (bsearch (vp, ip, sz, sz, compar), void *); + DIAG_PUSH_NEEDS_COMMENT; + /* This deliberately tests the type of the result with a null + pointer constant argument. */ + DIAG_IGNORE_NEEDS_COMMENT (14, "-Wnonnull"); + CHECK_TYPE (bsearch (cvp, 0, sz, sz, compar), void *); + CHECK_TYPE (bsearch (cvp, (void *) 0, sz, sz, compar), void *); + DIAG_POP_NEEDS_COMMENT; + return 0; +} + +#include diff --git a/string/Makefile b/string/Makefile index d842ae0457..ffa6590b3e 100644 --- a/string/Makefile +++ b/string/Makefile @@ -196,6 +196,7 @@ tests := \ tester \ tst-bswap \ tst-cmp \ + tst-const \ tst-endian \ tst-inlcall \ tst-memmove-overflow \ diff --git a/string/string.h b/string/string.h index 81f0b7fd21..1dc5995c17 100644 --- a/string/string.h +++ b/string/string.h @@ -113,6 +113,10 @@ memchr (const void *__s, int __c, size_t __n) __THROW #else extern void *memchr (const void *__s, int __c, size_t __n) __THROW __attribute_pure__ __nonnull ((1)); +# if __GLIBC_USE (ISOC23) && defined __glibc_const_generic && !defined _LIBC +# define memchr(S, C, N) \ + __glibc_const_generic (S, const void *, memchr (S, C, N)) +# endif #endif #ifdef __USE_GNU @@ -252,6 +256,10 @@ strchr (const char *__s, int __c) __THROW #else extern char *strchr (const char *__s, int __c) __THROW __attribute_pure__ __nonnull ((1)); +# if __GLIBC_USE (ISOC23) && defined __glibc_const_generic && !defined _LIBC +# define strchr(S, C) \ + __glibc_const_generic (S, const char *, strchr (S, C)) +# endif #endif /* Find the last occurrence of C in S. */ #ifdef __CORRECT_ISO_CPP_STRING_H_PROTO @@ -279,6 +287,10 @@ strrchr (const char *__s, int __c) __THROW #else extern char *strrchr (const char *__s, int __c) __THROW __attribute_pure__ __nonnull ((1)); +# if __GLIBC_USE (ISOC23) && defined __glibc_const_generic && !defined _LIBC +# define strrchr(S, C) \ + __glibc_const_generic (S, const char *, strrchr (S, C)) +# endif #endif #ifdef __USE_MISC @@ -329,6 +341,10 @@ strpbrk (const char *__s, const char *__accept) __THROW #else extern char *strpbrk (const char *__s, const char *__accept) __THROW __attribute_pure__ __nonnull ((1, 2)); +# if __GLIBC_USE (ISOC23) && defined __glibc_const_generic && !defined _LIBC +# define strpbrk(S, ACCEPT) \ + __glibc_const_generic (S, const char *, strpbrk (S, ACCEPT)) +# endif #endif /* Find the first occurrence of NEEDLE in HAYSTACK. */ #ifdef __CORRECT_ISO_CPP_STRING_H_PROTO @@ -356,6 +372,11 @@ strstr (const char *__haystack, const char *__needle) __THROW #else extern char *strstr (const char *__haystack, const char *__needle) __THROW __attribute_pure__ __nonnull ((1, 2)); +# if __GLIBC_USE (ISOC23) && defined __glibc_const_generic && !defined _LIBC +# define strstr(HAYSTACK, NEEDLE) \ + __glibc_const_generic (HAYSTACK, const char *, \ + strstr (HAYSTACK, NEEDLE)) +# endif #endif diff --git a/string/test-strnlen.c b/string/test-strnlen.c index acb1c055fc..7b5ceaf941 100644 --- a/string/test-strnlen.c +++ b/string/test-strnlen.c @@ -63,6 +63,7 @@ IMPL (__strnlen_default, 1) # define libc_hidden_weak(a) # include "wcsmbs/wmemchr.c" # define WCSNLEN __wcsnlen_default +# undef wmemchr # define wmemchr __wmemchr_default # include "wcsmbs/wcsnlen.c" IMPL (__wcsnlen_default, 1) diff --git a/string/tst-const.c b/string/tst-const.c new file mode 100644 index 0000000000..eeb603b7b2 --- /dev/null +++ b/string/tst-const.c @@ -0,0 +1,102 @@ +/* Test const-generic macros. + Copyright (C) 2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +void *vp; +const void *cvp; +int *ip; +const int *cip; +char *cp; +const char *ccp; +int c; +size_t sz; + +#define CHECK_TYPE(EXPR, TYPE) \ + _Static_assert (_Generic (EXPR, TYPE: 1), "type check") + +static int +do_test (void) +{ + /* This is a compilation test. */ + CHECK_TYPE (memchr (vp, c, sz), void *); + CHECK_TYPE (memchr (cvp, c, sz), const void *); + CHECK_TYPE (memchr (ip, c, sz), void *); + CHECK_TYPE (memchr (cip, c, sz), const void *); + CHECK_TYPE (memchr (cp, c, sz), void *); + CHECK_TYPE (memchr (ccp, c, sz), const void *); + DIAG_PUSH_NEEDS_COMMENT; + /* This deliberately tests the type of the result with a null + pointer constant argument. */ + DIAG_IGNORE_NEEDS_COMMENT (14, "-Wnonnull"); + CHECK_TYPE (memchr (0, c, sz), void *); + CHECK_TYPE (memchr ((void *) 0, c, sz), void *); + DIAG_POP_NEEDS_COMMENT; + CHECK_TYPE (strchr (vp, c), char *); + CHECK_TYPE (strchr (cvp, c), const char *); + CHECK_TYPE (strchr (cp, c), char *); + CHECK_TYPE (strchr (ccp, c), const char *); + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT (14, "-Wnonnull"); + CHECK_TYPE (strchr (0, c), char *); + CHECK_TYPE (strchr ((void *) 0, c), char *); + DIAG_POP_NEEDS_COMMENT; + CHECK_TYPE (strpbrk (vp, vp), char *); + CHECK_TYPE (strpbrk (vp, cvp), char *); + CHECK_TYPE (strpbrk (cvp, vp), const char *); + CHECK_TYPE (strpbrk (cvp, cvp), const char *); + CHECK_TYPE (strpbrk (cp, cp), char *); + CHECK_TYPE (strpbrk (cp, ccp), char *); + CHECK_TYPE (strpbrk (ccp, cp), const char *); + CHECK_TYPE (strpbrk (ccp, ccp), const char *); + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT (14, "-Wnonnull"); + CHECK_TYPE (strpbrk (0, cp), char *); + CHECK_TYPE (strpbrk (0, ccp), char *); + CHECK_TYPE (strpbrk ((void *) 0, cp), char *); + CHECK_TYPE (strpbrk ((void *) 0, ccp), char *); + DIAG_POP_NEEDS_COMMENT; + CHECK_TYPE (strrchr (vp, c), char *); + CHECK_TYPE (strrchr (cvp, c), const char *); + CHECK_TYPE (strrchr (cp, c), char *); + CHECK_TYPE (strrchr (ccp, c), const char *); + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT (14, "-Wnonnull"); + CHECK_TYPE (strrchr (0, c), char *); + CHECK_TYPE (strrchr ((void *) 0, c), char *); + DIAG_POP_NEEDS_COMMENT; + CHECK_TYPE (strstr (vp, vp), char *); + CHECK_TYPE (strstr (vp, cvp), char *); + CHECK_TYPE (strstr (cvp, vp), const char *); + CHECK_TYPE (strstr (cvp, cvp), const char *); + CHECK_TYPE (strstr (cp, cp), char *); + CHECK_TYPE (strstr (cp, ccp), char *); + CHECK_TYPE (strstr (ccp, cp), const char *); + CHECK_TYPE (strstr (ccp, ccp), const char *); + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT (14, "-Wnonnull"); + CHECK_TYPE (strstr (0, cp), char *); + CHECK_TYPE (strstr (0, ccp), char *); + CHECK_TYPE (strstr ((void *) 0, cp), char *); + CHECK_TYPE (strstr ((void *) 0, ccp), char *); + DIAG_POP_NEEDS_COMMENT; + return 0; +} + +#include diff --git a/timezone/Makefile b/timezone/Makefile index 6c7a7d4f4d..c03a68962c 100644 --- a/timezone/Makefile +++ b/timezone/Makefile @@ -73,8 +73,10 @@ tz-cflags = -DTZDIR='"$(zonedir)"' \ # The -Wno-unused-variable flag is used to prevent GCC 6 # from warning about time_t_min and time_t_max which are # defined in private.h but not used. +# -Wno-discarded-qualifiers is because zic is not prepared for C23 +# -qualifier-generic strchr. CFLAGS-zdump.c += $(tz-cflags) -CFLAGS-zic.c += $(tz-cflags) -Wno-unused-variable +CFLAGS-zic.c += $(tz-cflags) -Wno-unused-variable -Wno-discarded-qualifiers # We have to make sure the data for testing the tz functions is available. # Don't add leapseconds here since test-tz made checks that work only without diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile index 559438c1ce..71b5ffe1bd 100644 --- a/wcsmbs/Makefile +++ b/wcsmbs/Makefile @@ -172,6 +172,7 @@ tests := \ tst-c16-surrogate \ tst-c16c32-1 \ tst-c32-state \ + tst-const \ tst-fgetwc-after-eof \ tst-mbrtowc \ tst-mbrtowc2 \ diff --git a/wcsmbs/tst-const.c b/wcsmbs/tst-const.c new file mode 100644 index 0000000000..14f1b86449 --- /dev/null +++ b/wcsmbs/tst-const.c @@ -0,0 +1,80 @@ +/* Test const-generic macros. + Copyright (C) 2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void *vp; +const void *cvp; +wchar_t *wp; +const wchar_t *cwp; +size_t sz; +wchar_t wc; + +#define CHECK_TYPE(EXPR, TYPE) \ + _Static_assert (_Generic (EXPR, TYPE: 1), "type check") + +static int +do_test (void) +{ + /* This is a compilation test. */ + CHECK_TYPE (wmemchr (vp, wc, sz), wchar_t *); + CHECK_TYPE (wmemchr (cvp, wc, sz), const wchar_t *); + CHECK_TYPE (wmemchr (wp, wc, sz), wchar_t *); + CHECK_TYPE (wmemchr (cwp, wc, sz), const wchar_t *); + CHECK_TYPE (wmemchr (0, wc, sz), wchar_t *); + CHECK_TYPE (wmemchr ((void *) 0, wc, sz), wchar_t *); + CHECK_TYPE (wcschr (vp, wc), wchar_t *); + CHECK_TYPE (wcschr (cvp, wc), const wchar_t *); + CHECK_TYPE (wcschr (wp, wc), wchar_t *); + CHECK_TYPE (wcschr (cwp, wc), const wchar_t *); + CHECK_TYPE (wcschr (0, wc), wchar_t *); + CHECK_TYPE (wcschr ((void *) 0, wc), wchar_t *); + CHECK_TYPE (wcspbrk (vp, vp), wchar_t *); + CHECK_TYPE (wcspbrk (vp, cvp), wchar_t *); + CHECK_TYPE (wcspbrk (cvp, vp), const wchar_t *); + CHECK_TYPE (wcspbrk (cvp, cvp), const wchar_t *); + CHECK_TYPE (wcspbrk (wp, wp), wchar_t *); + CHECK_TYPE (wcspbrk (wp, cwp), wchar_t *); + CHECK_TYPE (wcspbrk (cwp, wp), const wchar_t *); + CHECK_TYPE (wcspbrk (cwp, cwp), const wchar_t *); + CHECK_TYPE (wcspbrk (0, wp), wchar_t *); + CHECK_TYPE (wcspbrk (0, cwp), wchar_t *); + CHECK_TYPE (wcspbrk ((void *) 0, wp), wchar_t *); + CHECK_TYPE (wcspbrk ((void *) 0, cwp), wchar_t *); + CHECK_TYPE (wcsrchr (vp, wc), wchar_t *); + CHECK_TYPE (wcsrchr (cvp, wc), const wchar_t *); + CHECK_TYPE (wcsrchr (wp, wc), wchar_t *); + CHECK_TYPE (wcsrchr (cwp, wc), const wchar_t *); + CHECK_TYPE (wcsrchr (0, wc), wchar_t *); + CHECK_TYPE (wcsrchr ((void *) 0, wc), wchar_t *); + CHECK_TYPE (wcsstr (vp, vp), wchar_t *); + CHECK_TYPE (wcsstr (vp, cvp), wchar_t *); + CHECK_TYPE (wcsstr (cvp, vp), const wchar_t *); + CHECK_TYPE (wcsstr (cvp, cvp), const wchar_t *); + CHECK_TYPE (wcsstr (wp, wp), wchar_t *); + CHECK_TYPE (wcsstr (wp, cwp), wchar_t *); + CHECK_TYPE (wcsstr (cwp, wp), const wchar_t *); + CHECK_TYPE (wcsstr (cwp, cwp), const wchar_t *); + CHECK_TYPE (wcsstr (0, wp), wchar_t *); + CHECK_TYPE (wcsstr (0, cwp), wchar_t *); + CHECK_TYPE (wcsstr ((void *) 0, wp), wchar_t *); + CHECK_TYPE (wcsstr ((void *) 0, cwp), wchar_t *); + return 0; +} + +#include diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h index b31ca2d241..19f71f90cf 100644 --- a/wcsmbs/wchar.h +++ b/wcsmbs/wchar.h @@ -188,6 +188,10 @@ extern "C++" const wchar_t *wcschr (const wchar_t *__wcs, wchar_t __wc) #else extern wchar_t *wcschr (const wchar_t *__wcs, wchar_t __wc) __THROW __attribute_pure__; +# if __GLIBC_USE (ISOC23) && defined __glibc_const_generic && !defined _LIBC +# define wcschr(WCS, WC) \ + __glibc_const_generic (WCS, const wchar_t *, wcschr (WCS, WC)) +# endif #endif /* Find the last occurrence of WC in WCS. */ #ifdef __CORRECT_ISO_CPP_WCHAR_H_PROTO @@ -198,6 +202,10 @@ extern "C++" const wchar_t *wcsrchr (const wchar_t *__wcs, wchar_t __wc) #else extern wchar_t *wcsrchr (const wchar_t *__wcs, wchar_t __wc) __THROW __attribute_pure__; +# if __GLIBC_USE (ISOC23) && defined __glibc_const_generic && !defined _LIBC +# define wcsrchr(WCS, WC) \ + __glibc_const_generic (WCS, const wchar_t *, wcsrchr (WCS, WC)) +# endif #endif #ifdef __USE_GNU @@ -225,6 +233,10 @@ extern "C++" const wchar_t *wcspbrk (const wchar_t *__wcs, #else extern wchar_t *wcspbrk (const wchar_t *__wcs, const wchar_t *__accept) __THROW __attribute_pure__; +# if __GLIBC_USE (ISOC23) && defined __glibc_const_generic && !defined _LIBC +# define wcspbrk(WCS, ACCEPT) \ + __glibc_const_generic (WCS, const wchar_t *, wcspbrk (WCS, ACCEPT)) +# endif #endif /* Find the first occurrence of NEEDLE in HAYSTACK. */ #ifdef __CORRECT_ISO_CPP_WCHAR_H_PROTO @@ -236,6 +248,11 @@ extern "C++" const wchar_t *wcsstr (const wchar_t *__haystack, #else extern wchar_t *wcsstr (const wchar_t *__haystack, const wchar_t *__needle) __THROW __attribute_pure__; +# if __GLIBC_USE (ISOC23) && defined __glibc_const_generic && !defined _LIBC +# define wcsstr(HAYSTACK, NEEDLE) \ + __glibc_const_generic (HAYSTACK, const wchar_t *, \ + wcsstr (HAYSTACK, NEEDLE)) +# endif #endif /* Divide WCS into tokens separated by characters in DELIM. */ @@ -277,6 +294,10 @@ extern "C++" const wchar_t *wmemchr (const wchar_t *__s, wchar_t __c, #else extern wchar_t *wmemchr (const wchar_t *__s, wchar_t __c, size_t __n) __THROW __attribute_pure__; +# if __GLIBC_USE (ISOC23) && defined __glibc_const_generic && !defined _LIBC +# define wmemchr(S, C, N) \ + __glibc_const_generic (S, const wchar_t *, wmemchr (S, C, N)) +# endif #endif /* Compare N wide characters of S1 and S2. */