aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/typeck.c40
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/template/nontype11.C22
4 files changed, 55 insertions, 18 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index ddb1e99..bcb9d21 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2004-11-22 Giovanni Bajo <giovannibajo@gcc.gnu.org>
+
+ PR c++/18354
+ * typeck.c (build_unary_op) <CONVERT_EXPR, NEGATE_EXPR>: Unify code.
+ Make sure the result is always a rvalue.
+
2004-11-16 Giovanni Bajo <giovannibajo@gcc.gnu.org>
* decl.c (start_preparsed_function): Call check_function_type even
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index b1a85d5..4caf051 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -3741,26 +3741,30 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
switch (code)
{
+ /* CONVERT_EXPR stands for unary plus in this context. */
case CONVERT_EXPR:
- /* This is used for unary plus, because a CONVERT_EXPR
- is enough to prevent anybody from looking inside for
- associativity, but won't generate any code. */
- if (!(arg = build_expr_type_conversion
- (WANT_ARITH | WANT_ENUM | WANT_POINTER, arg, true)))
- errstring = "wrong type argument to unary plus";
- else
- {
- if (!noconvert)
- arg = default_conversion (arg);
- arg = build1 (NON_LVALUE_EXPR, TREE_TYPE (arg), arg);
- }
- break;
-
case NEGATE_EXPR:
- if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
- errstring = "wrong type argument to unary minus";
- else if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg)))
- arg = perform_integral_promotions (arg);
+ {
+ 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)
+ errstring = (code == NEGATE_EXPR
+ ? "wrong type argument to unary minus"
+ : "wrong type argument to unary plus");
+ else
+ {
+ if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+ arg = perform_integral_promotions (arg);
+
+ /* Make sure the result is not a lvalue: a unary plus or minus
+ expression is always a rvalue. */
+ if (real_lvalue_p (arg))
+ arg = build1 (NON_LVALUE_EXPR, TREE_TYPE (arg), arg);
+ }
+ }
break;
case BIT_NOT_EXPR:
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b9ec394..3601740 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2004-11-22 Giovanni Bajo <giovannibajo@gcc.gnu.org>
+
+ PR c++/18354
+ * g++.dg/template/nontype11.C: New test.
+
2004-11-21 Roger Sayle <roger@eyesopen.com>
PR middle-end/18520
diff --git a/gcc/testsuite/g++.dg/template/nontype11.C b/gcc/testsuite/g++.dg/template/nontype11.C
new file mode 100644
index 0000000..d52eb9a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/nontype11.C
@@ -0,0 +1,22 @@
+// { dg-do compile }
+// Origin: <fsm at robots dot ox dot ac dot uk>
+// PR c++/18354: Unary plus should not be wrapped in NON_LVALUE_EXPR
+
+template <int N>
+struct X { };
+
+const int n = 1;
+
+void f()
+{
+ X< 1> a;
+ X<-1> b;
+ X<+1> c;
+}
+
+void g()
+{
+ X< n> a;
+ X<-n> b;
+ X<+n> c;
+}