@@ -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, walk_type;
tree value;
bool int_operands = EXPR_INT_CONST_OPERANDS (expr);
@@ -5836,7 +5837,37 @@ 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;
+ walk_type = type;
+
+ while (walk_type && TYPE_NAME (walk_type)
+ && TREE_CODE (TYPE_NAME (walk_type)) == TYPE_DECL)
+ {
+ tree orig_decl = lookup_name (TYPE_IDENTIFIER (walk_type));
+
+ if (!orig_decl || TREE_CODE (orig_decl) != TYPE_DECL)
+ break;
+
+ walk_type = TREE_TYPE (orig_decl);
+ if (TYPE_QUALS (walk_type) == TYPE_UNQUALIFIED)
+ {
+ res_type = walk_type;
+ break;
+ }
+
+ walk_type = DECL_ORIGINAL_TYPE (TYPE_NAME (walk_type));
+ }
+
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)
{
@@ -5864,7 +5895,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 +6049,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 +6085,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
new file mode 100644
@@ -0,0 +1,29 @@
+/* Test cast <> typedef interactions */
+/* Origin: David Lamparter <equinox@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 } */
+}