Message ID | 20230917185140.1333132-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: non-dependent assignment checking [PR63198, PR18474] | expand |
On 9/17/23 14:51, Patrick Palka wrote: > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > trunk? Patch generatde with -w to avoid noisy whitespace changes. > > -- >8 -- > > This patch makes us recognize and check non-dependent simple assigments > ahead of time, like we already do for compound assignments. This means > the templated representation of such assignments will now usually have > an implicit INDIRECT_REF (due to the reference return type), which the > -Wparentheses code needs to handle. As a drive-by improvement, this > patch also makes maybe_convert_cond issue -Wparentheses warnings ahead > of time. > > This revealed some libstdc++ tests were attempting to modify a data > member from a uninstantiated const member function; naively fixed by > making the data member mutable. > > PR c++/63198 > PR c++/18474 > > gcc/cp/ChangeLog: > > * semantics.cc (maybe_convert_cond): Look through implicit > INDIRECT_REF when deciding whether to issue a -Wparentheses > warning, and consider templated assignment expressions as well. > (finish_parenthesized_expr): Look through implicit INDIRECT_REF > when suppressing -Wparentheses warning. > * typeck.cc (build_x_modify_expr): Check simple assignments > ahead time too, not just compound assignments. Give the second > operand of MODOP_EXPR a non-null type so that it's not considered > always instantiation-dependent. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp0x/static_assert15.C: Expect diagnostic for > non-constant static_assert condition. > * g++.dg/expr/unary2.C: Remove xfails. > * g++.dg/template/init7.C: Make initializer type-dependent to > preserve intent of test. > * g++.dg/template/recurse3.C: Likewise for the erroneous > statement. > * g++.dg/template/non-dependent26.C: New test. > * g++.dg/warn/Wparentheses-32.C: New test. > > libstdc++/ChangeLog: > > * testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc: > Make seed_seq::called member mutable. > * testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc: > Likewise. > * testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc > Likewise. > * testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc: > Likewise. > * testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc: > Likewise. > * testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc: > Likewise. > * testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc > Likewise. > --- > gcc/cp/semantics.cc | 17 +++++++---- > gcc/cp/typeck.cc | 23 +++++++-------- > gcc/testsuite/g++.dg/cpp0x/static_assert15.C | 2 +- > gcc/testsuite/g++.dg/expr/unary2.C | 8 ++---- > gcc/testsuite/g++.dg/template/init7.C | 2 +- > .../g++.dg/template/non-dependent26.C | 25 +++++++++++++++++ > gcc/testsuite/g++.dg/template/recurse3.C | 8 +++--- > gcc/testsuite/g++.dg/warn/Wparentheses-32.C | 28 +++++++++++++++++++ > .../discard_block_engine/cons/seed_seq2.cc | 2 +- > .../independent_bits_engine/cons/seed_seq2.cc | 2 +- > .../cons/seed_seq2.cc | 2 +- > .../mersenne_twister_engine/cons/seed_seq2.cc | 2 +- > .../shuffle_order_engine/cons/seed_seq2.cc | 2 +- > .../cons/seed_seq2.cc | 2 +- > .../cons/seed_seq2.cc | 2 +- > 15 files changed, 91 insertions(+), 36 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent26.C > create mode 100644 gcc/testsuite/g++.dg/warn/Wparentheses-32.C > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > index 0f7f4e87ae4..b57c1ac868b 100644 > --- a/gcc/cp/semantics.cc > +++ b/gcc/cp/semantics.cc > diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc > index 459739d5866..74f5fced060 100644 > --- a/gcc/cp/typeck.cc > +++ b/gcc/cp/typeck.cc > @@ -9739,15 +9739,15 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, > rhs = build_non_dependent_expr (rhs); > } > > - if (modifycode != NOP_EXPR) > - { > - tree op = build_nt (modifycode, NULL_TREE, NULL_TREE); > - tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL, > + 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) > - { > if (rval == error_mark_node) > - return rval; > + return error_mark_node; > + if (modifycode != NOP_EXPR) > suppress_warning (rval /* What warning? */); Did you try disabling this to see if it's still needed? Jason
On Sun, 17 Sep 2023, Jason Merrill wrote: > On 9/17/23 14:51, Patrick Palka wrote: > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > > trunk? Patch generatde with -w to avoid noisy whitespace changes. > > > > -- >8 -- > > > > This patch makes us recognize and check non-dependent simple assigments > > ahead of time, like we already do for compound assignments. This means > > the templated representation of such assignments will now usually have > > an implicit INDIRECT_REF (due to the reference return type), which the > > -Wparentheses code needs to handle. As a drive-by improvement, this > > patch also makes maybe_convert_cond issue -Wparentheses warnings ahead > > of time. > > > > This revealed some libstdc++ tests were attempting to modify a data > > member from a uninstantiated const member function; naively fixed by > > making the data member mutable. > > > > PR c++/63198 > > PR c++/18474 > > > > gcc/cp/ChangeLog: > > > > * semantics.cc (maybe_convert_cond): Look through implicit > > INDIRECT_REF when deciding whether to issue a -Wparentheses > > warning, and consider templated assignment expressions as well. > > (finish_parenthesized_expr): Look through implicit INDIRECT_REF > > when suppressing -Wparentheses warning. > > * typeck.cc (build_x_modify_expr): Check simple assignments > > ahead time too, not just compound assignments. Give the second > > operand of MODOP_EXPR a non-null type so that it's not considered > > always instantiation-dependent. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/cpp0x/static_assert15.C: Expect diagnostic for > > non-constant static_assert condition. > > * g++.dg/expr/unary2.C: Remove xfails. > > * g++.dg/template/init7.C: Make initializer type-dependent to > > preserve intent of test. > > * g++.dg/template/recurse3.C: Likewise for the erroneous > > statement. > > * g++.dg/template/non-dependent26.C: New test. > > * g++.dg/warn/Wparentheses-32.C: New test. > > > > libstdc++/ChangeLog: > > > > * testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc: > > Make seed_seq::called member mutable. > > * > > testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc: > > Likewise. > > * > > testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc > > Likewise. > > * > > testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc: > > Likewise. > > * testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc: > > Likewise. > > * > > testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc: > > Likewise. > > * > > testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc > > Likewise. > > --- > > gcc/cp/semantics.cc | 17 +++++++---- > > gcc/cp/typeck.cc | 23 +++++++-------- > > gcc/testsuite/g++.dg/cpp0x/static_assert15.C | 2 +- > > gcc/testsuite/g++.dg/expr/unary2.C | 8 ++---- > > gcc/testsuite/g++.dg/template/init7.C | 2 +- > > .../g++.dg/template/non-dependent26.C | 25 +++++++++++++++++ > > gcc/testsuite/g++.dg/template/recurse3.C | 8 +++--- > > gcc/testsuite/g++.dg/warn/Wparentheses-32.C | 28 +++++++++++++++++++ > > .../discard_block_engine/cons/seed_seq2.cc | 2 +- > > .../independent_bits_engine/cons/seed_seq2.cc | 2 +- > > .../cons/seed_seq2.cc | 2 +- > > .../mersenne_twister_engine/cons/seed_seq2.cc | 2 +- > > .../shuffle_order_engine/cons/seed_seq2.cc | 2 +- > > .../cons/seed_seq2.cc | 2 +- > > .../cons/seed_seq2.cc | 2 +- > > 15 files changed, 91 insertions(+), 36 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent26.C > > create mode 100644 gcc/testsuite/g++.dg/warn/Wparentheses-32.C > > > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > > index 0f7f4e87ae4..b57c1ac868b 100644 > > --- a/gcc/cp/semantics.cc > > +++ b/gcc/cp/semantics.cc > > diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc > > index 459739d5866..74f5fced060 100644 > > --- a/gcc/cp/typeck.cc > > +++ b/gcc/cp/typeck.cc > > @@ -9739,15 +9739,15 @@ build_x_modify_expr (location_t loc, tree lhs, enum > > tree_code modifycode, > > rhs = build_non_dependent_expr (rhs); > > } > > - if (modifycode != NOP_EXPR) > > - { > > - tree op = build_nt (modifycode, NULL_TREE, NULL_TREE); > > - tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL, > > + 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) > > - { > > if (rval == error_mark_node) > > - return rval; > > + return error_mark_node; > > + if (modifycode != NOP_EXPR) > > suppress_warning (rval /* What warning? */); > > Did you try disabling this to see if it's still needed? Looks like it's not needed as far as bootstrap + regtest is concerned. FWIW this line originally was added in https://gcc.gnu.org/pipermail/gcc-patches/2004-July/144621.html to suppress -Wparentheses warnings for non-templated compound assignment operator expressions. Here's a patch that also gets rid of that suppress_warning call: -- >8 -- Subject: [PATCH] c++: non-dependent assignment checking [PR63198, PR18474] PR c++/63198 PR c++/18474 gcc/cp/ChangeLog: * semantics.cc (maybe_convert_cond): Look through implicit INDIRECT_REF when deciding whether to issue a -Wparentheses warning, and consider templated assignment expressions as well. (finish_parenthesized_expr): Look through implicit INDIRECT_REF when suppressing -Wparentheses warning. * typeck.cc (build_x_modify_expr): Check simple assignments ahead time too, not just compound assignments. Give the second operand of MODOP_EXPR a non-null type so that it's not considered always instantiation-dependent. Don't call suppress_warning. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/static_assert15.C: Expect diagnostic for non-constant static_assert condition. * g++.dg/expr/unary2.C: Remove xfails. * g++.dg/template/init7.C: Make initializer type-dependent to preserve intent of test. * g++.dg/template/recurse3.C: Likewise for the erroneous statement. * g++.dg/template/non-dependent26.C: New test. * g++.dg/warn/Wparentheses-32.C: New test. libstdc++/ChangeLog: * testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc: Make data member seed_seq::called mutable. * testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc: Likewise. * testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc Likewise. * testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc: Likewise. * testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc: Likewise. * testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc: Likewise. * testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc Likewise. --- gcc/cp/semantics.cc | 19 ++++++--- gcc/cp/typeck.cc | 41 ++++++++----------- gcc/testsuite/g++.dg/cpp0x/static_assert15.C | 2 +- gcc/testsuite/g++.dg/expr/unary2.C | 8 ++-- gcc/testsuite/g++.dg/template/init7.C | 2 +- .../g++.dg/template/non-dependent26.C | 25 +++++++++++ gcc/testsuite/g++.dg/template/recurse3.C | 8 ++-- gcc/testsuite/g++.dg/warn/Wparentheses-32.C | 28 +++++++++++++ .../discard_block_engine/cons/seed_seq2.cc | 2 +- .../independent_bits_engine/cons/seed_seq2.cc | 2 +- .../cons/seed_seq2.cc | 2 +- .../mersenne_twister_engine/cons/seed_seq2.cc | 2 +- .../shuffle_order_engine/cons/seed_seq2.cc | 2 +- .../cons/seed_seq2.cc | 2 +- .../cons/seed_seq2.cc | 2 +- 15 files changed, 100 insertions(+), 47 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/non-dependent26.C create mode 100644 gcc/testsuite/g++.dg/warn/Wparentheses-32.C diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 0f7f4e87ae4..4109ac33654 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 459739d5866..8132bd7fccc 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 a740f73fd4a..d5f50d07c91 100644 --- a/gcc/testsuite/g++.dg/cpp0x/static_assert15.C +++ b/gcc/testsuite/g++.dg/cpp0x/static_assert15.C @@ -5,6 +5,6 @@ template<int x> 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 5962bfe19c9..4db68375944 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 <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" "" } } diff --git a/gcc/testsuite/g++.dg/template/init7.C b/gcc/testsuite/g++.dg/template/init7.C index bb26c8f92b5..94fc22f578c 100644 --- a/gcc/testsuite/g++.dg/template/init7.C +++ b/gcc/testsuite/g++.dg/template/init7.C @@ -6,4 +6,4 @@ template<typename> struct A 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" } */ 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 00000000000..1faa39a4b1a --- /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<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" } +} diff --git a/gcc/testsuite/g++.dg/template/recurse3.C b/gcc/testsuite/g++.dg/template/recurse3.C index f1db7c5cbca..70c6152d063 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<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>(); } 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 00000000000..719a9d9e73a --- /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<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 *-*-* } } +} 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 720ce96dc28..0d7e667382d 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 f378621805f..2ef563038cc 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 c1cfe9da7fb..071ed75d8d8 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 52476026533..2fb9622fda0 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 1ca783e3044..3fa9c9ad8d3 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 08beb3bcf93..25d19a0ba66 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 b629053585e..fe798f2f05b 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
On 9/18/23 09:12, Patrick Palka wrote: > On Sun, 17 Sep 2023, Jason Merrill wrote: > >> On 9/17/23 14:51, Patrick Palka wrote: >>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for >>> trunk? Patch generatde with -w to avoid noisy whitespace changes. >>> >>> -- >8 -- >>> >>> This patch makes us recognize and check non-dependent simple assigments >>> ahead of time, like we already do for compound assignments. This means >>> the templated representation of such assignments will now usually have >>> an implicit INDIRECT_REF (due to the reference return type), which the >>> -Wparentheses code needs to handle. As a drive-by improvement, this >>> patch also makes maybe_convert_cond issue -Wparentheses warnings ahead >>> of time. >>> >>> This revealed some libstdc++ tests were attempting to modify a data >>> member from a uninstantiated const member function; naively fixed by >>> making the data member mutable. >>> >>> PR c++/63198 >>> PR c++/18474 >>> >>> gcc/cp/ChangeLog: >>> >>> * semantics.cc (maybe_convert_cond): Look through implicit >>> INDIRECT_REF when deciding whether to issue a -Wparentheses >>> warning, and consider templated assignment expressions as well. >>> (finish_parenthesized_expr): Look through implicit INDIRECT_REF >>> when suppressing -Wparentheses warning. >>> * typeck.cc (build_x_modify_expr): Check simple assignments >>> ahead time too, not just compound assignments. Give the second >>> operand of MODOP_EXPR a non-null type so that it's not considered >>> always instantiation-dependent. >>> >>> gcc/testsuite/ChangeLog: >>> >>> * g++.dg/cpp0x/static_assert15.C: Expect diagnostic for >>> non-constant static_assert condition. >>> * g++.dg/expr/unary2.C: Remove xfails. >>> * g++.dg/template/init7.C: Make initializer type-dependent to >>> preserve intent of test. >>> * g++.dg/template/recurse3.C: Likewise for the erroneous >>> statement. >>> * g++.dg/template/non-dependent26.C: New test. >>> * g++.dg/warn/Wparentheses-32.C: New test. >>> >>> libstdc++/ChangeLog: >>> >>> * testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc: >>> Make seed_seq::called member mutable. >>> * >>> testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc: >>> Likewise. >>> * >>> testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc >>> Likewise. >>> * >>> testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc: >>> Likewise. >>> * testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc: >>> Likewise. >>> * >>> testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc: >>> Likewise. >>> * >>> testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc >>> Likewise. >>> --- >>> gcc/cp/semantics.cc | 17 +++++++---- >>> gcc/cp/typeck.cc | 23 +++++++-------- >>> gcc/testsuite/g++.dg/cpp0x/static_assert15.C | 2 +- >>> gcc/testsuite/g++.dg/expr/unary2.C | 8 ++---- >>> gcc/testsuite/g++.dg/template/init7.C | 2 +- >>> .../g++.dg/template/non-dependent26.C | 25 +++++++++++++++++ >>> gcc/testsuite/g++.dg/template/recurse3.C | 8 +++--- >>> gcc/testsuite/g++.dg/warn/Wparentheses-32.C | 28 +++++++++++++++++++ >>> .../discard_block_engine/cons/seed_seq2.cc | 2 +- >>> .../independent_bits_engine/cons/seed_seq2.cc | 2 +- >>> .../cons/seed_seq2.cc | 2 +- >>> .../mersenne_twister_engine/cons/seed_seq2.cc | 2 +- >>> .../shuffle_order_engine/cons/seed_seq2.cc | 2 +- >>> .../cons/seed_seq2.cc | 2 +- >>> .../cons/seed_seq2.cc | 2 +- >>> 15 files changed, 91 insertions(+), 36 deletions(-) >>> create mode 100644 gcc/testsuite/g++.dg/template/non-dependent26.C >>> create mode 100644 gcc/testsuite/g++.dg/warn/Wparentheses-32.C >>> >>> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc >>> index 0f7f4e87ae4..b57c1ac868b 100644 >>> --- a/gcc/cp/semantics.cc >>> +++ b/gcc/cp/semantics.cc >>> diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc >>> index 459739d5866..74f5fced060 100644 >>> --- a/gcc/cp/typeck.cc >>> +++ b/gcc/cp/typeck.cc >>> @@ -9739,15 +9739,15 @@ build_x_modify_expr (location_t loc, tree lhs, enum >>> tree_code modifycode, >>> rhs = build_non_dependent_expr (rhs); >>> } >>> - if (modifycode != NOP_EXPR) >>> - { >>> - tree op = build_nt (modifycode, NULL_TREE, NULL_TREE); >>> - tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL, >>> + 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) >>> - { >>> if (rval == error_mark_node) >>> - return rval; >>> + return error_mark_node; >>> + if (modifycode != NOP_EXPR) >>> suppress_warning (rval /* What warning? */); >> >> Did you try disabling this to see if it's still needed? > > Looks like it's not needed as far as bootstrap + regtest is concerned. > FWIW this line originally was added in > https://gcc.gnu.org/pipermail/gcc-patches/2004-July/144621.html > to suppress -Wparentheses warnings for non-templated compound assignment > operator expressions. > > Here's a patch that also gets rid of that suppress_warning call: OK. > -- >8 -- > > Subject: [PATCH] c++: non-dependent assignment checking [PR63198, PR18474] > > PR c++/63198 > PR c++/18474 > > gcc/cp/ChangeLog: > > * semantics.cc (maybe_convert_cond): Look through implicit > INDIRECT_REF when deciding whether to issue a -Wparentheses > warning, and consider templated assignment expressions as well. > (finish_parenthesized_expr): Look through implicit INDIRECT_REF > when suppressing -Wparentheses warning. > * typeck.cc (build_x_modify_expr): Check simple assignments > ahead time too, not just compound assignments. Give the second > operand of MODOP_EXPR a non-null type so that it's not considered > always instantiation-dependent. Don't call suppress_warning. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp0x/static_assert15.C: Expect diagnostic for > non-constant static_assert condition. > * g++.dg/expr/unary2.C: Remove xfails. > * g++.dg/template/init7.C: Make initializer type-dependent to > preserve intent of test. > * g++.dg/template/recurse3.C: Likewise for the erroneous > statement. > * g++.dg/template/non-dependent26.C: New test. > * g++.dg/warn/Wparentheses-32.C: New test. > > libstdc++/ChangeLog: > > * testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc: > Make data member seed_seq::called mutable. > * testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc: > Likewise. > * testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc > Likewise. > * testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc: > Likewise. > * testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc: > Likewise. > * testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc: > Likewise. > * testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc > Likewise. > --- > gcc/cp/semantics.cc | 19 ++++++--- > gcc/cp/typeck.cc | 41 ++++++++----------- > gcc/testsuite/g++.dg/cpp0x/static_assert15.C | 2 +- > gcc/testsuite/g++.dg/expr/unary2.C | 8 ++-- > gcc/testsuite/g++.dg/template/init7.C | 2 +- > .../g++.dg/template/non-dependent26.C | 25 +++++++++++ > gcc/testsuite/g++.dg/template/recurse3.C | 8 ++-- > gcc/testsuite/g++.dg/warn/Wparentheses-32.C | 28 +++++++++++++ > .../discard_block_engine/cons/seed_seq2.cc | 2 +- > .../independent_bits_engine/cons/seed_seq2.cc | 2 +- > .../cons/seed_seq2.cc | 2 +- > .../mersenne_twister_engine/cons/seed_seq2.cc | 2 +- > .../shuffle_order_engine/cons/seed_seq2.cc | 2 +- > .../cons/seed_seq2.cc | 2 +- > .../cons/seed_seq2.cc | 2 +- > 15 files changed, 100 insertions(+), 47 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent26.C > create mode 100644 gcc/testsuite/g++.dg/warn/Wparentheses-32.C > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > index 0f7f4e87ae4..4109ac33654 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 459739d5866..8132bd7fccc 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 a740f73fd4a..d5f50d07c91 100644 > --- a/gcc/testsuite/g++.dg/cpp0x/static_assert15.C > +++ b/gcc/testsuite/g++.dg/cpp0x/static_assert15.C > @@ -5,6 +5,6 @@ template<int x> > 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 5962bfe19c9..4db68375944 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 <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" "" } > } > diff --git a/gcc/testsuite/g++.dg/template/init7.C b/gcc/testsuite/g++.dg/template/init7.C > index bb26c8f92b5..94fc22f578c 100644 > --- a/gcc/testsuite/g++.dg/template/init7.C > +++ b/gcc/testsuite/g++.dg/template/init7.C > @@ -6,4 +6,4 @@ template<typename> struct A > 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" } */ > 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 00000000000..1faa39a4b1a > --- /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<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" } > +} > diff --git a/gcc/testsuite/g++.dg/template/recurse3.C b/gcc/testsuite/g++.dg/template/recurse3.C > index f1db7c5cbca..70c6152d063 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<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>(); > } > 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 00000000000..719a9d9e73a > --- /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<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 *-*-* } } > +} > 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 720ce96dc28..0d7e667382d 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 f378621805f..2ef563038cc 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 c1cfe9da7fb..071ed75d8d8 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 52476026533..2fb9622fda0 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 1ca783e3044..3fa9c9ad8d3 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 08beb3bcf93..25d19a0ba66 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 b629053585e..fe798f2f05b 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
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 0f7f4e87ae4..b57c1ac868b 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)) + { + tree inner = REFERENCE_REF_P (expr) ? TREE_OPERAND (expr, 0) : *expr; /* This inhibits warnings in c_common_truthvalue_conversion. */ - suppress_warning (expr, OPT_Wparentheses); + 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 459739d5866..74f5fced060 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,15 +9739,15 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, rhs = build_non_dependent_expr (rhs); } - if (modifycode != NOP_EXPR) - { - tree op = build_nt (modifycode, NULL_TREE, NULL_TREE); - tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL, + 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) - { if (rval == error_mark_node) - return rval; + return error_mark_node; + if (modifycode != NOP_EXPR) suppress_warning (rval /* What warning? */); if (processing_template_decl) { @@ -9760,9 +9760,6 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, } return rval; } - } - return cp_build_modify_expr (loc, lhs, modifycode, rhs, complain); -} /* Helper function for get_delta_difference which assumes FROM is a base class of TO. Returns a delta for the conversion of pointer-to-member diff --git a/gcc/testsuite/g++.dg/cpp0x/static_assert15.C b/gcc/testsuite/g++.dg/cpp0x/static_assert15.C index a740f73fd4a..d5f50d07c91 100644 --- a/gcc/testsuite/g++.dg/cpp0x/static_assert15.C +++ b/gcc/testsuite/g++.dg/cpp0x/static_assert15.C @@ -5,6 +5,6 @@ template<int x> 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 5962bfe19c9..4db68375944 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 <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" "" } } diff --git a/gcc/testsuite/g++.dg/template/init7.C b/gcc/testsuite/g++.dg/template/init7.C index bb26c8f92b5..94fc22f578c 100644 --- a/gcc/testsuite/g++.dg/template/init7.C +++ b/gcc/testsuite/g++.dg/template/init7.C @@ -6,4 +6,4 @@ template<typename> struct A 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" } */ 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 00000000000..1faa39a4b1a --- /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<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" } +} diff --git a/gcc/testsuite/g++.dg/template/recurse3.C b/gcc/testsuite/g++.dg/template/recurse3.C index f1db7c5cbca..70c6152d063 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<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>(); } 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 00000000000..719a9d9e73a --- /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<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 *-*-* } } +} 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 720ce96dc28..0d7e667382d 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 f378621805f..2ef563038cc 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 c1cfe9da7fb..071ed75d8d8 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 52476026533..2fb9622fda0 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 1ca783e3044..3fa9c9ad8d3 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 08beb3bcf93..25d19a0ba66 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 b629053585e..fe798f2f05b 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