From patchwork Thu Jul 7 19:59:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 55858 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 8C1D7385C41C for ; Thu, 7 Jul 2022 20:00:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8C1D7385C41C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1657224007; bh=oHYfSScWrCMq/ObEbcth3+665Zk4qTp1LCx/HTnKdO4=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=AzjrwV3ebp8o3rI/uNU/PAkgLU60s/WDde0e0VZQqiCM5uusEaVLgxDVIhGEsennF YHQeTcb2bkG1vex/O0LjA+2n8+ABrIOEp+fWEbwbyLcoXDRyLFV7sZr91yrvjNKjsC fn7FXpjSFdxxV0j7v4tViowIv99u4jBYhcSeaqlo= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from rock.gnat.com (rock.gnat.com [205.232.38.15]) by sourceware.org (Postfix) with ESMTPS id D51143857410 for ; Thu, 7 Jul 2022 19:59:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D51143857410 Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id 43E95116805; Thu, 7 Jul 2022 15:59:35 -0400 (EDT) X-Virus-Scanned: Debian amavisd-new at gnat.com Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id kOe0CnttXZGX; Thu, 7 Jul 2022 15:59:35 -0400 (EDT) Received: from free.home (tron.gnat.com [IPv6:2620:20:4000:0:46a8:42ff:fe0e:e294]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by rock.gnat.com (Postfix) with ESMTPS id D66C11166B4; Thu, 7 Jul 2022 15:59:34 -0400 (EDT) Received: from livre (livre.home [172.31.160.2]) by free.home (8.15.2/8.15.2) with ESMTPS id 267JxNhC1192924 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 7 Jul 2022 16:59:24 -0300 To: gcc-patches@gcc.gnu.org Subject: [PATCH] Introduce hardbool attribute for C Organization: Free thinker, does not speak for AdaCore Date: Thu, 07 Jul 2022 16:59:23 -0300 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.2 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 X-Spam-Status: No, score=-12.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: 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: Alexandre Oliva via Gcc-patches From: Alexandre Oliva Reply-To: Alexandre Oliva Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" This patch introduces hardened booleans in C. The hardbool attribute, when attached to an integral type, turns it into an enumerate type with boolean semantics, using the named or implied constants as representations for false and true. Expressions of such types decay to _Bool, trapping if the value is neither true nor false, and _Bool can convert implicitly back to them. Other conversions go through _Bool first. Regstrapped on x86_64-linux-gnu. Ok to install? for gcc/c-family/ChangeLog * c-attribs.cc (c_common_attribute_table): Add hardbool. (handle_hardbool_attribute): New. (type_valid_for_vector_size): Reject hardbool. * c-common.cc (convert_and_check): Skip warnings for convert and check for hardbool. (c_hardbool_type_attr_1): New. * c-common.h (c_hardbool_type_attr): New. for gcc/c/ChangeLog * c-typeck.cc (convert_lvalue_to_rvalue): Decay hardbools. * c-convert.cc (convert): Convert to hardbool through truthvalue. * c-decl.cc (check_bitfield_type_and_width): Skip enumeral truncation warnings for hardbool. (finish_struct): Propagate hardbool attribute to bitfield types. (digest_init): Convert to hardbool. for gcc/ChangeLog * doc/extend.texi (hardbool): New type attribute. for gcc/testsuite/ChangeLog * gcc.dg/hardbool-err.c: New. * gcc.dg/hardbool-trap.c: New. * gcc.dg/hardbool.c: New. * gcc.dg/hardbool-s.c: New. * gcc.dg/hardbool-us.c: New. * gcc.dg/hardbool-i.c: New. * gcc.dg/hardbool-ul.c: New. * gcc.dg/hardbool-ll.c: New. * gcc.dg/hardbool-5a.c: New. * gcc.dg/hardbool-s-5a.c: New. * gcc.dg/hardbool-us-5a.c: New. * gcc.dg/hardbool-i-5a.c: New. * gcc.dg/hardbool-ul-5a.c: New. * gcc.dg/hardbool-ll-5a.c: New. --- gcc/c-family/c-attribs.cc | 97 ++++++++++++++++++++- gcc/c-family/c-common.cc | 21 ++++ gcc/c-family/c-common.h | 18 ++++ gcc/c/c-convert.cc | 14 +++ gcc/c/c-decl.cc | 10 ++ gcc/c/c-typeck.cc | 31 ++++++- gcc/doc/extend.texi | 37 ++++++++ gcc/testsuite/gcc.dg/hardbool-err.c | 28 ++++++ gcc/testsuite/gcc.dg/hardbool-trap.c | 13 +++ gcc/testsuite/gcc.dg/torture/hardbool-5a.c | 6 + gcc/testsuite/gcc.dg/torture/hardbool-i-5a.c | 6 + gcc/testsuite/gcc.dg/torture/hardbool-i.c | 5 + gcc/testsuite/gcc.dg/torture/hardbool-ll-5a.c | 6 + gcc/testsuite/gcc.dg/torture/hardbool-ll.c | 5 + gcc/testsuite/gcc.dg/torture/hardbool-s-5a.c | 6 + gcc/testsuite/gcc.dg/torture/hardbool-s.c | 5 + gcc/testsuite/gcc.dg/torture/hardbool-ul-5a.c | 6 + gcc/testsuite/gcc.dg/torture/hardbool-ul.c | 5 + gcc/testsuite/gcc.dg/torture/hardbool-us-5a.c | 6 + gcc/testsuite/gcc.dg/torture/hardbool-us.c | 5 + gcc/testsuite/gcc.dg/torture/hardbool.c | 118 +++++++++++++++++++++++++ 21 files changed, 444 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/hardbool-err.c create mode 100644 gcc/testsuite/gcc.dg/hardbool-trap.c create mode 100644 gcc/testsuite/gcc.dg/torture/hardbool-5a.c create mode 100644 gcc/testsuite/gcc.dg/torture/hardbool-i-5a.c create mode 100644 gcc/testsuite/gcc.dg/torture/hardbool-i.c create mode 100644 gcc/testsuite/gcc.dg/torture/hardbool-ll-5a.c create mode 100644 gcc/testsuite/gcc.dg/torture/hardbool-ll.c create mode 100644 gcc/testsuite/gcc.dg/torture/hardbool-s-5a.c create mode 100644 gcc/testsuite/gcc.dg/torture/hardbool-s.c create mode 100644 gcc/testsuite/gcc.dg/torture/hardbool-ul-5a.c create mode 100644 gcc/testsuite/gcc.dg/torture/hardbool-ul.c create mode 100644 gcc/testsuite/gcc.dg/torture/hardbool-us-5a.c create mode 100644 gcc/testsuite/gcc.dg/torture/hardbool-us.c create mode 100644 gcc/testsuite/gcc.dg/torture/hardbool.c diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index c8d96723f4c30..e385d780c49ce 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -172,6 +172,7 @@ static tree handle_objc_root_class_attribute (tree *, tree, tree, int, bool *); static tree handle_objc_nullability_attribute (tree *, tree, tree, int, bool *); static tree handle_signed_bool_precision_attribute (tree *, tree, tree, int, bool *); +static tree handle_hardbool_attribute (tree *, tree, tree, int, bool *); static tree handle_retain_attribute (tree *, tree, tree, int, bool *); /* Helper to define attribute exclusions. */ @@ -288,6 +289,8 @@ const struct attribute_spec c_common_attribute_table[] = affects_type_identity, handler, exclude } */ { "signed_bool_precision", 1, 1, false, true, false, true, handle_signed_bool_precision_attribute, NULL }, + { "hardbool", 0, 2, false, true, false, true, + handle_hardbool_attribute, NULL }, { "packed", 0, 0, false, false, false, false, handle_packed_attribute, attr_aligned_exclusions }, @@ -975,6 +978,95 @@ handle_signed_bool_precision_attribute (tree *node, tree name, tree args, return NULL_TREE; } +/* Handle a "hardbool" attribute; arguments as in struct + attribute_spec.handler. */ + +static tree +handle_hardbool_attribute (tree *node, tree name, tree args, + int /* flags */, bool *no_add_attrs) +{ + if (c_language != clk_c) + { + error ("%qE attribute only supported in C", name); + *no_add_attrs = TRUE; + return NULL_TREE; + } + + if (!TYPE_P (*node) || TREE_CODE (*node) != INTEGER_TYPE) + { + error ("%qE attribute only supported on " + "integral types", name); + *no_add_attrs = TRUE; + return NULL_TREE; + } + + tree orig = *node; + *node = build_duplicate_type (orig); + + TREE_SET_CODE (*node, ENUMERAL_TYPE); + + tree false_value; + if (args) + false_value = fold_convert (*node, TREE_VALUE (args)); + else + false_value = fold_convert (*node, integer_zero_node); + + if (TREE_OVERFLOW_P (false_value)) + { + warning (OPT_Wattributes, + "overflows in conversion from %qT to %qT " + "changes value from %qE to %qE", + TREE_TYPE (TREE_VALUE (args)), *node, + TREE_VALUE (args), false_value); + TREE_OVERFLOW (false_value) = false; + } + + tree true_value; + if (args && TREE_CHAIN (args)) + true_value = fold_convert (*node, TREE_VALUE (TREE_CHAIN (args))); + else + true_value = fold_build1 (BIT_NOT_EXPR, *node, false_value); + + if (TREE_OVERFLOW_P (true_value)) + { + warning (OPT_Wattributes, + "overflows in conversion from %qT to %qT " + "changes value from %qE to %qE", + TREE_TYPE (TREE_VALUE (TREE_CHAIN (args))), *node, + TREE_VALUE (TREE_CHAIN (args)), true_value); + TREE_OVERFLOW (true_value) = false; + } + + if (tree_int_cst_compare (false_value, true_value) == 0) + { + error ("%qE attribute requires different values for" + " % and % for type %qT", + name, *node); + *no_add_attrs = TRUE; + return NULL_TREE; + } + + tree values = build_tree_list (get_identifier ("false"), + false_value); + TREE_CHAIN (values) = build_tree_list (get_identifier ("true"), + true_value); + + /* Do *not* set TYPE_MIN_VALUE, TYPE_MAX_VALUE, nor TYPE_PRECISION according + to the false and true values. That might cause the constants to be the + only acceptable values, which would drop the very hardening checks this + attribute is supposed to add. */ + + TYPE_ATTRIBUTES (*node) = tree_cons (name, args, + TYPE_ATTRIBUTES (*node)); + *no_add_attrs = TRUE; + + gcc_checking_assert (!TYPE_CACHED_VALUES_P (*node)); + TYPE_VALUES (*node) = values; + TYPE_NAME (*node) = orig; + + return NULL_TREE; +} + /* Handle a "packed" attribute; arguments as in struct attribute_spec.handler. */ @@ -4289,7 +4381,8 @@ static tree type_valid_for_vector_size (tree type, tree atname, tree args, unsigned HOST_WIDE_INT *ptrnunits) { - bool error_p = ptrnunits != NULL; + bool hardbool_p = c_hardbool_type_attr (type); + bool error_p = ptrnunits != NULL || hardbool_p; /* Get the mode of the type being modified. */ machine_mode orig_mode = TYPE_MODE (type); @@ -4301,7 +4394,7 @@ type_valid_for_vector_size (tree type, tree atname, tree args, && GET_MODE_CLASS (orig_mode) != MODE_INT && !ALL_SCALAR_FIXED_POINT_MODE_P (orig_mode)) || !tree_fits_uhwi_p (TYPE_SIZE_UNIT (type)) - || TREE_CODE (type) == BOOLEAN_TYPE) + || TREE_CODE (type) == BOOLEAN_TYPE || hardbool_p) { if (error_p) error ("invalid vector type for attribute %qE", atname); diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 1b8e73f7bc5d8..9a8584a5fe095 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -1780,7 +1780,8 @@ convert_and_check (location_t loc, tree type, tree expr, bool init_const) if (c_inhibit_evaluation_warnings == 0 && !TREE_OVERFLOW_P (expr) - && result != error_mark_node) + && result != error_mark_node + && !c_hardbool_type_attr (type)) warnings_for_convert_and_check (loc, type, expr_for_warning, result); return result; @@ -9488,4 +9489,22 @@ c_common_finalize_early_debug (void) (*debug_hooks->early_global_decl) (cnode->decl); } +/* This is the slow path of c-common.h's c_hardbool_type_attr. */ + +tree +c_hardbool_type_attr_1 (tree type, tree *false_value, tree *true_value) +{ + tree attr = lookup_attribute ("hardbool", TYPE_ATTRIBUTES (type)); + if (!attr) + return attr; + + if (false_value) + *false_value = TREE_VALUE (TYPE_VALUES (type)); + + if (true_value) + *true_value = TREE_VALUE (TREE_CHAIN (TYPE_VALUES (type))); + + return attr; +} + #include "gt-c-family-c-common.h" diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index c0900848965a3..a8d6691d0813d 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -912,6 +912,7 @@ extern tree c_common_get_narrower (tree, int *); extern bool get_attribute_operand (tree, unsigned HOST_WIDE_INT *); extern void c_common_finalize_early_debug (void); extern bool c_option_is_from_cpp_diagnostics (int); +extern tree c_hardbool_type_attr_1 (tree, tree *, tree *); /* Used by convert_and_check; in front ends. */ extern tree convert_init (tree, tree); @@ -1291,6 +1292,23 @@ c_tree_chain_next (tree t) return NULL; } +/* Return the hardbool attribute associated with TYPE, if there is one, provided + that TYPE looks like an enumeral type that might have been set up by + handle_hardbool_attribute. Return NULL otherwise. + + If FALSE_VALUE or TRUE_VALUE are non-NULL and TYPE is a hardened boolean + type, store the corresponding representation values. */ +static inline tree +c_hardbool_type_attr (tree type, + tree *false_value = NULL, tree *true_value = NULL) +{ + if (TREE_CODE (type) != ENUMERAL_TYPE + || TYPE_LANG_SPECIFIC (type)) + return NULL_TREE; + + return c_hardbool_type_attr_1 (type, false_value, true_value); +} + /* Mask used by tm_stmt_attr. */ #define TM_STMT_ATTR_OUTER 2 #define TM_STMT_ATTR_ATOMIC 4 diff --git a/gcc/c/c-convert.cc b/gcc/c/c-convert.cc index 18083d5961826..1399cbf9d8d37 100644 --- a/gcc/c/c-convert.cc +++ b/gcc/c/c-convert.cc @@ -105,6 +105,20 @@ c_convert (tree type, tree expr, bool init_const) return error_mark_node; } + { + tree false_value, true_value; + if (c_hardbool_type_attr (type, &false_value, &true_value)) + { + bool save = in_late_binary_op; + in_late_binary_op = true; + expr = c_objc_common_truthvalue_conversion (input_location, expr); + in_late_binary_op = save; + + return fold_build3_loc (loc, COND_EXPR, type, + expr, true_value, false_value); + } + } + switch (code) { case VOID_TYPE: diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index ae8990c138fd2..e103582d677cd 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -6163,6 +6163,12 @@ check_bitfield_type_and_width (location_t loc, tree *type, tree *width, else w = tree_to_uhwi (*width); + /* Truncation of hardbool false and true representation values is always safe: + either the values remain different, or we'll report a problem when creating + the narrower type. */ + if (c_hardbool_type_attr (*type)) + return; + if (TREE_CODE (*type) == ENUMERAL_TYPE) { struct lang_type *lt = TYPE_LANG_SPECIFIC (*type); @@ -8887,6 +8893,10 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, { TREE_TYPE (field) = c_build_bitfield_integer_type (width, TYPE_UNSIGNED (type)); + if (tree attr = c_hardbool_type_attr (type)) + decl_attributes (&TREE_TYPE (field), + copy_list (attr), + 0, NULL_TREE); SET_DECL_MODE (field, TYPE_MODE (TREE_TYPE (field))); } DECL_INITIAL (field) = NULL_TREE; diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index fd0a7f81a7a92..1244241dd295b 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -2172,6 +2172,35 @@ convert_lvalue_to_rvalue (location_t loc, struct c_expr exp, if (convert_p && !error_operand_p (exp.value) && (TREE_CODE (TREE_TYPE (exp.value)) != ARRAY_TYPE)) exp.value = convert (build_qualified_type (TREE_TYPE (exp.value), TYPE_UNQUALIFIED), exp.value); + + { + tree false_value, true_value; + if (convert_p && !error_operand_p (exp.value) + && c_hardbool_type_attr (TREE_TYPE (exp.value), + &false_value, &true_value)) + { + tree t = save_expr (exp.value); + + mark_exp_read (exp.value); + + tree trapfn = builtin_decl_explicit (BUILT_IN_TRAP); + tree expr = build_call_expr_loc (loc, trapfn, 0); + expr = build_compound_expr (loc, expr, boolean_true_node); + expr = fold_build3_loc (loc, COND_EXPR, boolean_type_node, + fold_build2_loc (loc, NE_EXPR, + boolean_type_node, + t, true_value), + expr, boolean_true_node); + expr = fold_build3_loc (loc, COND_EXPR, boolean_type_node, + fold_build2_loc (loc, NE_EXPR, + boolean_type_node, + t, false_value), + expr, boolean_false_node); + + exp.value = expr; + } + } + return exp; } @@ -8167,7 +8196,7 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, } } - if (code == VECTOR_TYPE) + if (code == VECTOR_TYPE || c_hardbool_type_attr (type)) /* Although the types are compatible, we may require a conversion. */ inside_init = convert (type, inside_init); diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index dfbe33ac652f8..7b514354263f4 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -8654,6 +8654,43 @@ initialization will result in future breakage. GCC emits warnings based on this attribute by default; use @option{-Wno-designated-init} to suppress them. +@item hardbool +@itemx hardbool (@var{false_value}) +@itemx hardbool (@var{false_value}, @var{true_value}) +@cindex @code{hardbool} type attribute +This attribute may only be applied to integral types in C, to introduce +hardened boolean types. It turns the integral type into a boolean-like +type with the same size and precision, that uses the specified values as +representations for @code{false} and @code{true}. Underneath, it is +actually an enumerate type, but its observable behavior is like that of +@code{_Bool}, except for the strict internal representations, verified +by runtime checks. + +If @var{true_value} is omitted, the bitwise negation of +@var{false_value} is used. If @var{false_value} is omitted, zero is +used. The named representation values must be different when converted +to the original integral type. Narrower bitfields are rejected if the +representations become indistinguishable. + +Values of such types automatically decay to @code{_Bool}, at which +point, the selected representation values are mapped to the +corresponding @code{_Bool} values. When the represented value is not +determined, at compile time, to be either @var{false_value} or +@var{true_value}, runtime verification calls @code{__builtin_trap} if it +is neither. This is what makes them hardened boolean types. + +When converting scalar types to such hardened boolean types, implicitly +or explicitly, behavior corresponds to a conversion to @code{_Bool}, +followed by a mapping from @code{false} and @code{true} to +@var{false_value} and @var{true_value}, respectively. + +@smallexample +typedef char __attribute__ ((__hardbool__ (0x5a))) hbool; +hbool first = 0; /* False, stored as (char)0x5a. */ +hbool second = !first; /* True, stored as ~(char)0x5a. */ +@end smallexample + + @item may_alias @cindex @code{may_alias} type attribute Accesses through pointers to types with this attribute are not subject diff --git a/gcc/testsuite/gcc.dg/hardbool-err.c b/gcc/testsuite/gcc.dg/hardbool-err.c new file mode 100644 index 0000000000000..634feaed4deef --- /dev/null +++ b/gcc/testsuite/gcc.dg/hardbool-err.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ + +typedef _Bool __attribute__ ((__hardbool__)) +hbbl; /* { dg-error "integral types" } */ + +typedef double __attribute__ ((__hardbool__)) +hbdbl; /* { dg-error "integral types" } */ + +enum x; +typedef enum x __attribute__ ((__hardbool__)) +hbenum; /* { dg-error "integral types" } */ + +struct s; +typedef struct s __attribute__ ((__hardbool__)) +hbstruct; /* { dg-error "integral types" } */ + +typedef int __attribute__ ((__hardbool__ (0, 0))) +hb00; /* { dg-error "different values" } */ + +typedef int __attribute__ ((__hardbool__ (4, 16))) hb4x; +struct s { + hb4x m:2; +}; /* { dg-error "is a GCC extension|different values" } */ +/* { dg-warning "changes value" "warning" { target *-*-* } .-1 } */ + +hb4x __attribute__ ((vector_size (4 * sizeof (hb4x)))) +vvar; /* { dg-error "invalid vector type" } */ diff --git a/gcc/testsuite/gcc.dg/hardbool-trap.c b/gcc/testsuite/gcc.dg/hardbool-trap.c new file mode 100644 index 0000000000000..2eebd0ef64fff --- /dev/null +++ b/gcc/testsuite/gcc.dg/hardbool-trap.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fdump-tree-optimized" } */ + +typedef char __attribute__ ((__hardbool__ (1))) hbool; + +hbool var; + +int main () { + __builtin_memset (&var, 0, sizeof (var)); + (void)var; +} + +/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-5a.c b/gcc/testsuite/gcc.dg/torture/hardbool-5a.c new file mode 100644 index 0000000000000..a03887cfbecc5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool-5a.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-w" } */ + +#define falseval 0x5a + +#include "hardbool.c" diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-i-5a.c b/gcc/testsuite/gcc.dg/torture/hardbool-i-5a.c new file mode 100644 index 0000000000000..c0ba2a8b9148e --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool-i-5a.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-w" } */ + +#define falseval 0xa53cc35a + +#include "hardbool-i.c" diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-i.c b/gcc/testsuite/gcc.dg/torture/hardbool-i.c new file mode 100644 index 0000000000000..39214d28c5627 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool-i.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ + +#define basetype int + +#include "hardbool.c" diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-ll-5a.c b/gcc/testsuite/gcc.dg/torture/hardbool-ll-5a.c new file mode 100644 index 0000000000000..14438c5104f07 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool-ll-5a.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-w" } */ + +#define falseval 0x781ee187a53cc35all + +#include "hardbool-ll.c" diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-ll.c b/gcc/testsuite/gcc.dg/torture/hardbool-ll.c new file mode 100644 index 0000000000000..d4d498c6f2af1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool-ll.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ + +#define basetype long long + +#include "hardbool.c" diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-s-5a.c b/gcc/testsuite/gcc.dg/torture/hardbool-s-5a.c new file mode 100644 index 0000000000000..e38a56b5deb05 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool-s-5a.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-w" } */ + +#define falseval 0x5aa5 + +#include "hardbool-s.c" diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-s.c b/gcc/testsuite/gcc.dg/torture/hardbool-s.c new file mode 100644 index 0000000000000..942300be2072a --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool-s.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ + +#define basetype short + +#include "hardbool.c" diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-ul-5a.c b/gcc/testsuite/gcc.dg/torture/hardbool-ul-5a.c new file mode 100644 index 0000000000000..7beec578ff89c --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool-ul-5a.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-w" } */ + +#define falseval 0xa53cc35a + +#include "hardbool-ul.c" diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-ul.c b/gcc/testsuite/gcc.dg/torture/hardbool-ul.c new file mode 100644 index 0000000000000..841c1d4bc2ec8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool-ul.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ + +#define basetype unsigned long + +#include "hardbool.c" diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-us-5a.c b/gcc/testsuite/gcc.dg/torture/hardbool-us-5a.c new file mode 100644 index 0000000000000..5bfc922795d3d --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool-us-5a.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-w" } */ + +#define falseval 0xa55a + +#include "hardbool-us.c" diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-us.c b/gcc/testsuite/gcc.dg/torture/hardbool-us.c new file mode 100644 index 0000000000000..e9feec681c41e --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool-us.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ + +#define basetype unsigned short + +#include "hardbool.c" diff --git a/gcc/testsuite/gcc.dg/torture/hardbool.c b/gcc/testsuite/gcc.dg/torture/hardbool.c new file mode 100644 index 0000000000000..01684952a2a9f --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool.c @@ -0,0 +1,118 @@ +/* { dg-do run } */ + +#include + +#ifndef basetype +#define basetype char +#endif + +#ifndef falseval +#define falseval 0 +#endif + +#ifndef trueval +#define trueval ~falseval +#endif + +/* hardbool may be #defined so as to drop parms in other tests. */ +typedef basetype __attribute__ ((hardbool (falseval, trueval))) hbool; + +typedef unsigned char __attribute__ ((__hardbool__ (1, 0))) zbool; + +struct hs { + hbool a[2]; + hbool x:2; + hbool y:5; + zbool z:1; +}; + +hbool var = 0; + +struct hs x = { { 1, 0 }, 2, 0, 2 }; + +int f(hbool v) { + return !v; +} + +int g(int i) { + return f(i); +} + +hbool h(hbool x) { + return x; +} + +hbool h2(hbool x) { + return h(x); +} + +int hsx(struct hs v) { + return v.x; +} + +int ghs(hbool s) { + struct hs v = { {s, !s}, s, !s, s }; + return hsx (v); +} + +int t = (hbool)2; + +void check_pfalse (hbool *p) +{ + assert (!*p); + assert (*(basetype*)p == (basetype)falseval); + assert (!(int)(hbool)*p); +} + +void check_ptrue (hbool *p) +{ + assert (*p); + assert (*(basetype*)p == (basetype)trueval); + assert ((int)(hbool)*p); +} + +void check_vfalse (hbool v) +{ + check_pfalse (&v); +} + +void check_vtrue (hbool v) +{ + check_ptrue (&v); +} + +int main () { + check_pfalse (&var); + var = !(int)(hbool)(_Bool)var; + check_ptrue (&var); + var = (zbool)var; + check_ptrue (&var); + + check_ptrue (&x.a[0]); + check_pfalse (&x.a[1]); + check_vtrue (x.x); + check_vfalse (x.y); + check_vtrue (x.z); + + check_vtrue (t); + + check_vtrue (var && t); + check_vfalse (!var || x.y); + + check_vfalse (f (2)); + check_vfalse (f (1)); + check_vtrue (f (0)); + + check_vfalse (g (2)); + check_vfalse (g (1)); + check_vtrue (g (0)); + + check_vtrue (h (2)); + check_vtrue (h (1)); + check_vfalse (h (0)); + + check_vtrue (h2 (2)); + check_vtrue (h2 (1)); + check_vfalse (h2 (0)); +} +