[RFC] Add UNARY_PLUS_EXPR to C++ front-end

Roger Sayle roger@eyesopen.com
Thu May 26 05:43:00 GMT 2005


The following is a request for comment, or more accurately a request
for help, from the C++ folks for a patch to introduce a new front-end
tree code for C++'s unary plus operator.

Currently the g++ front-end abuses the semantics of the middle-end's
CONVERT_EXPR tree code to represent unary plus.  This isn't an issue
for the C front-end, which also temporarily misuses CONVERT_EXPR for
the same reason, but the use of default conversions followed by a
call to fold_build1 means that we never actually allocate a node to
represent it.  In C++, however, the deferral of folding until after
template instantiation, means that in numerous places the front-end
must preserve and interpret CONVERT_EXPR as a unary plus instead of
as a conversion operator.

In an attempt to clean this up, and more accurately represent the
user source code in the front-end's trees, the following patch introduces
a new UNARY_PLUS_EXPR tree code identical to the one used by the Java
front-end.

Now for the catch.  There's always a catch!  The following patch
passes a full top-level "make -k check", but with a single new
regression in the g++ testsuite...

FAIL: g++.dg/template/nontype11.C (test for excess errors)

which fails due to the error message:

nontype11.C:14: error: '+1' is not a valid template argument for type
'int' because it is a non-constant expression


The problem is that at template instantiation time, we're not folding
UNARY_PLUS_EXPR of an INTEGER_CST to just an INTEGER_CST soon enough.
Unfortunately, my "g++ fu" isn't strong enough to work out which one
or two line change to the template instantiation code required to replace
UNARY_PLUS_EXPR with it's TREE_OPERAND (t, 0) at the appropriate point.
There are several places this could be done, but I thought I'd ask the
list and solicit help for this final piece.


As mentioned above, the following patch has been bootstrapped and
regression tested on an x86_64-unknown-linux-gnu, all default
languages, and regression tested with a top-level "make -k check"
with only a single new failure, as described above.  Although better
representation of C++ semantics in the front-end is already a g++
goal, this change is also part of/blocking a much larger middle-end
clean-up I've been working on.


Any advice?  Co-authors wanted.  Pretty please.



2005-05-25  Roger Sayle  <roger@eyesopen.com>

	* cp-tree.def (UNARY_PLUS_EXPR): New C++ unary tree code.
	* parser.c (cp_parser_unary_expression): Use UNARY_PLUS_EXPR instead
	of CONVERT_EXPR.
	(cp_parser_unary_expression): Likewise.
	* typeck.c (build_unary_op): Likewise.
	* call.c (add_builtin_candidate, build_new_op): Likewise.
	* error.c (dump_expr): Likewise.
	* pt.c (tsubst_copy, tsubst_copy_and_build): Likewise.
	* cp-gimplify.c (cp_gimplify_expr): Handle UNARY_PLUS_EXPR like a
	conversion, if the result and argument types differ.


