Hi, This patch fixes an issue in the C frontend wherein the result of a cast-expression sometimes retains the type qualifiers of the operand type. It is incorrect for a cast-expression to have a qualified type because cast-expressions are rvalues.
This incorrect semantics can be seen through use of the typeof() operator: const int x; typeof ((int) x) y = 0; /* y erroneously has the type const int */ y = 1; /* error */ const int x; typeof ((const int) x) y = 0; /* y erroneously has the type const int */ y = 1; /* error */ I think that in either of these two cases, y should have type int. Instead it currently has type const int because x's type qualifiers are retained "through" the cast-expression. Note that the current behavior is not only wrong, but inconsistently wrong: if one replaces "(int)" with "(long)" and "(const int)" with "(const long)" in the above examples then neither of them emit an error: const int x; typeof ((long) x) y = 0; /* y is a long */ y = 1; /* OK. */ const int x; typeof ((const long) x) y = 0; /* y is a long */ y = 1; /* OK. */ The wrong behavior is only observed when the unqualified operand type is equal to the unqualified new type. This patch makes the semantics of type-casting more consistent and more correct. All the patch does is to make sure that the FE calls convert() on the operand of the cast-expression even when the TYPE_MAIN_VARIANT of the operand type and that of the new type happen to be the same. Bootstrapped and regtested on x86_64-unknown-linux-gnu. No new testcase is added because an existing testcase already contains the important cases; the existing testcase is then adjusted to expect the new correct behavior. Is this patch OK for trunk? 2014-08-17 Patrick Palka ppa...@gcc.gnu.org * c-typeck.c (build_c_cast): Do a conversion even when the TYPE_MAIN_VARIANTs are the same. 2014-08-17 Patrick Palka ppa...@gcc.gnu.org * gcc.dg/pr13519-1.c: Adjust. --- gcc/c/c-typeck.c | 2 ++ gcc/testsuite/gcc.dg/pr13519-1.c | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 0ed92c6..e6745be 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -4947,6 +4947,8 @@ build_c_cast (location_t loc, tree type, tree expr) || TREE_CODE (type) == UNION_TYPE) pedwarn (loc, OPT_Wpedantic, "ISO C forbids casting nonscalar to the same type"); + + value = convert (type, value); } else if (TREE_CODE (type) == UNION_TYPE) { diff --git a/gcc/testsuite/gcc.dg/pr13519-1.c b/gcc/testsuite/gcc.dg/pr13519-1.c index 907165f..1117a0e 100644 --- a/gcc/testsuite/gcc.dg/pr13519-1.c +++ b/gcc/testsuite/gcc.dg/pr13519-1.c @@ -14,9 +14,9 @@ void fn(void) { __typeof__(n) a1; a1=0; } { __typeof__(c) a2; a2=0; } /* { dg-error "read-only" "correct error" } */ { __typeof__((int)n) a3; a3=0; } - { __typeof__((int)c) a4; a4=0; } /* { dg-bogus "read-only" "bogus error" { xfail *-*-* } } */ - { __typeof__((const int)n) a5; a5=0; } /* { dg-error "read-only" "correct error" { xfail *-*-* } } */ - { __typeof__((const int)c) a6; a6=0; } /* { dg-error "read-only" "correct error" } */ + { __typeof__((int)c) a4; a4=0; } /* { dg-bogus "read-only" "bogus error" } */ + { __typeof__((const int)n) a5; a5=0; } + { __typeof__((const int)c) a6; a6=0; } { __typeof__(0) a7; a7=0; } { __typeof__(1) a8; a8=0; } -- 2.1.0