Hi, Alexandre,

> 
> diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> index 22e240a3c2a55..f9cc609b54d94 100644
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -2226,6 +2226,35 @@ convert_lvalue_to_rvalue (location_t loc, struct 
> c_expr exp,
>     exp.value = convert (build_qualified_type (TREE_TYPE (exp.value), 
> TYPE_UNQUALIFIED), exp.value);
>   if (force_non_npc)
>     exp.value = build1 (NOP_EXPR, TREE_TYPE (exp.value), 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;
> +      }
> +  }

I see that you have testing case to check the above built_in_trap call is 
generated by FE. 
Do you have a testing case to check the trap is happening at runtime? 
> +
>   return exp;
> }
> 
> @@ -8488,7 +8517,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 2de212c8c2d84..7b5592502734e 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -8681,6 +8681,58 @@ initialization will result in future breakage.
> GCC emits warnings based on this attribute by default; use
> @option{-Wno-designated-init} to suppress them.
> 
> +@cindex @code{hardbool} type attribute
> +@item hardbool
> +@itemx hardbool (@var{false_value})
> +@itemx hardbool (@var{false_value}, @var{true_value})
> +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.  */
> +
> +static hbool zeroinit; /* False, stored as (char)0x5a.  */
> +auto hbool uninit;     /* Undefined, may trap.  */
> +@end smallexample
> +
> +When zero-initializing a variable or field of hardened boolean type
> +(presumably held in static storage) the implied zero initializer gets
> +converted to @code{_Bool}, and then to the hardened boolean type, so
> +that the initial value is the hardened representation for @code{false}.
> +Using that value is well defined.  This is @emph{not} the case when
> +variables and fields of such types are uninitialized (presumably held in
> +automatic or dynamic storage): their values are indeterminate, and using
> +them invokes undefined behavior.  Using them may trap or not, depending
> +on the bits held in the storage (re)used for the variable, if any, and
> +on optimizations the compiler may perform on the grounds that using
> +uninitialized values invokes undefined behavior.

So, when -ftrivial-auto-var-init presents, what’s the behavior for the hardened 
Boolean auto variables? 
This might need to be documented and also handled correctly. 

thanks.

Qing

Reply via email to