Index: cp-tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.def,v
retrieving revision 1.101
diff -c -3 -p -r1.101 cp-tree.def
*** cp-tree.def	25 Apr 2005 19:03:36 -0000	1.101
--- cp-tree.def	24 May 2005 23:23:54 -0000
*************** DEFTREECODE (ALIGNOF_EXPR, "alignof_expr
*** 340,345 ****
--- 340,349 ----
     STMT_EXPR_STMT is the statement given by the expression.  */
  DEFTREECODE (STMT_EXPR, "stmt_expr", tcc_expression, 1)

+ /* Unary plus. Operand 0 is the expression to which the unary plus
+    is applied.  */
+ DEFTREECODE (UNARY_PLUS_EXPR, "unary_plus_expr", tcc_unary, 1)
+
  /*
  Local variables:
  mode:c
Index: parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.331
diff -c -3 -p -r1.331 parser.c
*** parser.c	19 May 2005 03:05:46 -0000	1.331
--- parser.c	24 May 2005 23:23:57 -0000
*************** cp_parser_unary_expression (cp_parser *p
*** 4873,4879 ****
  	  non_constant_p = (unary_operator == PREINCREMENT_EXPR
  			    ? "`++'" : "`--'");
  	  /* Fall through.  */
! 	case CONVERT_EXPR:
  	case NEGATE_EXPR:
  	case TRUTH_NOT_EXPR:
  	  expression = finish_unary_op_expr (unary_operator, cast_expression);
--- 4873,4879 ----
  	  non_constant_p = (unary_operator == PREINCREMENT_EXPR
  			    ? "`++'" : "`--'");
  	  /* Fall through.  */
! 	case UNARY_PLUS_EXPR:
  	case NEGATE_EXPR:
  	case TRUTH_NOT_EXPR:
  	  expression = finish_unary_op_expr (unary_operator, cast_expression);
*************** cp_parser_unary_operator (cp_token* toke
*** 4909,4915 ****
        return ADDR_EXPR;

      case CPP_PLUS:
!       return CONVERT_EXPR;

      case CPP_MINUS:
        return NEGATE_EXPR;
--- 4909,4915 ----
        return ADDR_EXPR;

      case CPP_PLUS:
!       return UNARY_PLUS_EXPR;

      case CPP_MINUS:
        return NEGATE_EXPR;
Index: typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.628
diff -c -3 -p -r1.628 typeck.c
*** typeck.c	17 May 2005 20:05:24 -0000	1.628
--- typeck.c	24 May 2005 23:23:59 -0000
*************** build_unary_op (enum tree_code code, tre
*** 3692,3704 ****

    switch (code)
      {
!     /* CONVERT_EXPR stands for unary plus in this context.  */
!     case CONVERT_EXPR:
      case NEGATE_EXPR:
        {
  	int flags = WANT_ARITH | WANT_ENUM;
  	/* Unary plus (but not unary minus) is allowed on pointers.  */
! 	if (code == CONVERT_EXPR)
  	  flags |= WANT_POINTER;
  	arg = build_expr_type_conversion (flags, arg, true);
  	if (!arg)
--- 3692,3703 ----

    switch (code)
      {
!     case UNARY_PLUS_EXPR:
      case NEGATE_EXPR:
        {
  	int flags = WANT_ARITH | WANT_ENUM;
  	/* Unary plus (but not unary minus) is allowed on pointers.  */
! 	if (code == UNARY_PLUS_EXPR)
  	  flags |= WANT_POINTER;
  	arg = build_expr_type_conversion (flags, arg, true);
  	if (!arg)
Index: call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.535
diff -c -3 -p -r1.535 call.c
*** call.c	23 Apr 2005 21:28:47 -0000	1.535
--- call.c	24 May 2005 23:24:00 -0000
*************** add_builtin_candidate (struct z_candidat
*** 1652,1658 ****
  	     T       operator+(T);
  	     T       operator-(T);  */

!     case CONVERT_EXPR: /* unary + */
        if (TREE_CODE (type1) == POINTER_TYPE)
  	break;
      case NEGATE_EXPR:
--- 1652,1658 ----
  	     T       operator+(T);
  	     T       operator-(T);  */

!     case UNARY_PLUS_EXPR: /* unary + */
        if (TREE_CODE (type1) == POINTER_TYPE)
  	break;
      case NEGATE_EXPR:
*************** build_new_op (enum tree_code code, int f
*** 3848,3854 ****
      case TRUTH_ORIF_EXPR:
        return cp_build_binary_op (code, arg1, arg2);

!     case CONVERT_EXPR:
      case NEGATE_EXPR:
      case BIT_NOT_EXPR:
      case TRUTH_NOT_EXPR:
--- 3848,3854 ----
      case TRUTH_ORIF_EXPR:
        return cp_build_binary_op (code, arg1, arg2);

!     case UNARY_PLUS_EXPR:
      case NEGATE_EXPR:
      case BIT_NOT_EXPR:
      case TRUTH_NOT_EXPR:
Index: error.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/error.c,v
retrieving revision 1.280
diff -c -3 -p -r1.280 error.c
*** error.c	24 Mar 2005 07:20:33 -0000	1.280
--- error.c	24 May 2005 23:24:00 -0000
*************** dump_expr (tree t, int flags)
*** 1511,1517 ****
        pp_cxx_right_bracket (cxx_pp);
        break;

!     case CONVERT_EXPR:
        if (TREE_TYPE (t) && VOID_TYPE_P (TREE_TYPE (t)))
  	{
  	  pp_cxx_left_paren (cxx_pp);
--- 1511,1517 ----
        pp_cxx_right_bracket (cxx_pp);
        break;

!     case UNARY_PLUS_EXPR:
        if (TREE_TYPE (t) && VOID_TYPE_P (TREE_TYPE (t)))
  	{
  	  pp_cxx_left_paren (cxx_pp);
Index: pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.997
diff -c -3 -p -r1.997 pt.c
*** pt.c	17 May 2005 20:05:18 -0000	1.997
--- pt.c	24 May 2005 23:24:03 -0000
*************** tsubst_copy (tree t, tree args, tsubst_f
*** 7802,7808 ****
      case TRUTH_NOT_EXPR:
      case BIT_NOT_EXPR:
      case ADDR_EXPR:
!     case CONVERT_EXPR:      /* Unary + */
      case SIZEOF_EXPR:
      case ALIGNOF_EXPR:
      case ARROW_EXPR:
--- 7802,7808 ----
      case TRUTH_NOT_EXPR:
      case BIT_NOT_EXPR:
      case ADDR_EXPR:
!     case UNARY_PLUS_EXPR:      /* Unary + */
      case SIZEOF_EXPR:
      case ALIGNOF_EXPR:
      case ARROW_EXPR:
*************** tsubst_copy_and_build (tree t,
*** 8483,8489 ****
      case BIT_NOT_EXPR:
      case ABS_EXPR:
      case TRUTH_NOT_EXPR:
!     case CONVERT_EXPR:  /* Unary + */
      case REALPART_EXPR:
      case IMAGPART_EXPR:
        return build_x_unary_op (TREE_CODE (t), RECUR (TREE_OPERAND (t, 0)));
--- 8483,8489 ----
      case BIT_NOT_EXPR:
      case ABS_EXPR:
      case TRUTH_NOT_EXPR:
!     case UNARY_PLUS_EXPR:  /* Unary + */
      case REALPART_EXPR:
      case IMAGPART_EXPR:
        return build_x_unary_op (TREE_CODE (t), RECUR (TREE_OPERAND (t, 0)));
Index: cp-gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-gimplify.c,v
retrieving revision 1.19
diff -c -3 -p -r1.19 cp-gimplify.c
*** cp-gimplify.c	25 Apr 2005 19:03:36 -0000	1.19
--- cp-gimplify.c	24 May 2005 23:24:03 -0000
*************** cp_gimplify_expr (tree *expr_p, tree *pr
*** 557,562 ****
--- 557,572 ----
        ret = GS_OK;
        break;

+     case UNARY_PLUS_EXPR:
+       {
+ 	tree arg = TREE_OPERAND (*expr_p, 0);
+ 	tree type = TREE_TYPE (*expr_p);
+ 	*expr_p = (TREE_TYPE (arg) != type) ? fold_convert (type, arg)
+ 					    : arg;
+ 	ret = GS_OK;
+       }
+       break;
+
      default:
        ret = c_gimplify_expr (expr_p, pre_p, post_p);
        break;

Roger
--



More information about the Gcc-patches mailing list