diff mbox

fix PR 33193, tighten argument types for __real and __image

Message ID 20101110201758.GP7991@nightcrawler
State New
Headers show

Commit Message

Nathan Froyd Nov. 10, 2010, 8:17 p.m. UTC
PR 33193 points out that __real and __imag accept unusual arguments: GCC
will happily generate code for __real of a struct and __real/__imag of a
pointer.  This seems somewhat odd and contrasts with the documentation:

  To extract the real part of a complex-valued expression exp, write
  __real__ exp. Likewise, use __imag__ to extract the imaginary part.

The patch below tightens the checking for __real and __imag to complain
if the argument to __real or __imag is not of COMPLEX_TYPE, integer
type, or floating-point type.  The latter two are necessary for numerous
testcases to pass, and seem like a reasonable extension.

Tested on x86_64-unknown-linux-gnu.  OK to commit?

-Nathan

gcc/
	PR c/33193
	* c-typeck.c (build_unary_op): Call build_real_imag_expr for
	REALPART_EXPR and IMAGPART_EXPR.

gcc/c-family/
	PR c/33193
	* c-common.h (build_real_imag_expr): Declare.
	* c-semantics.c (build_real_imag_expr): Define.

gcc/cp/
	PR c/33193
	* typeck.c (cp_build_unary_op): Call build_real_imag_expr for
	REALPART_EXPR and IMAGPART_EXPR.

gcc/testsuite/
	PR c/33193
	* c-c++-common/pr33193.c: New test.

Comments

Joseph Myers Nov. 10, 2010, 8:52 p.m. UTC | #1
On Wed, 10 Nov 2010, Nathan Froyd wrote:

> gcc/
> 	PR c/33193
> 	* c-typeck.c (build_unary_op): Call build_real_imag_expr for
> 	REALPART_EXPR and IMAGPART_EXPR.
> 
> gcc/c-family/
> 	PR c/33193
> 	* c-common.h (build_real_imag_expr): Declare.
> 	* c-semantics.c (build_real_imag_expr): Define.

The C changes are OK.
Mark Mitchell Nov. 17, 2010, 2:15 a.m. UTC | #2
On 11/10/2010 12:52 PM, Joseph S. Myers wrote:

>> gcc/
>> 	PR c/33193
>> 	* c-typeck.c (build_unary_op): Call build_real_imag_expr for
>> 	REALPART_EXPR and IMAGPART_EXPR.
>>
>> gcc/c-family/
>> 	PR c/33193
>> 	* c-common.h (build_real_imag_expr): Declare.
>> 	* c-semantics.c (build_real_imag_expr): Define.
> 
> The C changes are OK.

Other changes are OK too.
diff mbox

Patch

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 58d3a32..abdbd9c 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -821,6 +821,7 @@  extern void warn_for_omitted_condop (location_t, tree);
 extern tree do_case (location_t, tree, tree);
 extern tree build_stmt (location_t, enum tree_code, ...);
 extern tree build_case_label (location_t, tree, tree, tree);
+extern tree build_real_imag_expr (location_t, enum tree_code, tree);
 
 /* These functions must be defined by each front-end which implements
    a variant of the C language.  They are used in c-common.c.  */
diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c
index 0eccd51..d26d871 100644
--- a/gcc/c-family/c-semantics.c
+++ b/gcc/c-family/c-semantics.c
@@ -140,3 +140,35 @@  build_case_label (location_t loc,
 {
   return build_stmt (loc, CASE_LABEL_EXPR, low_value, high_value, label_decl);
 }
+
+/* Build a REALPART_EXPR or IMAGPART_EXPR, according to CODE, from ARG.  */
+
+tree
+build_real_imag_expr (location_t location, enum tree_code code, tree arg)
+{
+  tree ret;
+  tree arg_type = TREE_TYPE (arg);
+
+  gcc_assert (code == REALPART_EXPR || code == IMAGPART_EXPR);
+
+  if (TREE_CODE (arg_type) == COMPLEX_TYPE)
+    {
+      ret = build1 (code, TREE_TYPE (TREE_TYPE (arg)), arg);
+      SET_EXPR_LOCATION (ret, location);
+    }
+  else if (INTEGRAL_TYPE_P (arg_type) || SCALAR_FLOAT_TYPE_P (arg_type))
+    {
+      ret = (code == REALPART_EXPR
+	     ? arg
+	     : omit_one_operand_loc (location, arg_type,
+				     integer_zero_node, arg));
+    }
+  else
+    {
+      error_at (location, "wrong type argument to %s",
+		code == REALPART_EXPR ? "__real" : "__imag");
+      ret = error_mark_node;
+    }
+
+  return ret;
+}
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 7f448dd..1a8e924 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -3561,26 +3561,10 @@  build_unary_op (location_t location,
       goto return_build_unary_op;
 
     case REALPART_EXPR:
-      if (TREE_CODE (arg) == COMPLEX_CST)
-	ret = TREE_REALPART (arg);
-      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-	ret = fold_build1_loc (location,
-			       REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
-      else
-	ret = arg;
-      if (eptype && TREE_CODE (eptype) == COMPLEX_TYPE)
-	eptype = TREE_TYPE (eptype);
-      goto return_build_unary_op;
-
     case IMAGPART_EXPR:
-      if (TREE_CODE (arg) == COMPLEX_CST)
-	ret = TREE_IMAGPART (arg);
-      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-	ret = fold_build1_loc (location,
-			       IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
-      else
-	ret = omit_one_operand_loc (location, TREE_TYPE (arg),
-				integer_zero_node, arg);
+      ret = build_real_imag_expr (location, code, arg);
+      if (ret == error_mark_node)
+	return error_mark_node;
       if (eptype && TREE_CODE (eptype) == COMPLEX_TYPE)
 	eptype = TREE_TYPE (eptype);
       goto return_build_unary_op;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index cad8817..91a5a9f 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -5098,26 +5098,12 @@  cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
       break;
 
     case REALPART_EXPR:
-      if (TREE_CODE (arg) == COMPLEX_CST)
-	return TREE_REALPART (arg);
-      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-	{
-	  arg = build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
-	  return fold_if_not_in_template (arg);
-	}
-      else
-	return arg;
-
     case IMAGPART_EXPR:
-      if (TREE_CODE (arg) == COMPLEX_CST)
-	return TREE_IMAGPART (arg);
-      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-	{
-	  arg = build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
-	  return fold_if_not_in_template (arg);
-	}
+      arg = build_real_imag_expr (input_location, code, arg);
+      if (arg == error_mark_node)
+	return arg;
       else
-	return cp_convert (TREE_TYPE (arg), integer_zero_node);
+	return fold_if_not_in_template (arg);
 
     case PREINCREMENT_EXPR:
     case POSTINCREMENT_EXPR:
diff --git a/gcc/testsuite/c-c++-common/pr33193.c b/gcc/testsuite/c-c++-common/pr33193.c
new file mode 100644
index 0000000..2d19298
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr33193.c
@@ -0,0 +1,19 @@ 
+/* PR c/33193 */
+/* { dg-do compile } */
+
+struct a {float x, y; };
+
+float f(struct a b)
+{
+  /* The error messages here are different between C and C++, so just
+     make sure we get an error.  */
+  float x = __real b;		/* { dg-error "" } */
+  float y = __imag b;		/* { dg-error "" } */
+  return x / y;
+}
+int f1(int *b)
+{
+  float x = __imag b;		/* { dg-error "wrong type argument" } */
+  float y = __real b;		/* { dg-error "wrong type argument" } */
+  return x - y;
+}