diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 0f7f4e87ae424..4109ac33654ff 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -881,13 +881,17 @@ maybe_convert_cond (tree cond) /* 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); } @@ -2155,8 +2159,11 @@ cp_expr 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) diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 459739d5866b7..8132bd7fccc26 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -9721,13 +9721,13 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, 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) @@ -9739,29 +9739,24 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, 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 diff --git a/gcc/testsuite/g++.dg/cpp0x/static_assert15.C b/gcc/testsuite/g++.dg/cpp0x/static_assert15.C index a740f73fd4acd..d5f50d07c9159 100644 --- a/gcc/testsuite/g++.dg/cpp0x/static_assert15.C +++ b/gcc/testsuite/g++.dg/cpp0x/static_assert15.C @@ -5,6 +5,6 @@ template struct a { constexpr void b() { int c; - static_assert(c %= 1, ""); + static_assert(c %= 1, ""); // { dg-error "constant" } } }; diff --git a/gcc/testsuite/g++.dg/expr/unary2.C b/gcc/testsuite/g++.dg/expr/unary2.C index 5962bfe19c943..4db68375944dc 100644 --- a/gcc/testsuite/g++.dg/expr/unary2.C +++ b/gcc/testsuite/g++.dg/expr/unary2.C @@ -1,9 +1,7 @@ +// 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) @@ -15,6 +13,6 @@ void f(void) template 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" "" } } diff --git a/gcc/testsuite/g++.dg/template/init7.C b/gcc/testsuite/g++.dg/template/init7.C index bb26c8f92b5d6..94fc22f578c9f 100644 --- a/gcc/testsuite/g++.dg/template/init7.C +++ b/gcc/testsuite/g++.dg/template/init7.C @@ -6,4 +6,4 @@ template struct A static const int i=0; }; -template const int A::i = 0=0; /* { dg-error "duplicate initialization" } */ +template const int A::i = T()=0; /* { dg-error "duplicate initialization" } */ diff --git a/gcc/testsuite/g++.dg/template/non-dependent26.C b/gcc/testsuite/g++.dg/template/non-dependent26.C new file mode 100644 index 0000000000000..1faa39a4b1ae6 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent26.C @@ -0,0 +1,25 @@ +// 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 void f1(decltype(y = y)::t1); + +int n; +template void f2(decltype(n = n)::t1); // { dg-error "not a class" } +template void f3(decltype(n += n)::t1); // { dg-error "not a class" } + +template +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" } +} diff --git a/gcc/testsuite/g++.dg/template/recurse3.C b/gcc/testsuite/g++.dg/template/recurse3.C index f1db7c5cbca04..70c6152d0633a 100644 --- a/gcc/testsuite/g++.dg/template/recurse3.C +++ b/gcc/testsuite/g++.dg/template/recurse3.C @@ -1,14 +1,14 @@ // PR c++/44609 // { dg-options -ftemplate-depth=10 } -template +template void f() { - 0 = 0; // { dg-error "lvalue required" } - f(); // { dg-bogus "instantiation depth" } + T(0) = 0; // { dg-error "lvalue required" } + f(); // { dg-bogus "instantiation depth" } } int main() { - f<0>(); + f(); } diff --git a/gcc/testsuite/g++.dg/warn/Wparentheses-32.C b/gcc/testsuite/g++.dg/warn/Wparentheses-32.C new file mode 100644 index 0000000000000..719a9d9e73a99 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wparentheses-32.C @@ -0,0 +1,28 @@ +// 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 +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 *-*-* } } +} diff --git a/libstdc++-v3/testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc index 720ce96dc283f..0d7e667382d8b 100644 --- a/libstdc++-v3/testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc +++ b/libstdc++-v3/testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc @@ -51,7 +51,7 @@ struct seed_seq // 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 diff --git a/libstdc++-v3/testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc index f378621805f3e..2ef563038ccdd 100644 --- a/libstdc++-v3/testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc +++ b/libstdc++-v3/testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc @@ -51,7 +51,7 @@ struct seed_seq // 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 diff --git a/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc index c1cfe9da7fbc2..071ed75d8d85f 100644 --- a/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc +++ b/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc @@ -51,7 +51,7 @@ struct seed_seq // 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 diff --git a/libstdc++-v3/testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc index 5247602653359..2fb9622fda069 100644 --- a/libstdc++-v3/testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc +++ b/libstdc++-v3/testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc @@ -51,7 +51,7 @@ struct seed_seq // 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 diff --git a/libstdc++-v3/testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc index 1ca783e304494..3fa9c9ad8d349 100644 --- a/libstdc++-v3/testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc +++ b/libstdc++-v3/testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc @@ -51,7 +51,7 @@ struct seed_seq // 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 diff --git a/libstdc++-v3/testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc index 08beb3bcf93ab..25d19a0ba6602 100644 --- a/libstdc++-v3/testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc +++ b/libstdc++-v3/testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc @@ -51,7 +51,7 @@ struct seed_seq // 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 diff --git a/libstdc++-v3/testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc index b629053585eca..fe798f2f05be0 100644 --- a/libstdc++-v3/testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc +++ b/libstdc++-v3/testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc @@ -52,7 +52,7 @@ struct seed_seq // 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