On Wed, Oct 11, 2023 at 10:57:06AM +1100, Nathaniel Shead wrote:
> On Mon, Oct 09, 2023 at 04:10:20PM -0400, Jason Merrill wrote:
> > On 10/9/23 06:03, Nathaniel Shead wrote:
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu with
> > > GXX_TESTSUITE_STDS=98,11,14,17,20,23,26,impcx.
> > > 
> > > -- >8 --
> > > 
> > > This patch improves the errors given when casting from void* in C++26 to
> > > include the expected type if the type of the pointed-to object was
> > > not similar to the casted-to type.
> > > 
> > > It also ensures (for all standard modes) that void* casts are checked
> > > even for DECL_ARTIFICIAL declarations, such as lifetime-extended
> > > temporaries, and is only ignored for cases where we know it's OK (heap
> > > identifiers and source_location::current). This provides more accurate
> > > diagnostics when using the pointer and ensures that some other casts
> > > from void* are now correctly rejected.
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * constexpr.cc (is_std_source_location_current): New.
> > >   (cxx_eval_constant_expression): Only ignore cast from void* for
> > >   specific cases and improve other diagnostics.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >   * g++.dg/cpp0x/constexpr-cast4.C: New test.
> > > 
> > > Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
> > > ---
> > >   gcc/cp/constexpr.cc                          | 83 +++++++++++++++++---
> > >   gcc/testsuite/g++.dg/cpp0x/constexpr-cast4.C |  7 ++
> > >   2 files changed, 78 insertions(+), 12 deletions(-)
> > >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-cast4.C
> > > 
> > > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> > > index 0f948db7c2d..f38d541a662 100644
> > > --- a/gcc/cp/constexpr.cc
> > > +++ b/gcc/cp/constexpr.cc
> > > @@ -2301,6 +2301,36 @@ is_std_allocator_allocate (const constexpr_call 
> > > *call)
> > >             && is_std_allocator_allocate (call->fundef->decl));
> > >   }
> > > +/* Return true if FNDECL is std::source_location::current.  */
> > > +
> > > +static inline bool
> > > +is_std_source_location_current (tree fndecl)
> > > +{
> > > +  if (!decl_in_std_namespace_p (fndecl))
> > > +    return false;
> > > +
> > > +  tree name = DECL_NAME (fndecl);
> > > +  if (name == NULL_TREE || !id_equal (name, "current"))
> > > +    return false;
> > > +
> > > +  tree ctx = DECL_CONTEXT (fndecl);
> > > +  if (ctx == NULL_TREE || !CLASS_TYPE_P (ctx) || !TYPE_MAIN_DECL (ctx))
> > > +    return false;
> > > +
> > > +  name = DECL_NAME (TYPE_MAIN_DECL (ctx));
> > > +  return name && id_equal (name, "source_location");
> > > +}
> > > +
> > > +/* Overload for the above taking constexpr_call*.  */
> > > +
> > > +static inline bool
> > > +is_std_source_location_current (const constexpr_call *call)
> > > +{
> > > +  return (call
> > > +   && call->fundef
> > > +   && is_std_source_location_current (call->fundef->decl));
> > > +}
> > > +
> > >   /* Return true if FNDECL is __dynamic_cast.  */
> > >   static inline bool
> > > @@ -7850,33 +7880,62 @@ cxx_eval_constant_expression (const constexpr_ctx 
> > > *ctx, tree t,
> > >           if (TYPE_PTROB_P (type)
> > >               && TYPE_PTR_P (TREE_TYPE (op))
> > >               && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (op)))
> > > -     /* Inside a call to std::construct_at or to
> > > -        std::allocator<T>::{,de}allocate, we permit casting from void*
> > > +     /* Inside a call to std::construct_at,
> > > +        std::allocator<T>::{,de}allocate, or
> > > +        std::source_location::current, we permit casting from void*
> > >                  because that is compiler-generated code.  */
> > >               && !is_std_construct_at (ctx->call)
> > > -     && !is_std_allocator_allocate (ctx->call))
> > > +     && !is_std_allocator_allocate (ctx->call)
> > > +     && !is_std_source_location_current (ctx->call))
> > >             {
> > >               /* Likewise, don't error when casting from void* when OP is
> > >                  &heap uninit and similar.  */
> > >               tree sop = tree_strip_nop_conversions (op);
> > > -     if (TREE_CODE (sop) == ADDR_EXPR
> > > -         && VAR_P (TREE_OPERAND (sop, 0))
> > > -         && DECL_ARTIFICIAL (TREE_OPERAND (sop, 0)))
> > > +     tree decl = NULL_TREE;
> > > +     if (TREE_CODE (sop) == ADDR_EXPR)
> > > +       decl = TREE_OPERAND (sop, 0);
> > > +     if (decl
> > > +         && VAR_P (decl)
> > > +         && DECL_ARTIFICIAL (decl)
> > > +         && (DECL_NAME (decl) == heap_identifier
> > > +             || DECL_NAME (decl) == heap_uninit_identifier
> > > +             || DECL_NAME (decl) == heap_vec_identifier
> > > +             || DECL_NAME (decl) == heap_vec_uninit_identifier))
> > >                 /* OK */;
> > >               /* P2738 (C++26): a conversion from a prvalue P of type 
> > > "pointer to
> > >                  cv void" to a pointer-to-object type T unless P points 
> > > to an
> > >                  object whose type is similar to T.  */
> > > -     else if (cxx_dialect > cxx23
> > > -              && (sop = cxx_fold_indirect_ref (ctx, loc,
> > > -                                               TREE_TYPE (type), sop)))
> > > +     else if (cxx_dialect > cxx23)
> > >                 {
> > > -         r = build1 (ADDR_EXPR, type, sop);
> > > -         break;
> > > +         r = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (type), sop);
> > > +         if (r)
> > > +           {
> > > +             r = build1 (ADDR_EXPR, type, r);
> > > +             break;
> > > +           }
> > > +         if (!ctx->quiet)
> > > +           {
> > > +             if (TREE_CODE (sop) == ADDR_EXPR)
> > > +               {
> > > +                 error_at (loc, "cast from %qT is not allowed because "
> > > +                           "pointed-to type %qT is not similar to %qT",
> > > +                           TREE_TYPE (op), TREE_TYPE (TREE_TYPE (sop)),
> > > +                           TREE_TYPE (type));
> > > +                 tree obj = build_fold_indirect_ref (sop);
> > > +                 inform (DECL_SOURCE_LOCATION (obj),
> > > +                         "pointed-to object declared here");
> > > +               }
> > > +             else
> > > +               error_at (loc, "cast from %qT is not allowed",
> > 
> > Can this be more helpful as well, i.e. say because op is not the address of
> > an object of similar type?
> > 
> > Can we only get here if op is null, since we would have returned already for
> > non-constant op?
> > 
> > Jason
> > 
> 
> Hm, yes; I'd kept the error as it was because I wasn't sure what other
> kinds of trees might end up here, but I've done a fair amount of testing
> and I've only been able to reach here with null pointers: everything
> else gets caught earlier. I've updated the error message appropriately
> and documented this assumption with an assertion.
> 
> Bootstrapped + regtested on x86_64-pc-linux-gnu as above.
> 
> -- >8 --
> 
> This patch improves the errors given when casting from void* in C++26 to
> include the expected type if the types of the pointed-to objects were
> not similar. It also ensures (for all standard modes) that void* casts
> are checked even for DECL_ARTIFICIAL declarations, such as
> lifetime-extended temporaries, and is only ignored for cases where we
> know it's OK (e.g. source_location::current) or have no other choice
> (heap-allocated data).
> 
> gcc/cp/ChangeLog:
> 
>       * constexpr.cc (is_std_source_location_current): New.
>       (cxx_eval_constant_expression): Only ignore cast from void* for
>       specific cases and improve other diagnostics.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/cpp0x/constexpr-cast4.C: New test.
> 
> Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
> ---
>  gcc/cp/constexpr.cc                          | 87 +++++++++++++++++---
>  gcc/testsuite/g++.dg/cpp0x/constexpr-cast4.C | 11 +++
>  2 files changed, 86 insertions(+), 12 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-cast4.C
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index 0f948db7c2d..d060e374cb3 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -2301,6 +2301,36 @@ is_std_allocator_allocate (const constexpr_call *call)
>         && is_std_allocator_allocate (call->fundef->decl));
>  }
>  
> +/* Return true if FNDECL is std::source_location::current.  */
> +
> +static inline bool
> +is_std_source_location_current (tree fndecl)
> +{
> +  if (!decl_in_std_namespace_p (fndecl))
> +    return false;
> +
> +  tree name = DECL_NAME (fndecl);
> +  if (name == NULL_TREE || !id_equal (name, "current"))
> +    return false;
> +
> +  tree ctx = DECL_CONTEXT (fndecl);
> +  if (ctx == NULL_TREE || !CLASS_TYPE_P (ctx) || !TYPE_MAIN_DECL (ctx))
> +    return false;
> +
> +  name = DECL_NAME (TYPE_MAIN_DECL (ctx));
> +  return name && id_equal (name, "source_location");
> +}
> +
> +/* Overload for the above taking constexpr_call*.  */
> +
> +static inline bool
> +is_std_source_location_current (const constexpr_call *call)
> +{
> +  return (call
> +       && call->fundef
> +       && is_std_source_location_current (call->fundef->decl));
> +}
> +
>  /* Return true if FNDECL is __dynamic_cast.  */
>  
>  static inline bool
> @@ -7850,33 +7880,66 @@ cxx_eval_constant_expression (const constexpr_ctx 
> *ctx, tree t,
>       if (TYPE_PTROB_P (type)
>           && TYPE_PTR_P (TREE_TYPE (op))
>           && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (op)))
> -         /* Inside a call to std::construct_at or to
> -            std::allocator<T>::{,de}allocate, we permit casting from void*
> +         /* Inside a call to std::construct_at,
> +            std::allocator<T>::{,de}allocate, or
> +            std::source_location::current, we permit casting from void*
>              because that is compiler-generated code.  */
>           && !is_std_construct_at (ctx->call)
> -         && !is_std_allocator_allocate (ctx->call))
> +         && !is_std_allocator_allocate (ctx->call)
> +         && !is_std_source_location_current (ctx->call))
>         {
>           /* Likewise, don't error when casting from void* when OP is
>              &heap uninit and similar.  */
>           tree sop = tree_strip_nop_conversions (op);
> -         if (TREE_CODE (sop) == ADDR_EXPR
> -             && VAR_P (TREE_OPERAND (sop, 0))
> -             && DECL_ARTIFICIAL (TREE_OPERAND (sop, 0)))
> +         tree decl = NULL_TREE;
> +         if (TREE_CODE (sop) == ADDR_EXPR)
> +           decl = TREE_OPERAND (sop, 0);
> +         if (decl
> +             && VAR_P (decl)
> +             && DECL_ARTIFICIAL (decl)
> +             && (DECL_NAME (decl) == heap_identifier
> +                 || DECL_NAME (decl) == heap_uninit_identifier
> +                 || DECL_NAME (decl) == heap_vec_identifier
> +                 || DECL_NAME (decl) == heap_vec_uninit_identifier))
>             /* OK */;
>           /* P2738 (C++26): a conversion from a prvalue P of type "pointer to
>              cv void" to a pointer-to-object type T unless P points to an
>              object whose type is similar to T.  */
> -         else if (cxx_dialect > cxx23
> -                  && (sop = cxx_fold_indirect_ref (ctx, loc,
> -                                                   TREE_TYPE (type), sop)))
> +         else if (cxx_dialect > cxx23)
>             {
> -             r = build1 (ADDR_EXPR, type, sop);
> -             break;
> +             r = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (type), sop);
> +             if (r)
> +               {
> +                 r = build1 (ADDR_EXPR, type, r);
> +                 break;
> +               }
> +             if (!ctx->quiet)
> +               {
> +                 if (TREE_CODE (sop) == ADDR_EXPR)
> +                   {

A very minor point (sorry), but I think you want

  auto_diagnostic_group d;

here.  Not need to repost the patch only because of this.

> +                     error_at (loc, "cast from %qT is not allowed because "
> +                               "pointed-to type %qT is not similar to %qT",
> +                               TREE_TYPE (op), TREE_TYPE (TREE_TYPE (sop)),
> +                               TREE_TYPE (type));
> +                     tree obj = build_fold_indirect_ref (sop);
> +                     inform (DECL_SOURCE_LOCATION (obj),
> +                             "pointed-to object declared here");
> +                   }

Marek

Reply via email to