From patchwork Mon Jan 22 23:13:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 1889454 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=VehpZgwu; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4TJmJM2JX0z1yS7 for ; Tue, 23 Jan 2024 10:14:25 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 512973858D20 for ; Mon, 22 Jan 2024 23:14:23 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org 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 C749F3858D20 for ; Mon, 22 Jan 2024 23:14:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C749F3858D20 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org C749F3858D20 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1705965244; cv=none; b=qkiBEfZFCoYQBMeIQw9x6ePyR7LfCIXI23bv1Vn03tBKeKDuAP0PIxjFPjw/IwPnIAdzhfoli5kY6zPLqP98avSus8FwUPCY4XSdgjTRjdyRNzFZoX3xGqts1hRD/lvUp9Ih256VGMMeESR3ACp3IwZSuAPis1Q05Gppxq09yr0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1705965244; c=relaxed/simple; bh=07/nuNIyTp3Dh7yShgILanb6GTIAeU9poRZqSPQ510c=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=hc2EhRoH60WZKp2Bs9ww+WL3Hi8M1KTEgYy8c3+bsWIbuA7UCRB/lhDEqLhn8jeS5spw1iAgTcObs4uu/RT3BHS4YAqFkSyc0zfFqngFXhrffb/+/AJt+CHPdKknnvfCK7ThQ6hZJk8+jGhsrK1JYuTQ2LwN4ChbDlxsXdi8F7w= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1705965242; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=EH3ci15ZSDvKsnN7lZIJsLkD5llsikXZIX0vaCNIlCU=; b=VehpZgwuAGWNpVBfisC6G3U3QywZqF65TL9r2MapaW4L3PyjE+mVTXIVYJgqQu0YKfUNJh Jz9Sofex+sLH9nJSvevGlVfmOu2e9XxBvZL3r8KTweQzTyGw4j+1Iqn0cq49an/GUmbAxU c/FB1kN1cb2Egztcn6BkdNcGiQha0zw= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-561-tetZIbEvMYugYjlrdF1rHg-1; Mon, 22 Jan 2024 18:14:00 -0500 X-MC-Unique: tetZIbEvMYugYjlrdF1rHg-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 2F10885A588 for ; Mon, 22 Jan 2024 23:14:00 +0000 (UTC) Received: from pdp-11.lan (unknown [10.22.17.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0BC8A492BE4; Mon, 22 Jan 2024 23:14:00 +0000 (UTC) From: Marek Polacek To: Jason Merrill , GCC Patches Subject: [PATCH] c++: avoid -Wdangling-reference for std::span-like classes [PR110358] Date: Mon, 22 Jan 2024 18:13:51 -0500 Message-ID: <20240122231351.59259-1-polacek@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.10 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.6 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, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? -- >8 -- Real-world experience shows that -Wdangling-reference triggers for user-defined std::span-like classes a lot. We can easily avoid that by considering classes like template struct Span { T* data_; std::size len_; }; to be std::span-like, and not warning for them. PR c++/110358 PR c++/109640 gcc/cp/ChangeLog: * call.cc (span_like_class_p): New. (do_warn_dangling_reference): Use it. gcc/ChangeLog: * doc/invoke.texi: Update -Wdangling-reference documentation. gcc/testsuite/ChangeLog: * g++.dg/warn/Wdangling-reference18.C: New test. * g++.dg/warn/Wdangling-reference19.C: New test. * g++.dg/warn/Wdangling-reference20.C: New test. --- gcc/cp/call.cc | 38 ++++++++++++++++- gcc/doc/invoke.texi | 15 +++++++ .../g++.dg/warn/Wdangling-reference18.C | 24 +++++++++++ .../g++.dg/warn/Wdangling-reference19.C | 25 +++++++++++ .../g++.dg/warn/Wdangling-reference20.C | 42 +++++++++++++++++++ 5 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wdangling-reference18.C create mode 100644 gcc/testsuite/g++.dg/warn/Wdangling-reference19.C create mode 100644 gcc/testsuite/g++.dg/warn/Wdangling-reference20.C base-commit: c596ce03120cc22e141186401c6656009ddebdaa prerequisite-patch-id: 5929438e96b89b465c26c2fbd5b92d2444d1901d diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 77f51bacce3..d6bdb3cc9bd 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -14082,6 +14082,40 @@ reference_like_class_p (tree ctype) return false; } +/* Return true if class TYPE looks like std::span: it's a class template + and has a T* member followed by a field of integral type. For example, + + template + struct Span { + T* data_; + std::size len_; + }; + + is considered std::span-like. */ + +static bool +span_like_class_p (tree type) +{ + if (!NON_UNION_CLASS_TYPE_P (type) + || !CLASSTYPE_TEMPLATE_INSTANTIATION (type)) + return false; + + tree args = CLASSTYPE_TI_ARGS (type); + if (TREE_VEC_LENGTH (args) != 1) + return false; + + tree f = next_aggregate_field (TYPE_FIELDS (type)); + if (f && TYPE_PTR_P (TREE_TYPE (f))) + { + f = next_aggregate_field (DECL_CHAIN (f)); + if (f && INTEGRAL_TYPE_P (TREE_TYPE (f)) + && !next_aggregate_field (DECL_CHAIN (f))) + return true; + } + + return false; +} + /* Helper for maybe_warn_dangling_reference to find a problematic CALL_EXPR that initializes the LHS (and at least one of its arguments represents a temporary, as outlined in maybe_warn_dangling_reference), or NULL_TREE @@ -14126,7 +14160,9 @@ do_warn_dangling_reference (tree expr, bool arg_p) tree type = TREE_TYPE (e); /* If the temporary represents a lambda, we don't really know what's going on here. */ - if (!reference_like_class_p (type) && !LAMBDA_TYPE_P (type)) + if (!reference_like_class_p (type) + && !LAMBDA_TYPE_P (type) + && !span_like_class_p (type)) return expr; } diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 278c931b6a3..509779c8fd8 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -3914,6 +3914,21 @@ where @code{std::minmax} returns @code{std::pair}, and both references dangle after the end of the full expression that contains the call to @code{std::minmax}. +The warning does not warn for @code{std::span}-like classes. We consider +classes of the form: + +@smallexample +template +struct Span @{ + T* data_; + std::size len_; +@}; +@end smallexample + +as @code{std::span}-like; that is, the class is a class template that +has a pointer data member followed by an integral data member, and does +not have any other data members. + This warning is enabled by @option{-Wall}. @opindex Wdelete-non-virtual-dtor diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference18.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference18.C new file mode 100644 index 00000000000..e088c177769 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference18.C @@ -0,0 +1,24 @@ +// PR c++/110358 +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } +// Don't warn for std::span-like classes. + +template +struct Span { + T* data_; + int len_; + + [[nodiscard]] constexpr auto operator[](int n) const noexcept -> T& { return data_[n]; } + [[nodiscard]] constexpr auto front() const noexcept -> T& { return data_[0]; } + [[nodiscard]] constexpr auto back() const noexcept -> T& { return data_[len_ - 1]; } +}; + +auto get() -> Span; + +auto f() -> int { + int const& a = get().front(); // { dg-bogus "dangling reference" } + int const& b = get().back(); // { dg-bogus "dangling reference" } + int const& c = get()[0]; // { dg-bogus "dangling reference" } + + return a + b + c; +} diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference19.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference19.C new file mode 100644 index 00000000000..3f74ab701c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference19.C @@ -0,0 +1,25 @@ +// PR c++/110358 +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } +// Like Wdangling-reference18.C but not actually a span-like class. + +template +struct Span { + T* data_; + int len_; + T foo_; + + [[nodiscard]] constexpr auto operator[](int n) const noexcept -> T& { return data_[n]; } + [[nodiscard]] constexpr auto front() const noexcept -> T& { return data_[0]; } + [[nodiscard]] constexpr auto back() const noexcept -> T& { return data_[len_ - 1]; } +}; + +auto get() -> Span; + +auto f() -> int { + int const& a = get().front(); // { dg-warning "dangling reference" } + int const& b = get().back(); // { dg-warning "dangling reference" } + int const& c = get()[0]; // { dg-warning "dangling reference" } + + return a + b + c; +} diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference20.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference20.C new file mode 100644 index 00000000000..463c7380283 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference20.C @@ -0,0 +1,42 @@ +// PR c++/109640 +// { dg-do compile { target c++20 } } +// { dg-options "-Wdangling-reference" } +// Don't warn for std::span-like classes. + +#include +#include + +template +struct MySpan +{ + MySpan(T* data, std::size_t size) : + data_(data), + size_(size) + {} + + T& operator[](std::size_t idx) { return data_[idx]; } + +private: + T* data_; + std::size_t size_; +}; + +template +MySpan make_my_span(T const(&x)[n]) +{ + return MySpan(std::begin(x), n); +} + +template +std::span make_span(T const(&x)[n]) +{ + return std::span(std::begin(x), n); +} + +int main() +{ + int x[10]{}; + int const& y{make_my_span(x)[0]}; + int const& y2{make_span(x)[0]}; + (void) y, (void) y2; +}