From patchwork Sat Jun 10 10:37:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 105926 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp1464191vqr; Sat, 10 Jun 2023 03:38:36 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7Iov/WlnH342InAbOovUrFqryhlNDINUEzU6HqvfRml+30TE6u6bD6+j33F9imoq1+vGiO X-Received: by 2002:aa7:c998:0:b0:506:c2d7:504a with SMTP id c24-20020aa7c998000000b00506c2d7504amr803501edt.42.1686393515989; Sat, 10 Jun 2023 03:38:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1686393515; cv=none; d=google.com; s=arc-20160816; b=ubiZYrm3EKrMlmd/ouqas7z/U7t46gIijGJC+jpjhIjOmrwC2UVb0Hfe2843ZfNKEC V0NFQBtHjC8KbZmHnf06HGzdgbKg72twCIckb6QHkIbxcPXuTPO+wLHFWo4PBkFaFeNU B/Me3qdYV2XLQxLK2tPm8ZZBFLwoIHKlvMJNIJAAjH24/jCsP0qcGc7EFM/Pj9SRht6o QHgF/ZvFnYFkPjrqDRCFwSfW7Lpg+j3DvuCzBw+tw1eM7NMEreAa8pAzVndWpV0siUn6 nsihy33swe2KohVRhmHWfxUjmjSREFznfhHvQ86EMc/H8f24DihttaV4ChQulrqxBcJ/ vFqg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence :content-disposition:mime-version:message-id:subject:cc:to:date :dmarc-filter:delivered-to:dkim-signature:dkim-filter; bh=hkpjjTBnC381D1NgiGI0jMHHCupGhc+fa9vMdMtwc18=; b=LiINKzpX5PCeh/evu/jfVDdfpWZyB/ss5C/5qMyKPtZjAa5v+4zfIAuLo76qa3J5o1 J6ay8EhK7E9ND4uPP8LcR4IOi8mK0dtYrCc4MjuF/IxfDHE3dXm09Px0LMz+21Q1Wim1 EdLnGbBwRdI2zhPJJFaM83cANv0FPkhrRp7M0AqmmNPjQ2vRr5W26j+4yts5HiaX5vhV 0eIOA9uf8D6ZtdrJonrWhkM1IS//OmpbvYa2p0AUIY0wjMDgTUaleX5WyX3+REXedTxo KQ/vt2p0+NrAFvD5oI2Dp6FKt49EXDElL8KQN84p3dJMs/BjbTEXXTZRLS3g0h33X6/H sYkQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=toEQKq+C; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id b23-20020a05640202d700b005149e01288fsi3468412edx.563.2023.06.10.03.38.35 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 10 Jun 2023 03:38:35 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=toEQKq+C; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A753A385773C for ; Sat, 10 Jun 2023 10:38:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A753A385773C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1686393514; bh=hkpjjTBnC381D1NgiGI0jMHHCupGhc+fa9vMdMtwc18=; h=Date:To:Cc:Subject:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=toEQKq+CiLxdgM1horGBcS/F3cLBZUwkd50b1CXiJaYQesQLnyqyi8ncUJ/jKvA4u B6NYWP/hx6oS6R5r56a2lvLoXGiUtHpLbcV8/BLagSIBnmh2xGhoHp/tBo1gzIcDHB Z1dLxyoRNivOA0ll7dzy/m0Ub51FEuEjxBNci7rY= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id CD83D385661A for ; Sat, 10 Jun 2023 10:37:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CD83D385661A Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-5-9rLZSKrfNHKagcvYmo1KOA-1; Sat, 10 Jun 2023 06:37:46 -0400 X-MC-Unique: 9rLZSKrfNHKagcvYmo1KOA-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id A735E85A5AA; Sat, 10 Jun 2023 10:37:45 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.194.30]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 4589A2166B25; Sat, 10 Jun 2023 10:37:45 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 35AAbgFa178737 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Sat, 10 Jun 2023 12:37:42 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 35AAbfCI178736; Sat, 10 Jun 2023 12:37:41 +0200 Date: Sat, 10 Jun 2023 12:37:40 +0200 To: "Joseph S. Myers" , Marek Polacek Cc: gcc-patches@gcc.gnu.org Subject: [RFC] Add stdckdint.h header for C23 Message-ID: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.6 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-3.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, KAM_NUMSUBJECT, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Jakub Jelinek via Gcc-patches From: Jakub Jelinek Reply-To: Jakub Jelinek Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1768311767030489344?= X-GMAIL-MSGID: =?utf-8?q?1768311767030489344?= Hi! The following patch is an attempt to implement the C23 stdckdint.h header on top of our GNU extension - __builtin_{add,sub,mul}_overflow builtins. I have looked at gnulib stdckdint.h and they are full of workarounds for various compilers, EDG doesn't do this, clang <= 14 can't multiply __int128, ..., so I think the header belongs into the compiler rather than C library, because it would be a nightmare to maintain it there. What I'm struggling with is enforcing the weird restrictions C23 imposes on these. The builtins error on the result pointer not being writable, or having boolean or enumeral type (the reason for disallowing bool was that it would be questionable whether it should act as if storing to an unsigned 1-bit precision type which would overflow if result is not in [0,1] or whether it would never overflow for bool * result and simply store false if the infinite precision result is 0 and true otherwise, and for enums because of the uncertainities on just the enumerators vs. range from smallest to largest enumerator vs. strict enum precision with underlying type). They do allow storing result in plain char. And the source operands can have any integral types, including plain char, including booleans and including enumeral types. The plain is to allow even _BitInt(N) as both source and result later on. Now, C23 says that suitable types for both type2/type3 and type1 are integral types other than plain char, bool, a bit-precise integer type, or an enumerated type. And it also says: It is recommended to produce a diagnostic message if type2 or type3 are not suitable integer types, or if *result is not a modifiable lvalue of a suitable integer type. I've tried to first check it with: static_assert (_Generic ((a), char: 0, const char: 0, volatile char: 0, const volatile char: 0, default: __builtin_classify_type (a) - 1 <= 1U), "...") but that only catches plain char and doesn't catch _Bool/bool and doesn't catch enumerated types (note, for the *result we diagnose it for the builtins, but not for the other args), because __builtin_classify_type sadly promotes its argument. The _Generic in the patch below is slightly better, it catches also _Bool/bool, but doesn't catch enumerated types, comptypes used by _Generic says enumeral type is compatible with the underlying integer type. But catching just plain char and bool would be also doable with just _Generic listing the non-allowed types. I think changing __builtin_classify_type behavior after 35 years would be dangerous, shall we introduce a new similar builtin which would just never promote the argument/perform array/function/enum conversions on it, so that __builtin_type_classify (true) == boolean_type_class enum E { E1, E2 } e; __builtin_type_classify (e) == enumeral_type_class int a[2]; __builtin_type_classify (a) == array_type_class etc.? Seems clang changed __builtin_type_classify at some point so that it e.g. returns enumeral_type_class for enum arguments and array_type_class for arrays, but doesn't return boolean_type_class for _Bool argument. Also, shall we introduce __typeof_unqual__ keyword which could be used in < C23 modes and perhaps C++? 2023-06-10 Jakub Jelinek * Makefile.in (USER_H): Add stdckdint.h. * ginclude/stdckdint.h: New file. * gcc.dg/stdckdint-1.c: New test. * gcc.dg/stdckdint-2.c: New test. Jakub --- gcc/Makefile.in.jj 2023-06-06 20:02:35.581211930 +0200 +++ gcc/Makefile.in 2023-06-10 10:17:05.062270115 +0200 @@ -466,6 +466,7 @@ USER_H = $(srcdir)/ginclude/float.h \ $(srcdir)/ginclude/stdnoreturn.h \ $(srcdir)/ginclude/stdalign.h \ $(srcdir)/ginclude/stdatomic.h \ + $(srcdir)/ginclude/stdckdint.h \ $(EXTRA_HEADERS) USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@ --- gcc/ginclude/stdckdint.h.jj 2023-06-10 09:20:39.154053338 +0200 +++ gcc/ginclude/stdckdint.h 2023-06-10 12:02:33.454947780 +0200 @@ -0,0 +1,78 @@ +/* Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC 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 General Public License for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +/* ISO C23: 7.20 Checked Integer Arithmetic . */ + +#ifndef _STDCKDINT_H +#define _STDCKDINT_H + +#define __STDC_VERSION_STDCKDINT_H__ 202311L + +#if __STDC_VERSION__ > 201710L +# ifdef __SIZEOF_INT20__ +# define __ckd_type_int20 __int20: 1, unsigned __int20: 1, +# else +# define __ckd_type_int20 +# endif +# ifdef __SIZEOF_INT128__ +# define __ckd_type_int128 __int128: 1, unsigned __int128: 1, +# else +# define __ckd_type_int128 +# endif +# define __ckd_type_check_1(a, n) \ + static_assert (_Generic (((typeof_unqual (a)) 0), \ + signed char: 1, \ + unsigned char: 1, \ + short: 1, \ + unsigned short: 1, \ + int: 1, \ + unsigned int: 1, \ + long: 1, \ + unsigned long: 1, \ + long long: 1, \ + unsigned long long: 1, \ + __ckd_type_int20 \ + __ckd_type_int128 \ + default: 0), \ + "types used in " n " should be integral other than plain " \ + "char, bool, bit-precise integer or enumerated type") +# define __ckd_type_check(r, a, b, n) \ + (__extension__ ({ __ckd_type_check_1 ((r)[0], n); \ + __ckd_type_check_1 (a, n); \ + __ckd_type_check_1 (b, n); \ + (r); })) +#else +# define __ckd_type_check(r, a, b, n) r +#endif + +#define ckd_add(r, a, b) \ + ((_Bool) __builtin_add_overflow (a, b, \ + __ckd_type_check (r, a, b, "ckd_add"))) +#define ckd_sub(r, a, b) \ + ((_Bool) __builtin_sub_overflow (a, b, \ + __ckd_type_check (r, a, b, "ckd_sub"))) +#define ckd_mul(r, a, b) \ + ((_Bool) __builtin_mul_overflow (a, b, \ + __ckd_type_check (r, a, b, "ckd_mul"))) + +#endif /* stdckdint.h */ --- gcc/testsuite/gcc.dg/stdckdint-1.c.jj 2023-06-10 10:04:23.547792318 +0200 +++ gcc/testsuite/gcc.dg/stdckdint-1.c 2023-06-10 10:50:29.748579415 +0200 @@ -0,0 +1,61 @@ +/* Test C23 Checked Integer Arithmetic macros in . */ +/* { dg-do run } */ +/* { dg-options "-std=c2x" } */ + +#include + +#if __STDC_VERSION_STDCKDINT_H__ != 202311L +# error __STDC_VERSION_STDCKDINT_H__ not defined to 202311L +#endif + +extern void abort (void); + +int +main () +{ + unsigned int a; + if (ckd_add (&a, 1, 2) || a != 3) + abort (); + if (ckd_add (&a, ~2U, 2) || a != ~0U) + abort (); + if (!ckd_add (&a, ~2U, 4) || a != 1) + abort (); + if (ckd_sub (&a, 42, 2) || a != 40) + abort (); + if (!ckd_sub (&a, 11, ~0ULL) || a != 12) + abort (); + if (ckd_mul (&a, 42, 16U) || a != 672) + abort (); + if (ckd_mul (&a, ~0UL, 0) || a != 0) + abort (); + if (ckd_mul (&a, 1, ~0U) || a != ~0U) + abort (); + if (ckd_mul (&a, ~0UL, 1) != (~0UL > ~0U) || a != ~0U) + abort (); + static_assert (_Generic (ckd_add (&a, 1, 1), bool: 1, default: 0)); + static_assert (_Generic (ckd_sub (&a, 1, 1), bool: 1, default: 0)); + static_assert (_Generic (ckd_mul (&a, 1, 1), bool: 1, default: 0)); + signed char b; + if (ckd_add (&b, 8, 12) || b != 20) + abort (); + if (ckd_sub (&b, 8UL, 12ULL) || b != -4) + abort (); + if (ckd_mul (&b, 2, 3) || b != 6) + abort (); + unsigned char c; + if (ckd_add (&c, 8, 12) || c != 20) + abort (); + if (ckd_sub (&c, 8UL, 12ULL) != (-4ULL > (unsigned char) -4U) + || c != (unsigned char) -4U) + abort (); + if (ckd_mul (&c, 2, 3) || c != 6) + abort (); + long long d; + if (ckd_add (&d, ~0U, ~0U) != (~0U + 1ULL < ~0U) + || d != (long long) (2 * (unsigned long long) ~0U)) + abort (); + if (ckd_sub (&d, 0, 0) || d != 0) + abort (); + if (ckd_mul (&d, 16, 1) || d != 16) + abort (); +} --- gcc/testsuite/gcc.dg/stdckdint-2.c.jj 2023-06-10 10:04:31.600681050 +0200 +++ gcc/testsuite/gcc.dg/stdckdint-2.c 2023-06-10 12:00:25.560711350 +0200 @@ -0,0 +1,53 @@ +/* Test C23 Checked Integer Arithmetic macros in . */ +/* { dg-do run } */ +/* { dg-options "-std=c2x" } */ + +#include + +int +main () +{ + char a; + bool b; + enum E { E1, E2 } c = E1; + int d; + ckd_add (&a, 1, 1); /* { dg-error "types used in ckd_add should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_sub (&a, 1, 1); /* { dg-error "types used in ckd_sub should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_mul (&a, 1, 1); /* { dg-error "types used in ckd_mul should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_add (&b, 1, 1); /* { dg-error "types used in ckd_add should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + /* { dg-error "has pointer to boolean type" "" { target *-*-* } .-1 } */ + ckd_sub (&b, 1, 1); /* { dg-error "types used in ckd_sub should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + /* { dg-error "has pointer to boolean type" "" { target *-*-* } .-1 } */ + ckd_mul (&b, 1, 1); /* { dg-error "types used in ckd_mul should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + /* { dg-error "has pointer to boolean type" "" { target *-*-* } .-1 } */ + ckd_add (&c, 1, 1); /* { dg-error "types used in ckd_add should be integral other than plain char, bool, bit-precise integer or enumerated type" "" { xfail *-*-* } } */ + /* { dg-error "has pointer to enumerated type" "" { target *-*-* } .-1 } */ + ckd_sub (&c, 1, 1); /* { dg-error "types used in ckd_sub should be integral other than plain char, bool, bit-precise integer or enumerated type" "" { xfail *-*-* } } */ + /* { dg-error "has pointer to enumerated type" "" { target *-*-* } .-1 } */ + ckd_mul (&c, 1, 1); /* { dg-error "types used in ckd_mul should be integral other than plain char, bool, bit-precise integer or enumerated type" "" { xfail *-*-* } } */ + /* { dg-error "has pointer to enumerated type" "" { target *-*-* } .-1 } */ + ckd_add (&d, (char) 1, 1); /* { dg-error "types used in ckd_add should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_sub (&d, (char) 1, 1); /* { dg-error "types used in ckd_sub should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_mul (&d, (char) 1, 1); /* { dg-error "types used in ckd_mul should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_add (&d, false, 1); /* { dg-error "types used in ckd_add should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_sub (&d, false, 1); /* { dg-error "types used in ckd_sub should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_mul (&d, false, 1); /* { dg-error "types used in ckd_mul should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_add (&d, true, 1); /* { dg-error "types used in ckd_add should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_sub (&d, true, 1); /* { dg-error "types used in ckd_sub should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_mul (&d, true, 1); /* { dg-error "types used in ckd_mul should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_add (&d, c, 1); /* { dg-error "types used in ckd_add should be integral other than plain char, bool, bit-precise integer or enumerated type" "" { xfail *-*-* } } */ + ckd_sub (&d, c, 1); /* { dg-error "types used in ckd_sub should be integral other than plain char, bool, bit-precise integer or enumerated type" "" { xfail *-*-* } } */ + ckd_mul (&d, c, 1); /* { dg-error "types used in ckd_mul should be integral other than plain char, bool, bit-precise integer or enumerated type" "" { xfail *-*-* } } */ + ckd_add (&d, 1, (char) 1); /* { dg-error "types used in ckd_add should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_sub (&d, 1, (char) 1); /* { dg-error "types used in ckd_sub should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_mul (&d, 1, (char) 1); /* { dg-error "types used in ckd_mul should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_add (&d, 1, false); /* { dg-error "types used in ckd_add should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_sub (&d, 1, false); /* { dg-error "types used in ckd_sub should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_mul (&d, 1, false); /* { dg-error "types used in ckd_mul should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_add (&d, 1, true); /* { dg-error "types used in ckd_add should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_sub (&d, 1, true); /* { dg-error "types used in ckd_sub should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_mul (&d, 1, true); /* { dg-error "types used in ckd_mul should be integral other than plain char, bool, bit-precise integer or enumerated type" } */ + ckd_add (&d, 1, c); /* { dg-error "types used in ckd_add should be integral other than plain char, bool, bit-precise integer or enumerated type" "" { xfail *-*-* } } */ + ckd_sub (&d, 1, c); /* { dg-error "types used in ckd_sub should be integral other than plain char, bool, bit-precise integer or enumerated type" "" { xfail *-*-* } } */ + ckd_mul (&d, 1, c); /* { dg-error "types used in ckd_mul should be integral other than plain char, bool, bit-precise integer or enumerated type" "" { xfail *-*-* } } */ +}