On Wed, Apr 28, 2021 at 8:54 AM Andreas Krebbel via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> The problem appears to be triggered by two locations in the front-end
> where non-POINTER_SIZE pointers aren't handled right now.
>
> 1. An assertion in strip_typedefs is triggered because the alignment
> of the types don't match. This in turn is caused by creating the new
> type with build_pointer_type instead of taking the type of the
> original pointer into account.
>
> 2. An assertion in cp_convert_to_pointer is triggered which expects
> the target type to always have POINTER_SIZE.
>
> Ok for mainline?
>
> gcc/cp/ChangeLog:
>
>         PR c++/100281
>         * cvt.c (cp_convert_to_pointer): Use the size of the target
>         pointer type.
>         * tree.c (strip_typedefs): Use build_pointer_type_for_mode for
>         non-POINTER_SIZE pointers.
>
> gcc/testsuite/ChangeLog:
>
>         PR c++/100281
>         * g++.target/s390/pr100281.C: New test.
> ---
>  gcc/cp/cvt.c                             |  2 +-
>  gcc/cp/tree.c                            |  5 ++++-
>  gcc/testsuite/g++.target/s390/pr100281.C | 10 ++++++++++
>  3 files changed, 15 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.target/s390/pr100281.C
>
> diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
> index f1687e804d1..7fa6e8df52b 100644
> --- a/gcc/cp/cvt.c
> +++ b/gcc/cp/cvt.c
> @@ -232,7 +232,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold,
>      {
>        if (TYPE_PRECISION (intype) == POINTER_SIZE)
>         return build1 (CONVERT_EXPR, type, expr);
> -      expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 0), expr,
> +      expr = cp_convert (c_common_type_for_size (TYPE_PRECISION (type), 0), 
> expr,
>                          complain);
>        /* Modes may be different but sizes should be the same.  There
>          is supposed to be some integral type that is the same width
> diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
> index a8bfd5fc053..6f6b732c9c9 100644
> --- a/gcc/cp/tree.c
> +++ b/gcc/cp/tree.c
> @@ -1556,7 +1556,10 @@ strip_typedefs (tree t, bool *remove_attributes, 
> unsigned int flags)
>      {
>      case POINTER_TYPE:
>        type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);
> -      result = build_pointer_type (type);
> +      if (TYPE_PRECISION (t) == POINTER_SIZE)
> +       result = build_pointer_type (type);
> +      else
> +       result = build_pointer_type_for_mode (type, TYPE_MODE (t), false);

I wonder under which circumstances re-using the original mode will fail?  In
particular I do not like the TYPE_PRECISION check.  Supposedly you
were thinking of playing safe?

>        break;
>      case REFERENCE_TYPE:
>        type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);

There's code below with exactly the same issue for reference types which
would need adjustments to cp_build_reference_type.

> diff --git a/gcc/testsuite/g++.target/s390/pr100281.C 
> b/gcc/testsuite/g++.target/s390/pr100281.C
> new file mode 100644
> index 00000000000..f45798c3879
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/s390/pr100281.C
> @@ -0,0 +1,10 @@
> +// PR C++/100281
> +// { dg-do compile }
> +
> +typedef void * __attribute__((mode (SI))) __ptr32_t;
> +
> +void foo(){
> +  unsigned int b = 100;
> +  __ptr32_t a;
> +  a = b; /* { dg-error "invalid conversion from 'unsigned int' to 
> '__ptr32_t'.*" } */
> +}
> --
> 2.30.2
>

Reply via email to