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

Reply via email to