On Fri, May 07, 2021 at 06:09:35PM +0200, David Lamparter wrote:
> The TYPE_MAIN_VARIANT() here was, for casts to a typedef'd type name,
> resulting in all information about the typedef's involvement getting
> lost.  This drops necessary information for warnings and can make them
> confusing or even misleading.  It also makes specialized warnings for
> unspecified-size system types (pid_t, uid_t, ...) impossible.

Any comments on this?  Anything I can do to move this forward?  Or is it
not suitable to be picked up?

Cheers,


-David

> [...]
>
> diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
> index fdc7bb6125c2..ba6014726a4b 100644
> --- a/gcc/c/c-typeck.c
> +++ b/gcc/c/c-typeck.c
> @@ -5876,6 +5876,7 @@ c_safe_function_type_cast_p (tree t1, tree t2)
>  tree
>  build_c_cast (location_t loc, tree type, tree expr)
>  {
> +  tree res_type, walk_type;
>    tree value;
>  
>    bool int_operands = EXPR_INT_CONST_OPERANDS (expr);
> @@ -5896,7 +5897,39 @@ build_c_cast (location_t loc, tree type, tree expr)
>    if (objc_is_object_ptr (type) && objc_is_object_ptr (TREE_TYPE (expr)))
>      return build1 (NOP_EXPR, type, expr);
>  
> +  /* Want to keep typedef information, but at the same time we need to strip
> +     qualifiers for a proper rvalue.  Unfortunately, we don't know if any
> +     qualifiers on a typedef are part of the typedef or were locally 
> supplied.
> +     So grab the original typedef and use that only if it has no qualifiers.
> +     cf. cast-typedef testcase */
> +
> +  res_type = NULL;
> +
> +  for (walk_type = type;
> +       walk_type && TYPE_NAME (walk_type)
> +      && TREE_CODE (TYPE_NAME (walk_type)) == TYPE_DECL;
> +       walk_type = DECL_ORIGINAL_TYPE (TYPE_NAME (walk_type)))
> +    {
> +      tree walk_unqual, orig_type, orig_decl;
> +
> +      walk_unqual = build_qualified_type (walk_type, TYPE_UNQUALIFIED);
> +
> +      orig_decl = lookup_name (TYPE_IDENTIFIER (walk_type));
> +      if (!orig_decl || TREE_CODE (orig_decl) != TYPE_DECL)
> +     continue;
> +      orig_type = TREE_TYPE (orig_decl);
> +
> +      if (walk_unqual == orig_type)
> +     {
> +       res_type = walk_unqual;
> +       break;
> +     }
> +    }
> +
>    type = TYPE_MAIN_VARIANT (type);
> +  if (!res_type)
> +    res_type = type;
> +  gcc_assert (TYPE_MAIN_VARIANT (res_type) == type);
>  
>    if (TREE_CODE (type) == ARRAY_TYPE)
>      {
> @@ -5924,7 +5957,7 @@ build_c_cast (location_t loc, tree type, tree expr)
>                "ISO C forbids casting nonscalar to the same type");
>  
>        /* Convert to remove any qualifiers from VALUE's type.  */
> -      value = convert (type, value);
> +      value = convert (res_type, value);
>      }
>    else if (TREE_CODE (type) == UNION_TYPE)
>      {
> @@ -6078,7 +6111,7 @@ build_c_cast (location_t loc, tree type, tree expr)
>                   " from %qT to %qT", otype, type);
>  
>        ovalue = value;
> -      value = convert (type, value);
> +      value = convert (res_type, value);
>  
>        /* Ignore any integer overflow caused by the cast.  */
>        if (TREE_CODE (value) == INTEGER_CST && !FLOAT_TYPE_P (otype))
> @@ -6114,7 +6147,7 @@ build_c_cast (location_t loc, tree type, tree expr)
>               && INTEGRAL_TYPE_P (TREE_TYPE (expr)))
>              || TREE_CODE (expr) == REAL_CST
>              || TREE_CODE (expr) == COMPLEX_CST)))
> -      value = build1 (NOP_EXPR, type, value);
> +      value = build1 (NOP_EXPR, res_type, value);
>  
>    /* If the expression has integer operands and so can occur in an
>       unevaluated part of an integer constant expression, ensure the
> diff --git a/gcc/testsuite/gcc.dg/cast-typedef.c 
> b/gcc/testsuite/gcc.dg/cast-typedef.c
> new file mode 100644
> index 000000000000..3058e5a0b190
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/cast-typedef.c
> @@ -0,0 +1,35 @@
> +/* Test cast <> typedef interactions */
> +/* Origin: David Lamparter <equi...@diac24.net> */
> +/* { dg-do compile } */
> +/* { dg-options "-Wconversion" } */
> +
> +typedef int typedefname;
> +typedef volatile int qual1;
> +typedef volatile typedefname qual2;
> +
> +extern int val;
> +extern void f2(unsigned char arg);
> +
> +void
> +f (void)
> +{
> +  /* -Wconversion just used to print out the actual type */
> +
> +  f2 ((typedefname) val); /* { dg-warning "typedefname" } */
> +  f2 ((volatile typedefname) val); /* { dg-warning "typedefname" } */
> +  f2 ((qual1) val); /* { dg-warning "int" } */
> +  f2 ((qual2) val); /* { dg-warning "typedefname" } */
> +
> +  /* { dg-bogus "volatile" "qualifiers should be stripped" { target { 
> "*-*-*" } } 19  } */
> +  /* { dg-bogus "volatile" "qualifiers should be stripped" { target { 
> "*-*-*" } } 20  } */
> +  /* { dg-bogus "volatile" "qualifiers should be stripped" { target { 
> "*-*-*" } } 21  } */
> +
> +  /* { dg-bogus "qual1" "typedef with qualifier should not be used" { target 
> { "*-*-*" } } 20  } */
> +  /* { dg-bogus "qual2" "typedef with qualifier should not be used" { target 
> { "*-*-*" } } 21  } */
> +
> +  /* shadow "typedefname" & make sure it's not used */
> +  typedef short typedefname;
> +  f2 ((qual2) val); /* { dg-warning "int" } */
> +
> +  /* { dg-bogus "typedefname" "retaining a shadowed typedef would be 
> confusing" { target { "*-*-*" } } 32 } */
> +}

Reply via email to