From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 35E2B3858D38 for ; Sun, 17 Sep 2023 18:51:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 35E2B3858D38 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1694976707; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=h12+cnbEzoNd1BXcs6UCKjPbPxRPIoy0johq+D8aOX0=; b=bMhI93sJWGGb70I/5NXQlzGXd/67Kse94qtK40V7VrI7k8R3qpXRHmtkMJpf+M0g3WPbG7 M4qxOSILQOn8P7rS6RC+6ArCWvAxc+8wRt7ccu03N9kivDJv2qzmqQUfKJo2nEEO9GOnhV j+ACSzOVdD+RXWfaBRfHMPpW/2DQcjQ= Received: from mail-oo1-f69.google.com (mail-oo1-f69.google.com [209.85.161.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-457-1REGEKZrMIyGPf-B5zYauw-1; Sun, 17 Sep 2023 14:51:45 -0400 X-MC-Unique: 1REGEKZrMIyGPf-B5zYauw-1 Received: by mail-oo1-f69.google.com with SMTP id 006d021491bc7-5733fc73957so5552676eaf.1 for ; Sun, 17 Sep 2023 11:51:45 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1694976705; x=1695581505; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=h12+cnbEzoNd1BXcs6UCKjPbPxRPIoy0johq+D8aOX0=; b=DLleZSO8hEiDDlixymNe42dxw0qYBzfNQ0effL///QlHzXaPq1TtBvKiFS//8H+WW6 4nF4kO3f6yQ6SFiASZ9xu+21xT6HVYmTnnNCFCLCeBXrA8Rs2fX7tz3cTz3GKexkZjRR GLxxHYpNWT4CLDaQmTo7JLsmFjeKb97QhN3DSy8OYxw5F+9V+NAurEWu/wm7dn6TuNQL J62b3o3pDQA4XxkT2N/DvZ1twHyIDwoYegC8RPoKx+Ss8uB0EbKlwpUKSqCMx+mg3Gk2 ymENtK+HRKSOe5lZkVwpdbD5LahezOnFTPiAQd9xtWZ4b/CeaS7nzsPedM/JhVy7RPxZ ml9Q== X-Gm-Message-State: AOJu0YyhTEDoVpho6KFVVTT6s8Nm2VFdOj9AJKpD2xU5kCNaWe2USmaB tEwnFvtfhLUM3heJzIaosIrB05uWV8Y4YFSo5H3gFB2Ilr/KHGZOBQ2mt7/wn1jx6Y88hLjT7yJ r2bKm6gK8sA55xZE= X-Received: by 2002:a05:6870:c113:b0:1d0:f84f:40d with SMTP id f19-20020a056870c11300b001d0f84f040dmr8954872oad.34.1694976704834; Sun, 17 Sep 2023 11:51:44 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFZ+826y+ST4f+HIkfvh6ZtBbg16bGVmhU0AIWyYD+XKl/JreS6pj7Dx9OHYUX1lBPHXlMdIg== X-Received: by 2002:a05:6870:c113:b0:1d0:f84f:40d with SMTP id f19-20020a056870c11300b001d0f84f040dmr8954864oad.34.1694976704562; Sun, 17 Sep 2023 11:51:44 -0700 (PDT) Received: from localhost.localdomain (ool-457670bb.dyn.optonline.net. [69.118.112.187]) by smtp.gmail.com with ESMTPSA id e12-20020ad4418c000000b00647386a3234sm2507228qvp.85.2023.09.17.11.51.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 17 Sep 2023 11:51:44 -0700 (PDT) From: Patrick Palka To: gcc-patches@gcc.gnu.org Cc: jason@redhat.com, libstdc++@gcc.gnu.org, Patrick Palka Subject: [PATCH] c++: non-dependent assignment checking [PR63198, PR18474] Date: Sun, 17 Sep 2023 14:51:40 -0400 Message-ID: <20230917185140.1333132-1-ppalka@redhat.com> X-Mailer: git-send-email 2.42.0.216.gbda494f404 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-13.9 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: 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 @@ -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 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 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 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 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 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 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 +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 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 +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 -- 2.42.0.216.gbda494f404