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.
gcc/c/ChangeLog: 2021-03-09 David Lamparter <equi...@diac24.net> * c-typeck.c (build_c_cast): retain (unqualified) typedefs in casts rather than stripping down to basic type. --- gcc/c/c-typeck.c | 11 +++++++---- gcc/testsuite/gcc.dg/cast-5.c | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/cast-5.c
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 4e6d369c4c9c..0f67753be4d7 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -5816,6 +5816,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; tree value; bool int_operands = EXPR_INT_CONST_OPERANDS (expr); @@ -5836,7 +5837,9 @@ 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); - type = TYPE_MAIN_VARIANT (type); + /* rvalue - retain typedefs w/o qualifier, but use actual type for checks */ + res_type = build_qualified_type (type, TYPE_UNQUALIFIED); + type = TYPE_MAIN_VARIANT (res_type); if (TREE_CODE (type) == ARRAY_TYPE) { @@ -5864,7 +5867,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) { @@ -6018,7 +6021,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)) @@ -6054,7 +6057,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-5.c b/gcc/testsuite/gcc.dg/cast-5.c new file mode 100644 index 000000000000..dcd9b290653d --- /dev/null +++ b/gcc/testsuite/gcc.dg/cast-5.c @@ -0,0 +1,19 @@ +/* Test cast <> typedef interactions */ +/* Origin: David Lamparter <equi...@diac24.net> */ +/* { dg-do compile } */ +/* { dg-options "-Wconversion" } */ + +typedef int typedefname; +typedef volatile int qualtypedefname; + +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 ((qualtypedefname) val); /* { dg-warning "qualtypedefname" } */ /* { dg-bogus "volatile" } */ +}