c++: avoid -Wdangling-reference for std::span-like classes [PR110358]
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<typename T> struct Span { T* data_; std::size len_; }; to be std::span-like, and not warning for them. Unlike the previous patch, this one considers a non-union class template that has a pointer data member and a trivial destructor as std::span-like. PR c++/110358 PR c++/109640 gcc/cp/ChangeLog: * call.cc (reference_like_class_p): Don't warn for std::span-like classes. gcc/ChangeLog: * doc/invoke.texi: Update -Wdangling-reference description. 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.
This commit is contained in:
parent
24d5e0bf19
commit
f2061b2a96
5 changed files with 125 additions and 0 deletions
|
@ -14082,6 +14082,24 @@ reference_like_class_p (tree ctype)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Avoid warning if CTYPE looks like std::span: it's a class template,
|
||||
has a T* member, and a trivial destructor. For example,
|
||||
|
||||
template<typename T>
|
||||
struct Span {
|
||||
T* data_;
|
||||
std::size len_;
|
||||
};
|
||||
|
||||
is considered std::span-like. */
|
||||
if (NON_UNION_CLASS_TYPE_P (ctype)
|
||||
&& CLASSTYPE_TEMPLATE_INSTANTIATION (ctype)
|
||||
&& TYPE_HAS_TRIVIAL_DESTRUCTOR (ctype))
|
||||
for (tree field = next_aggregate_field (TYPE_FIELDS (ctype));
|
||||
field; field = next_aggregate_field (DECL_CHAIN (field)))
|
||||
if (TYPE_PTR_P (TREE_TYPE (field)))
|
||||
return true;
|
||||
|
||||
/* Some classes, such as std::tuple, have the reference member in its
|
||||
(non-direct) base class. */
|
||||
if (dfs_walk_once (TYPE_BINFO (ctype), class_has_reference_member_p_r,
|
||||
|
|
|
@ -3916,6 +3916,20 @@ where @code{std::minmax} returns @code{std::pair<const int&, const int&>}, 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<typename T>
|
||||
struct Span @{
|
||||
T* data_;
|
||||
std::size len_;
|
||||
@};
|
||||
@end smallexample
|
||||
|
||||
as @code{std::span}-like; that is, the class is a non-union class template
|
||||
that has a pointer data member and a trivial destructor.
|
||||
|
||||
This warning is enabled by @option{-Wall}.
|
||||
|
||||
@opindex Wdelete-non-virtual-dtor
|
||||
|
|
24
gcc/testsuite/g++.dg/warn/Wdangling-reference18.C
Normal file
24
gcc/testsuite/g++.dg/warn/Wdangling-reference18.C
Normal file
|
@ -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 <typename T>
|
||||
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<int>;
|
||||
|
||||
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;
|
||||
}
|
25
gcc/testsuite/g++.dg/warn/Wdangling-reference19.C
Normal file
25
gcc/testsuite/g++.dg/warn/Wdangling-reference19.C
Normal file
|
@ -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 <typename T>
|
||||
struct Span {
|
||||
T* data_;
|
||||
int len_;
|
||||
~Span ();
|
||||
|
||||
[[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<int>;
|
||||
|
||||
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;
|
||||
}
|
44
gcc/testsuite/g++.dg/warn/Wdangling-reference20.C
Normal file
44
gcc/testsuite/g++.dg/warn/Wdangling-reference20.C
Normal file
|
@ -0,0 +1,44 @@
|
|||
// PR c++/109640
|
||||
// { dg-do compile { target c++20 } }
|
||||
// { dg-options "-Wdangling-reference" }
|
||||
// Don't warn for std::span-like classes.
|
||||
|
||||
#include <iterator>
|
||||
#include <span>
|
||||
|
||||
template <typename T>
|
||||
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 <typename T, std::size_t n>
|
||||
MySpan<T const> make_my_span(T const(&x)[n])
|
||||
{
|
||||
return MySpan(std::begin(x), n);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t n>
|
||||
std::span<T const> make_span(T const(&x)[n])
|
||||
{
|
||||
return std::span(std::begin(x), n);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int x[10]{};
|
||||
[[maybe_unused]] int const& y1{make_my_span(x)[0]};
|
||||
[[maybe_unused]] int const& y2{make_span(x)[0]};
|
||||
using T = int[10];
|
||||
[[maybe_unused]] int const& y3{make_my_span(T{})[0]}; // { dg-warning "dangling reference" }
|
||||
[[maybe_unused]] int const& y4{make_span(T{})[0]}; // { dg-warning "dangling reference" }
|
||||
}
|
Loading…
Add table
Reference in a new issue