diff mbox series

[1/2] c++: -Wdangling-reference and empty class [PR115361]

Message ID 20240917211948.72205-1-jason@redhat.com
State New
Headers show
Series [1/2] c++: -Wdangling-reference and empty class [PR115361] | expand

Commit Message

Jason Merrill Sept. 17, 2024, 9:16 p.m. UTC
Tested x86_64-pc-linux-gnu.  Marek, any concerns?

-- 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


base-commit: a9f9391e1eeccb9d062b9e73ef27ac577b23ed64

Comments

Marek Polacek Sept. 17, 2024, 9:48 p.m. UTC | #1
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 mbox series

Patch

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();
 };