Bug 104477 - [C++23] Implement P2255R2, type trait to detect reference binding to temporary
Summary: [C++23] Implement P2255R2, type trait to detect reference binding to temporary
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 12.0
: P3 enhancement
Target Milestone: ---
Assignee: Marek Polacek
URL:
Keywords:
Depends on:
Blocks: c++23-core 70692 108822
  Show dependency treegraph
 
Reported: 2022-02-09 19:46 UTC by Jason Merrill
Modified: 2023-12-08 19:22 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2022-02-09 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jason Merrill 2022-02-09 19:46:36 UTC
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2255r2.html

The library type traits std::reference_{constructs,converts}_from_temporary will need a compiler intrinsic to implement.

Apparently clang already has a __reference_binds_to_temporary with similar but not identical semantics; I think let's see if they plan to adjust that builtin or add a new one before we settle on a name.
Comment 1 Marek Polacek 2022-05-27 15:04:06 UTC
https://clang.llvm.org/cxx_status.html#cxx23 says

"Clang provides a __reference_binds_to_temporary type trait builtin, with which the library facility can be partially implemented. Both __reference_constructs_from_temporary and __reference_converts_from_temporary builtins should be provided, following the normal cross-vendor convention to implement traits requiring compiler support directly."

which suggests to me that we should implement two new builtins:
__reference_constructs_from_temporary
__reference_converts_from_temporary
With those in place, I don't think we need __reference_binds_to_temporary.
Comment 2 Jakub Jelinek 2022-05-27 15:24:33 UTC
Agree on that.
Comment 3 Andrew Pinski 2022-06-29 23:23:26 UTC
I am going to be like Johnathan and say I wish these compiler intrinsic were defined by the standard rather than having  to define them ourselves.
Comment 4 Jonathan Wakely 2022-07-01 11:27:57 UTC
They are defined by the standard, as library traits. The intrinsics are needed to implement what the standard defines.
Comment 5 GCC Commits 2022-07-15 15:33:12 UTC
The trunk branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>:

https://gcc.gnu.org/g:9a15d3beace26d68561cb3481b70b0bbcb122ca5

commit r13-1714-g9a15d3beace26d68561cb3481b70b0bbcb122ca5
Author: Marek Polacek <polacek@redhat.com>
Date:   Wed Jun 29 19:00:54 2022 -0400

    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.
Comment 6 Marek Polacek 2022-07-15 15:35:21 UTC
Implemented in GCC 13.