/* Do the conversion. */
cond = convert_from_reference (cond);
- if ((TREE_CODE (cond) == MODIFY_EXPR || is_assignment_op_expr_p (cond))
+ tree inner = REFERENCE_REF_P (cond) ? TREE_OPERAND (cond, 0) : cond;
+ if ((TREE_CODE (inner) == MODIFY_EXPR
+ || (TREE_CODE (inner) == MODOP_EXPR
+ && TREE_CODE (TREE_OPERAND (inner, 1)) == NOP_EXPR)
+ || is_assignment_op_expr_p (inner))
&& warn_parentheses
- && !warning_suppressed_p (cond, OPT_Wparentheses)
- && warning_at (cp_expr_loc_or_input_loc (cond),
+ && !warning_suppressed_p (inner, OPT_Wparentheses)
+ && warning_at (cp_expr_loc_or_input_loc (inner),
OPT_Wparentheses, "suggest parentheses around "
"assignment used as truth value"))
- suppress_warning (cond, OPT_Wparentheses);
+ suppress_warning (inner, OPT_Wparentheses);
return condition_conversion (cond);
}
finish_parenthesized_expr (cp_expr expr)
{
if (EXPR_P (expr))
- /* This inhibits warnings in c_common_truthvalue_conversion. */
- suppress_warning (expr, OPT_Wparentheses);
+ {
+ /* This inhibits warnings in c_common_truthvalue_conversion. */
+ tree inner = REFERENCE_REF_P (expr) ? TREE_OPERAND (expr, 0) : *expr;
+ suppress_warning (inner, OPT_Wparentheses);
+ }
if (TREE_CODE (expr) == OFFSET_REF
|| TREE_CODE (expr) == SCOPE_REF)
if (lhs == error_mark_node || rhs == error_mark_node)
return cp_expr (error_mark_node, loc);
+ tree op = build_min (modifycode, void_type_node, NULL_TREE, NULL_TREE);
+
if (processing_template_decl)
{
- if (modifycode == NOP_EXPR
- || type_dependent_expression_p (lhs)
+ if (type_dependent_expression_p (lhs)
|| type_dependent_expression_p (rhs))
{
- tree op = build_min_nt_loc (loc, modifycode, NULL_TREE, NULL_TREE);
tree rval = build_min_nt_loc (loc, MODOP_EXPR, lhs, op, rhs);
if (modifycode != NOP_EXPR)
TREE_TYPE (rval)
rhs = build_non_dependent_expr (rhs);
}
- if (modifycode != NOP_EXPR)
+ tree rval;
+ if (modifycode == NOP_EXPR)
+ rval = cp_build_modify_expr (loc, lhs, modifycode, rhs, complain);
+ else
+ rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL,
+ lhs, rhs, op, lookups, &overload, complain);
+ if (rval == error_mark_node)
+ return error_mark_node;
+ if (processing_template_decl)
{
- tree op = build_nt (modifycode, NULL_TREE, NULL_TREE);
- tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL,
- lhs, rhs, op, lookups, &overload, complain);
- if (rval)
- {
- if (rval == error_mark_node)
- return rval;
- suppress_warning (rval /* What warning? */);
- if (processing_template_decl)
- {
- if (overload != NULL_TREE)
- return (build_min_non_dep_op_overload
- (MODIFY_EXPR, rval, overload, orig_lhs, orig_rhs));
+ if (overload != NULL_TREE)
+ return (build_min_non_dep_op_overload
+ (MODIFY_EXPR, rval, overload, orig_lhs, orig_rhs));
- return (build_min_non_dep
- (MODOP_EXPR, rval, orig_lhs, op, orig_rhs));
- }
- return rval;
- }
+ return (build_min_non_dep
+ (MODOP_EXPR, rval, orig_lhs, op, orig_rhs));
}
- return cp_build_modify_expr (loc, lhs, modifycode, rhs, complain);
+ return rval;
}
/* Helper function for get_delta_difference which assumes FROM is a base
struct a {
constexpr void b() {
int c;
- static_assert(c %= 1, "");
+ static_assert(c %= 1, ""); // { dg-error "constant" }
}
};
+// PR c++/18474
// { dg-do compile }
// Unary plus/minus are not lvalues.
-// In templates we require an instantiation to emit the diagnostic. This
-// is wrong and it is PR 18474.
-
int n;
void f(void)
template <int>
void g(void)
{
- -n = 0; // { dg-error "lvalue" "" { xfail *-*-* } }
- +n = 0; // { dg-error "lvalue" "" { xfail *-*-* } }
+ -n = 0; // { dg-error "lvalue" "" }
+ +n = 0; // { dg-error "lvalue" "" }
}
static const int i=0;
};
-template<typename T> const int A<T>::i = 0=0; /* { dg-error "duplicate initialization" } */
+template<typename T> const int A<T>::i = T()=0; /* { dg-error "duplicate initialization" } */
--- /dev/null
+// Verify non-dependent assignment expressions are recognized as such
+// and are checked ahead of time.
+// PR c++/63198
+// { dg-do compile { target c++11 } }
+
+struct X { using t1 = int; };
+struct Y { X operator=(const Y&); } y;
+template<class T> void f1(decltype(y = y)::t1);
+
+int n;
+template<class T> void f2(decltype(n = n)::t1); // { dg-error "not a class" }
+template<class T> void f3(decltype(n += n)::t1); // { dg-error "not a class" }
+
+template<class T>
+void g() {
+ const int n;
+ n = 42; // { dg-error "read-only" }
+
+ const X x;
+ x = {}; // { dg-error "no match" }
+
+ const Y y;
+ y = {}; // { dg-error "no match" }
+ Y{} = X{}; // { dg-error "no match" }
+}
// PR c++/44609
// { dg-options -ftemplate-depth=10 }
-template<int N>
+template<class T, int N>
void f()
{
- 0 = 0; // { dg-error "lvalue required" }
- f<N+1>(); // { dg-bogus "instantiation depth" }
+ T(0) = 0; // { dg-error "lvalue required" }
+ f<T, N+1>(); // { dg-bogus "instantiation depth" }
}
int main()
{
- f<0>();
+ f<int, 0>();
}
--- /dev/null
+// Verify we issue -Wparentheses warnings at template definition time
+// (for suitable non-dependent expressions).
+// { dg-additional-options "-Wparentheses" }
+
+struct X { operator bool(); };
+struct Y { Y& operator=(const Y&); operator bool(); };
+struct Z { int m; operator bool(); };
+
+template<class T>
+void f() {
+ int n, m;
+ if (n = m) { } // { dg-warning "parentheses" }
+
+ X x1, x2;
+ if (x1 = x2) { } // { dg-warning "parentheses" }
+
+ Y y1, y2;
+ if (y1 = y2) { } // { dg-warning "parentheses" }
+
+ Z z1, z2;
+ if (z1 = z2) { } // { dg-warning "parentheses" }
+
+ bool b;
+ b = m = n; // { dg-warning "parentheses" "" { xfail *-*-* } }
+ b = x1 = x2; // { dg-warning "parentheses" "" { xfail *-*-* } }
+ b = y1 = y2; // { dg-warning "parentheses" "" { xfail *-*-* } }
+ b = z1 = z2; // { dg-warning "parentheses" "" { xfail *-*-* } }
+}
// T is convertible to the engine's result_type:
operator T() const noexcept { return T(); }
- bool called = false;
+ mutable bool called = false;
};
using engine_type
// T is convertible to the engine's result_type:
operator T() const noexcept { return T(); }
- bool called = false;
+ mutable bool called = false;
};
using engine_type
// T is convertible to the engine's result_type:
operator T() const noexcept { return T(); }
- bool called = false;
+ mutable bool called = false;
};
using engine_type
// T is convertible to the engine's result_type:
operator T() const noexcept { return T(); }
- bool called = false;
+ mutable bool called = false;
};
using engine_type
// T is convertible to the engine's result_type:
operator T() const noexcept { return T(); }
- bool called = false;
+ mutable bool called = false;
};
using engine_type
// T is convertible to the engine's result_type:
operator T() const noexcept { return T(); }
- bool called = false;
+ mutable bool called = false;
};
using engine_type
// T is convertible to the engine's result_type:
operator T() const noexcept { return T(); }
- bool called = false;
+ mutable bool called = false;
};
using engine_type