]> git.ipfire.org Git - thirdparty/gcc.git/commit - libstdc++-v3/testsuite/20_util/reference_from_temporary/value.cc
c++: Add __reference_con{struc,ver}ts_from_temporary [PR104477]
authorMarek Polacek <polacek@redhat.com>
Wed, 29 Jun 2022 23:00:54 +0000 (19:00 -0400)
committerMarek Polacek <polacek@redhat.com>
Fri, 15 Jul 2022 15:30:38 +0000 (11:30 -0400)
commit9a15d3beace26d68561cb3481b70b0bbcb122ca5
tree7db269b8e6e93169326693418b3ac42c50c0d62d
parent0a8edfbd37d399d1103d86e134ba0a92f8c873c3
c++: Add __reference_con{struc,ver}ts_from_temporary [PR104477]

This patch implements C++23 P2255R2, which adds two new type traits to
detect reference binding to a temporary.  They can be used to detect code
like

  std::tuple<const std::string&> t("meow");

which is incorrect because it always creates a dangling reference, because
the std::string temporary is created inside the selected constructor of
std::tuple, and not outside it.

There are two new compiler builtins, __reference_constructs_from_temporary
and __reference_converts_from_temporary.  The former is used to simulate
direct- and the latter copy-initialization context.  But I had a hard time
finding a test where there's actually a difference.  Under DR 2267, both
of these are invalid:

  struct A { } a;
  struct B { explicit B(const A&); };
  const B &b1{a};
  const B &b2(a);

so I had to peruse [over.match.ref], and eventually realized that the
difference can be seen here:

  struct G {
    operator int(); // #1
    explicit operator int&&(); // #2
  };

int&& r1(G{}); // use #2 (no temporary)
int&& r2 = G{}; // use #1 (a temporary is created to be bound to int&&)

The implementation itself was rather straightforward because we already
have the conv_binds_ref_to_prvalue function.  The main function here is
ref_xes_from_temporary.
I've changed the return type of ref_conv_binds_directly to tristate, because
previously the function didn't distinguish between an invalid conversion and
one that binds to a prvalue.  Since it no longer returns a bool, I removed
the _p suffix.

The patch also adds the relevant class and variable templates to <type_traits>.

PR c++/104477

gcc/c-family/ChangeLog:

* c-common.cc (c_common_reswords): Add
__reference_constructs_from_temporary and
__reference_converts_from_temporary.
* c-common.h (enum rid): Add RID_REF_CONSTRUCTS_FROM_TEMPORARY and
RID_REF_CONVERTS_FROM_TEMPORARY.

gcc/cp/ChangeLog:

* call.cc (ref_conv_binds_directly_p): Rename to ...
(ref_conv_binds_directly): ... this.  Add a new bool parameter.  Change
the return type to tristate.
* constraint.cc (diagnose_trait_expr): Handle
CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and CPTK_REF_CONVERTS_FROM_TEMPORARY.
* cp-tree.h: Include "tristate.h".
(enum cp_trait_kind): Add CPTK_REF_CONSTRUCTS_FROM_TEMPORARY
and CPTK_REF_CONVERTS_FROM_TEMPORARY.
(ref_conv_binds_directly_p): Rename to ...
(ref_conv_binds_directly): ... this.
(ref_xes_from_temporary): Declare.
* cxx-pretty-print.cc (pp_cxx_trait_expression): Handle
CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and CPTK_REF_CONVERTS_FROM_TEMPORARY.
* method.cc (ref_xes_from_temporary): New.
* parser.cc (cp_parser_primary_expression): Handle
RID_REF_CONSTRUCTS_FROM_TEMPORARY and RID_REF_CONVERTS_FROM_TEMPORARY.
(cp_parser_trait_expr): Likewise.
(warn_for_range_copy): Adjust to call ref_conv_binds_directly.
* semantics.cc (trait_expr_value): Handle
CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and CPTK_REF_CONVERTS_FROM_TEMPORARY.
(finish_trait_expr): Likewise.

libstdc++-v3/ChangeLog:

* include/std/type_traits (reference_constructs_from_temporary,
reference_converts_from_temporary): New class templates.
(reference_constructs_from_temporary_v,
reference_converts_from_temporary_v): New variable templates.
(__cpp_lib_reference_from_temporary): Define for C++23.
* include/std/version (__cpp_lib_reference_from_temporary): Define for
C++23.
* testsuite/20_util/variable_templates_for_traits.cc: Test
reference_constructs_from_temporary_v and
reference_converts_from_temporary_v.
* testsuite/20_util/reference_from_temporary/value.cc: New test.
* testsuite/20_util/reference_from_temporary/value2.cc: New test.
* testsuite/20_util/reference_from_temporary/version.cc: New test.

gcc/testsuite/ChangeLog:

* g++.dg/ext/reference_constructs_from_temporary1.C: New test.
* g++.dg/ext/reference_converts_from_temporary1.C: New test.
17 files changed:
gcc/c-family/c-common.cc
gcc/c-family/c-common.h
gcc/cp/call.cc
gcc/cp/constraint.cc
gcc/cp/cp-tree.h
gcc/cp/cxx-pretty-print.cc
gcc/cp/method.cc
gcc/cp/parser.cc
gcc/cp/semantics.cc
gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C [new file with mode: 0644]
libstdc++-v3/include/std/type_traits
libstdc++-v3/include/std/version
libstdc++-v3/testsuite/20_util/reference_from_temporary/value.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/reference_from_temporary/value2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/reference_from_temporary/version.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc