Message ID | 20240917211948.72205-1-jason@redhat.com |
---|---|
State | New |
Headers | show |
Series | [1/2] c++: -Wdangling-reference and empty class [PR115361] | expand |
On Tue, Sep 17, 2024 at 05:16:47PM -0400, Jason Merrill wrote: > Tested x86_64-pc-linux-gnu. Marek, any concerns? LGTM, thanks. The ChangeLog may not pass the hook because it's missing some entries. > -- 8< -- > > We can't have a dangling reference to an empty class unless it's > specifically to that class or one of its bases. This was giving a > false positive on the _ExtractKey pattern in libstdc++ hashtable.h. > > This also adjusts the order of arguments to reference_related_p, which > is relevant for empty classes (unlike scalars). > > Several of the classes in the testsuite needed to gain data members to > continue to warn. > > PR c++/115361 > > gcc/cp/ChangeLog: > > * call.cc (do_warn_dangling_reference): Check is_empty_class. > > gcc/testsuite/ChangeLog: > > * g++.dg/ext/attr-no-dangling6.C: > * g++.dg/ext/attr-no-dangling7.C: > * g++.dg/ext/attr-no-dangling8.C: > * g++.dg/ext/attr-no-dangling9.C: > * g++.dg/warn/Wdangling-reference1.C: > * g++.dg/warn/Wdangling-reference2.C: > * g++.dg/warn/Wdangling-reference3.C: Make classes non-empty. > * g++.dg/warn/Wdangling-reference23.C: New test. > --- > gcc/cp/call.cc | 12 +++++++----- > gcc/testsuite/g++.dg/ext/attr-no-dangling6.C | 6 +++--- > gcc/testsuite/g++.dg/ext/attr-no-dangling7.C | 6 +++--- > gcc/testsuite/g++.dg/ext/attr-no-dangling8.C | 2 ++ > gcc/testsuite/g++.dg/ext/attr-no-dangling9.C | 1 + > gcc/testsuite/g++.dg/warn/Wdangling-reference1.C | 1 + > gcc/testsuite/g++.dg/warn/Wdangling-reference2.C | 2 +- > gcc/testsuite/g++.dg/warn/Wdangling-reference23.C | 14 ++++++++++++++ > gcc/testsuite/g++.dg/warn/Wdangling-reference3.C | 1 + > 9 files changed, 33 insertions(+), 12 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/warn/Wdangling-reference23.C > > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc > index 664088eed9c..1ecf3aac705 100644 > --- a/gcc/cp/call.cc > +++ b/gcc/cp/call.cc > @@ -14356,12 +14356,14 @@ do_warn_dangling_reference (tree expr, bool arg_p) > if ((arg = do_warn_dangling_reference (arg, /*arg_p=*/true))) > { > /* If we know the temporary could not bind to the return type, > - don't warn. This is for scalars only because for classes > - we can't be sure we are not returning its sub-object. */ > - if (SCALAR_TYPE_P (TREE_TYPE (arg)) > + don't warn. This is for scalars and empty classes only > + because for other classes we can't be sure we are not > + returning its sub-object. */ > + if ((SCALAR_TYPE_P (TREE_TYPE (arg)) > + || is_empty_class (TREE_TYPE (arg))) > && TYPE_REF_P (rettype) > - && !reference_related_p (TREE_TYPE (arg), > - TREE_TYPE (rettype))) > + && !reference_related_p (TREE_TYPE (rettype), > + TREE_TYPE (arg))) > continue; > return expr; > } > diff --git a/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C b/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C > index 5b349e8e682..1fc426d20d3 100644 > --- a/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C > +++ b/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C > @@ -2,9 +2,9 @@ > // { dg-do compile { target c++20 } } > // { dg-options "-Wdangling-reference" } > > -class X { }; > -const X x1; > -const X x2; > +class X { int i; }; > +const X x1 {}; > +const X x2 {}; > > constexpr bool val () { return true; } > struct ST { static constexpr bool value = true; }; > diff --git a/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C b/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C > index a5fb809e6bd..04c6badf0b6 100644 > --- a/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C > +++ b/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C > @@ -2,9 +2,9 @@ > // { dg-do compile { target c++20 } } > // { dg-options "-Wdangling-reference" } > > -class X { }; > -const X x1; > -const X x2; > +class X { int i; }; > +const X x1 {}; > +const X x2 {}; > > template<bool... N> > [[gnu::no_dangling(N)]] const X& get(const int& i); // { dg-error "parameter packs not expanded" } > diff --git a/gcc/testsuite/g++.dg/ext/attr-no-dangling8.C b/gcc/testsuite/g++.dg/ext/attr-no-dangling8.C > index 8208d751a4b..aa196315a38 100644 > --- a/gcc/testsuite/g++.dg/ext/attr-no-dangling8.C > +++ b/gcc/testsuite/g++.dg/ext/attr-no-dangling8.C > @@ -8,6 +8,7 @@ template<class T> constexpr bool is_reference_v<T&&> = true; > > template <typename T> > struct [[gnu::no_dangling(is_reference_v<T>)]] S { > + int i; > int &foo (const int &); > }; > > @@ -15,6 +16,7 @@ template <typename T1, typename T2> > struct X { > template <typename U1 = T1, typename U2 = T2> > struct [[gnu::no_dangling(is_reference_v<U1> && is_reference_v<U2>)]] Y { > + int i; > int &foo (const int &); > }; > }; > diff --git a/gcc/testsuite/g++.dg/ext/attr-no-dangling9.C b/gcc/testsuite/g++.dg/ext/attr-no-dangling9.C > index 65b4f7145a9..d7fd897de53 100644 > --- a/gcc/testsuite/g++.dg/ext/attr-no-dangling9.C > +++ b/gcc/testsuite/g++.dg/ext/attr-no-dangling9.C > @@ -12,6 +12,7 @@ using true_type = bool_constant<true>; > using false_type = bool_constant<false>; > > struct S { > + int i; > template<bool B> > [[gnu::no_dangling(B)]] int &foo (const int &); > }; > diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C > index 1718c28165e..a184317dd5c 100644 > --- a/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C > +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C > @@ -131,6 +131,7 @@ int n = 1; > const int& refmax = max(n - 1, n + 1); // { dg-warning "dangling reference" } > > struct Y { > + int i; > operator int&(); > operator int&&(); > const int& foo(const int&); > diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C > index dafdb43f1b9..a3d5ad6d867 100644 > --- a/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C > +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C > @@ -3,7 +3,7 @@ > // { dg-options "-Wdangling-reference" } > > namespace std { > -struct any {}; > +struct any { void *p; ~any(); }; > template <typename _ValueType> _ValueType any_cast(any &&); > template <typename _Tp> struct remove_reference { using type = _Tp; }; > template <typename _Tp> _Tp forward(typename remove_reference<_Tp>::type); > diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference23.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference23.C > new file mode 100644 > index 00000000000..e59ccc5057b > --- /dev/null > +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference23.C > @@ -0,0 +1,14 @@ > +// PR c++/115361 > +// { dg-additional-options -Wdangling-reference } > + > +struct B { int i; }; > + > +struct A { > + const int & operator()(const B& b) { return b.i; } > +}; > + > +int main() > +{ > + B b = {}; > + const int &r = A()(b); > +} > diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C > index 4bc20c13b3f..7db1dc86855 100644 > --- a/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C > +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C > @@ -18,6 +18,7 @@ struct G { > }; > > struct F { > + int i; > G& f(); > }; > > > base-commit: a9f9391e1eeccb9d062b9e73ef27ac577b23ed64 > -- > 2.46.0 > Marek
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 664088eed9c..1ecf3aac705 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -14356,12 +14356,14 @@ do_warn_dangling_reference (tree expr, bool arg_p) if ((arg = do_warn_dangling_reference (arg, /*arg_p=*/true))) { /* If we know the temporary could not bind to the return type, - don't warn. This is for scalars only because for classes - we can't be sure we are not returning its sub-object. */ - if (SCALAR_TYPE_P (TREE_TYPE (arg)) + don't warn. This is for scalars and empty classes only + because for other classes we can't be sure we are not + returning its sub-object. */ + if ((SCALAR_TYPE_P (TREE_TYPE (arg)) + || is_empty_class (TREE_TYPE (arg))) && TYPE_REF_P (rettype) - && !reference_related_p (TREE_TYPE (arg), - TREE_TYPE (rettype))) + && !reference_related_p (TREE_TYPE (rettype), + TREE_TYPE (arg))) continue; return expr; } diff --git a/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C b/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C index 5b349e8e682..1fc426d20d3 100644 --- a/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C +++ b/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C @@ -2,9 +2,9 @@ // { dg-do compile { target c++20 } } // { dg-options "-Wdangling-reference" } -class X { }; -const X x1; -const X x2; +class X { int i; }; +const X x1 {}; +const X x2 {}; constexpr bool val () { return true; } struct ST { static constexpr bool value = true; }; diff --git a/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C b/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C index a5fb809e6bd..04c6badf0b6 100644 --- a/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C +++ b/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C @@ -2,9 +2,9 @@ // { dg-do compile { target c++20 } } // { dg-options "-Wdangling-reference" } -class X { }; -const X x1; -const X x2; +class X { int i; }; +const X x1 {}; +const X x2 {}; template<bool... N> [[gnu::no_dangling(N)]] const X& get(const int& i); // { dg-error "parameter packs not expanded" } diff --git a/gcc/testsuite/g++.dg/ext/attr-no-dangling8.C b/gcc/testsuite/g++.dg/ext/attr-no-dangling8.C index 8208d751a4b..aa196315a38 100644 --- a/gcc/testsuite/g++.dg/ext/attr-no-dangling8.C +++ b/gcc/testsuite/g++.dg/ext/attr-no-dangling8.C @@ -8,6 +8,7 @@ template<class T> constexpr bool is_reference_v<T&&> = true; template <typename T> struct [[gnu::no_dangling(is_reference_v<T>)]] S { + int i; int &foo (const int &); }; @@ -15,6 +16,7 @@ template <typename T1, typename T2> struct X { template <typename U1 = T1, typename U2 = T2> struct [[gnu::no_dangling(is_reference_v<U1> && is_reference_v<U2>)]] Y { + int i; int &foo (const int &); }; }; diff --git a/gcc/testsuite/g++.dg/ext/attr-no-dangling9.C b/gcc/testsuite/g++.dg/ext/attr-no-dangling9.C index 65b4f7145a9..d7fd897de53 100644 --- a/gcc/testsuite/g++.dg/ext/attr-no-dangling9.C +++ b/gcc/testsuite/g++.dg/ext/attr-no-dangling9.C @@ -12,6 +12,7 @@ using true_type = bool_constant<true>; using false_type = bool_constant<false>; struct S { + int i; template<bool B> [[gnu::no_dangling(B)]] int &foo (const int &); }; diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C index 1718c28165e..a184317dd5c 100644 --- a/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C @@ -131,6 +131,7 @@ int n = 1; const int& refmax = max(n - 1, n + 1); // { dg-warning "dangling reference" } struct Y { + int i; operator int&(); operator int&&(); const int& foo(const int&); diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C index dafdb43f1b9..a3d5ad6d867 100644 --- a/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C @@ -3,7 +3,7 @@ // { dg-options "-Wdangling-reference" } namespace std { -struct any {}; +struct any { void *p; ~any(); }; template <typename _ValueType> _ValueType any_cast(any &&); template <typename _Tp> struct remove_reference { using type = _Tp; }; template <typename _Tp> _Tp forward(typename remove_reference<_Tp>::type); diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference23.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference23.C new file mode 100644 index 00000000000..e59ccc5057b --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference23.C @@ -0,0 +1,14 @@ +// PR c++/115361 +// { dg-additional-options -Wdangling-reference } + +struct B { int i; }; + +struct A { + const int & operator()(const B& b) { return b.i; } +}; + +int main() +{ + B b = {}; + const int &r = A()(b); +} diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C index 4bc20c13b3f..7db1dc86855 100644 --- a/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C @@ -18,6 +18,7 @@ struct G { }; struct F { + int i; G& f(); };