Re: [PATCH] c++: implement [[gnu::non_owning]] [PR110358]

2024-01-26 Thread Jason Merrill

On 1/25/24 20:37, Marek Polacek wrote:

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
Since -Wdangling-reference has false positives that can't be
prevented, we should offer an easy way to suppress the warning.
Currently, that is only possible by using a #pragma, either around the
enclosing class or around the call site.  But #pragma GCC diagnostic tend
to be onerous.  A better solution would be to have an attribute.  Such
an attribute should not be tied to this particular warning though.  [*]

The warning bogusly triggers for classes that are like std::span,
std::reference_wrapper, and std::ranges::ref_view.  The common property
seems to be that these classes are only wrappers around some data.  So
I chose the name non_owning, but I'm not attached to it.  I hope that
in the future the attribute can be used for something other than this
diagnostic.


You decided not to pursue Barry's request for a bool argument to the 
attribute?


Might it be more useful for the attribute to make reference_like_class_p 
return true, so that we still warn about a temporary of another type 
passing through it?


Jason



Re: [PATCH] c++: implement [[gnu::non_owning]] [PR110358]

2024-01-25 Thread Marek Polacek
On Thu, Jan 25, 2024 at 08:37:36PM -0500, Marek Polacek wrote:
> +/* Handle a "non_owning" attribute; arguments as in
> +   struct attribute_spec.handler.  */
> +
> +tree
> +handle_non_owning_attribute (tree *node, tree name, tree args, int,
> +  bool *no_add_attrs)

I overlooked error: unused parameter 'args'.  Fixed.

Marek



[PATCH] c++: implement [[gnu::non_owning]] [PR110358]

2024-01-25 Thread Marek Polacek
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
Since -Wdangling-reference has false positives that can't be
prevented, we should offer an easy way to suppress the warning.
Currently, that is only possible by using a #pragma, either around the
enclosing class or around the call site.  But #pragma GCC diagnostic tend
to be onerous.  A better solution would be to have an attribute.  Such
an attribute should not be tied to this particular warning though.  [*]

The warning bogusly triggers for classes that are like std::span,
std::reference_wrapper, and std::ranges::ref_view.  The common property
seems to be that these classes are only wrappers around some data.  So
I chose the name non_owning, but I'm not attached to it.  I hope that
in the future the attribute can be used for something other than this
diagnostic.

[*] As I'm typing this, it's occurring to me that we might consider
having a general attribute allowing users to do [[gnu::ignore("-Wfoo")]].

PR c++/110358
PR c++/109642

gcc/cp/ChangeLog:

* call.cc (do_warn_dangling_reference): Don't warn when the function
or its enclosing class has attribute gnu::non_owning.
* tree.cc (cxx_gnu_attributes): Add gnu::non_owning.
(handle_non_owning_attribute): New.

gcc/ChangeLog:

* doc/extend.texi: Document gnu::non_owning.
* doc/invoke.texi: Mention that gnu::non_owning disables
-Wdangling-reference.

gcc/testsuite/ChangeLog:

* g++.dg/ext/attr-non-owning1.C: New test.
* g++.dg/ext/attr-non-owning2.C: New test.
* g++.dg/ext/attr-non-owning3.C: New test.
* g++.dg/ext/attr-non-owning4.C: New test.
* g++.dg/ext/attr-non-owning5.C: New test.
---
 gcc/cp/call.cc  |  9 -
 gcc/cp/tree.cc  | 20 +++
 gcc/doc/extend.texi | 15 
 gcc/doc/invoke.texi | 21 
 gcc/testsuite/g++.dg/ext/attr-non-owning1.C | 38 +
 gcc/testsuite/g++.dg/ext/attr-non-owning2.C | 28 +++
 gcc/testsuite/g++.dg/ext/attr-non-owning3.C | 24 +
 gcc/testsuite/g++.dg/ext/attr-non-owning4.C | 14 
 gcc/testsuite/g++.dg/ext/attr-non-owning5.C | 29 
 9 files changed, 197 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-non-owning1.C
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-non-owning2.C
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-non-owning3.C
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-non-owning4.C
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-non-owning5.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 9de0d77c423..88ddba825a9 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -14157,9 +14157,16 @@ do_warn_dangling_reference (tree expr, bool arg_p)
   but probably not to one of its arguments.  */
|| (DECL_OBJECT_MEMBER_FUNCTION_P (fndecl)
&& DECL_OVERLOADED_OPERATOR_P (fndecl)
-   && DECL_OVERLOADED_OPERATOR_IS (fndecl, INDIRECT_REF)))
+   && DECL_OVERLOADED_OPERATOR_IS (fndecl, INDIRECT_REF))
+   || lookup_attribute ("non_owning",
+TYPE_ATTRIBUTES (TREE_TYPE (fndecl
  return NULL_TREE;
 
+   if (tree ctx = CP_DECL_CONTEXT (fndecl))
+ if (TYPE_P (ctx)
+ && lookup_attribute ("non_owning", TYPE_ATTRIBUTES (ctx)))
+   return NULL_TREE;
+
tree rettype = TREE_TYPE (TREE_TYPE (fndecl));
/* If the function doesn't return a reference, don't warn.  This
   can be e.g.
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 77f57e0f9ac..2adf59b22d4 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -47,6 +47,7 @@ static tree verify_stmt_tree_r (tree *, int *, void *);
 static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *);
 static tree handle_abi_tag_attribute (tree *, tree, tree, int, bool *);
 static tree handle_contract_attribute (tree *, tree, tree, int, bool *);
+static tree handle_non_owning_attribute (tree *, tree, tree, int, bool *);
 
 /* If REF is an lvalue, returns the kind of lvalue that REF is.
Otherwise, returns clk_none.  */
@@ -5096,6 +5097,8 @@ static const attribute_spec cxx_gnu_attributes[] =
 handle_init_priority_attribute, NULL },
   { "abi_tag", 1, -1, false, false, false, true,
 handle_abi_tag_attribute, NULL },
+  { "non_owning", 0, 0, false, true, false, false,
+handle_non_owning_attribute, NULL },
 };
 
 const scoped_attribute_specs cxx_gnu_attribute_table =
@@ -5385,6 +5388,23 @@ handle_contract_attribute (tree *ARG_UNUSED (node), tree 
ARG_UNUSED (name),
   return NULL_TREE;
 }
 
+/* Handle a "non_owning" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_non_owning_attribute (tree *node, tree name, tree args, int,
+bool *no_add_attrs)
+{