From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 7A38F3856DDE for ; Fri, 15 Jul 2022 03:49:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7A38F3856DDE Received: from mail-qk1-f200.google.com (mail-qk1-f200.google.com [209.85.222.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-470-4TCGEz-cOMSN242katmabg-1; Thu, 14 Jul 2022 23:48:55 -0400 X-MC-Unique: 4TCGEz-cOMSN242katmabg-1 Received: by mail-qk1-f200.google.com with SMTP id l189-20020a37bbc6000000b006af2596c5e8so2614649qkf.14 for ; Thu, 14 Jul 2022 20:48:55 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:date:mime-version:user-agent:subject :content-language:to:cc:references:from:in-reply-to :content-transfer-encoding; bh=ocnZ+Hjbv499IKYHhiXu0axtmhstmchD5IT978MfFU8=; b=4SvK+Y0qAzfr+gWeUJw2jfNgOrIG2vc4fKrgs0z9jDU3x6qfgySLeaDK8e0gu5G3H8 3nrhKdw2XNFi68BzULSIZi/bcN/5pid+6HifebAz8ahwltGyId+zkU83d1iFKTZLBi99 bTZgbp3qm/Cx3ORBKBborVEUPGo8uaXYQWC+1lVQR2YpsjCwwb7/mzXeu1ng28HxJUWi eviMxTPYxUKu2XuJXWbEaUrEi1ZXpGwg4gNa4bjFGplTdMjk7AwpgfjoIKCFCmSA+FT2 i6qvSwbkoRzvbgNcvgngLyvbmxK30/MO7gpc2BVRa9uHOtlsr1pVbOrkUP/JIiJXEi1k mLMw== X-Gm-Message-State: AJIora8WqbzNZ14BvpUfv99dLCjxJsDXk3EqGKGGF2CbvIrPOXCvHDCI dWV60Qcyj/XzVB8s5VIwh+CnuXyGSls/MmxWOMKcTigHKtKrTg1MyCynppKNeDE+7tR5eiR4wur d3YUtEnybVT/DGNU= X-Received: by 2002:a05:6214:29ef:b0:473:7504:52cd with SMTP id jv15-20020a05621429ef00b00473750452cdmr10633324qvb.82.1657856934766; Thu, 14 Jul 2022 20:48:54 -0700 (PDT) X-Google-Smtp-Source: AGRyM1sTieuOxtfwJWFHfCtcs1W+qYds+y1SE4tg3Mg63hEyzNTF75Bl6KVxnk7qh5EgY/BxewzsaQ== X-Received: by 2002:a05:6214:29ef:b0:473:7504:52cd with SMTP id jv15-20020a05621429ef00b00473750452cdmr10633312qvb.82.1657856934319; Thu, 14 Jul 2022 20:48:54 -0700 (PDT) Received: from [192.168.1.191] ([98.11.146.95]) by smtp.gmail.com with ESMTPSA id j15-20020a05620a288f00b006a5d2eb58b2sm3200961qkp.33.2022.07.14.20.48.52 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 14 Jul 2022 20:48:53 -0700 (PDT) Message-ID: <93e09683-22c9-9e13-9ae1-13c4b447f38f@redhat.com> Date: Thu, 14 Jul 2022 23:48:51 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.11.0 Subject: Re: [PATCH] c++: Add __reference_con{struc,ver}ts_from_temporary [PR104477] To: Marek Polacek Cc: GCC Patches , libstdc++ , Jonathan Wakely References: <20220708174133.2462418-1-polacek@redhat.com> <7955e63f-c20e-482c-cea3-db0942ed0149@redhat.com> <16983f2a-f56a-1462-c2db-3e4bc6fa6ad7@redhat.com> From: Jason Merrill In-Reply-To: X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, BODY_8BITS, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 15 Jul 2022 03:49:06 -0000 On 7/14/22 13:43, Marek Polacek wrote: > On Tue, Jul 12, 2022 at 04:15:00PM -0400, Jason Merrill wrote: >> On 7/12/22 16:10, Jason Merrill wrote: >>> On 7/8/22 13:41, Marek Polacek wrote: >>>> 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 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 conv_binds_ref_to_prvalue.  The main function here is >>>> reference_from_temporary.  The renaming to ref_conv_binds_to_temporary_p >>>> is because previously the function didn't distinguish between an invalid >>>> conversion and one that binds to a prvalue. >>>> >>>> The patch also adds the relevant class and variable templates to >>>> . >>>> >>>> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? >>>> >>>>     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_to_temporary_p): ... this.  Add a new bool >>>>     parameter.  Return true only if the conversion is valid and >>>>     conv_binds_ref_to_prvalue returns true. >>>>     * constraint.cc (diagnose_trait_expr): Handle >>>>     CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and >>>> CPTK_REF_CONVERTS_FROM_TEMPORARY. >>>>     * cp-tree.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_to_temporary_p): ... this. >>>>     (reference_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 (reference_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_to_temporary_p. >>>>     * 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. >>>> --- >>>>   gcc/c-family/c-common.cc                      |   4 + >>>>   gcc/c-family/c-common.h                       |   2 + >>>>   gcc/cp/call.cc                                |  14 +- >>>>   gcc/cp/constraint.cc                          |   8 + >>>>   gcc/cp/cp-tree.h                              |   7 +- >>>>   gcc/cp/cxx-pretty-print.cc                    |   6 + >>>>   gcc/cp/method.cc                              |  28 +++ >>>>   gcc/cp/parser.cc                              |  14 +- >>>>   gcc/cp/semantics.cc                           |   8 + >>>>   .../reference_constructs_from_temporary1.C    | 214 ++++++++++++++++++ >>>>   .../ext/reference_converts_from_temporary1.C  | 214 ++++++++++++++++++ >>>>   libstdc++-v3/include/std/type_traits          |  39 ++++ >>>>   libstdc++-v3/include/std/version              |   5 +- >>>>   .../20_util/reference_from_temporary/value.cc | 110 +++++++++ >>>>   .../reference_from_temporary/value2.cc        |  28 +++ >>>>   .../reference_from_temporary/version.cc       |  27 +++ >>>>   .../20_util/variable_templates_for_traits.cc  |  14 ++ >>>>   17 files changed, 730 insertions(+), 12 deletions(-) >>>>   create mode 100644 >>>> gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C >>>>   create mode 100644 >>>> gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C >>>>   create mode 100644 >>>> libstdc++-v3/testsuite/20_util/reference_from_temporary/value.cc >>>>   create mode 100644 >>>> libstdc++-v3/testsuite/20_util/reference_from_temporary/value2.cc >>>>   create mode 100644 >>>> libstdc++-v3/testsuite/20_util/reference_from_temporary/version.cc >>>> >>>> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc >>>> index 1b8e73f7bc5..655c3aefee6 100644 >>>> --- a/gcc/c-family/c-common.cc >>>> +++ b/gcc/c-family/c-common.cc >>>> @@ -537,6 +537,10 @@ const struct c_common_resword c_common_reswords[] = >>>>     { "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY }, >>>>     { "__is_nothrow_assignable", RID_IS_NOTHROW_ASSIGNABLE, D_CXXONLY }, >>>>     { "__is_nothrow_constructible", RID_IS_NOTHROW_CONSTRUCTIBLE, >>>> D_CXXONLY }, >>>> +  { "__reference_constructs_from_temporary", >>>> RID_REF_CONSTRUCTS_FROM_TEMPORARY, >>>> +                    D_CXXONLY }, >>>> +  { "__reference_converts_from_temporary", >>>> RID_REF_CONVERTS_FROM_TEMPORARY, >>>> +                    D_CXXONLY }, >>>>     /* C++ transactional memory.  */ >>>>     { "synchronized",    RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM }, >>>> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h >>>> index c0900848965..f9064393b4e 100644 >>>> --- a/gcc/c-family/c-common.h >>>> +++ b/gcc/c-family/c-common.h >>>> @@ -184,6 +184,8 @@ enum rid >>>>     RID_IS_UNION,                RID_UNDERLYING_TYPE, >>>>     RID_IS_ASSIGNABLE,           RID_IS_CONSTRUCTIBLE, >>>>     RID_IS_NOTHROW_ASSIGNABLE,   RID_IS_NOTHROW_CONSTRUCTIBLE, >>>> +  RID_REF_CONSTRUCTS_FROM_TEMPORARY, >>>> +  RID_REF_CONVERTS_FROM_TEMPORARY, >>>>     /* C++11 */ >>>>     RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, >>>> RID_STATIC_ASSERT, >>>> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc >>>> index fc98552fda2..1ba209f61f1 100644 >>>> --- a/gcc/cp/call.cc >>>> +++ b/gcc/cp/call.cc >>>> @@ -9109,21 +9109,23 @@ conv_binds_ref_to_prvalue (conversion *c) >>>>     return conv_is_prvalue (next_conversion (c)); >>>>   } >>>> -/* True iff converting EXPR to a reference type TYPE does not involve >>>> -   creating a temporary.  */ >>>> +/* True iff converting EXPR to a reference type TYPE binds the >>>> reference to >>>> +   a temporary.  DIRECT_INIT_P says whether the conversion should >>>> be done >>>> +   in direct- or copy-initialization context.  */ >>>>   bool >>>> -ref_conv_binds_directly_p (tree type, tree expr) >>>> +ref_conv_binds_to_temporary_p (tree type, tree expr, >>>> +                   bool direct_init_p /*= false*/) >>>>   { >>>>     gcc_assert (TYPE_REF_P (type)); >>>>     /* Get the high-water mark for the CONVERSION_OBSTACK.  */ >>>>     void *p = conversion_obstack_alloc (0); >>>> +  const int flags = direct_init_p ? LOOKUP_NORMAL : LOOKUP_IMPLICIT; >>>>     conversion *conv = implicit_conversion (type, TREE_TYPE (expr), expr, >>>> -                      /*c_cast_p=*/false, >>>> -                      LOOKUP_IMPLICIT, tf_none); >>>> -  bool ret = conv && !conv->bad_p && !conv_binds_ref_to_prvalue (conv); >>>> +                      /*c_cast_p=*/false, flags, tf_none); >>>> +  bool ret = conv && !conv->bad_p && conv_binds_ref_to_prvalue (conv); >>>>     /* Free all the conversions we allocated.  */ >>>>     obstack_free (&conversion_obstack, p); >>>> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc >>>> index 591155cee22..648cc9d176d 100644 >>>> --- a/gcc/cp/constraint.cc >>>> +++ b/gcc/cp/constraint.cc >>>> @@ -3687,6 +3687,14 @@ diagnose_trait_expr (tree expr, tree args) >>>>       case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS: >>>>         inform (loc, "  %qT does not have unique object >>>> representations", t1); >>>>         break; >>>> +    case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: >>>> +      inform (loc, "  %qT is not a reference that binds to a temporary " >>>> +          "object of type %qT (direct-initialization)", t1, t2); >>>> +      break; >>>> +    case CPTK_REF_CONVERTS_FROM_TEMPORARY: >>>> +      inform (loc, "  %qT is not a reference that binds to a temporary " >>>> +          "object of type %qT (copy-initialization)", t1, t2); >>>> +      break; >>>>       case CPTK_BASES: >>>>       case CPTK_DIRECT_BASES: >>>>       case CPTK_UNDERLYING_TYPE: >>>> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h >>>> index 2fde4f83b41..c3bed31e455 100644 >>>> --- a/gcc/cp/cp-tree.h >>>> +++ b/gcc/cp/cp-tree.h >>>> @@ -1397,7 +1397,9 @@ enum cp_trait_kind >>>>     CPTK_IS_ASSIGNABLE, >>>>     CPTK_IS_CONSTRUCTIBLE, >>>>     CPTK_IS_NOTHROW_ASSIGNABLE, >>>> -  CPTK_IS_NOTHROW_CONSTRUCTIBLE >>>> +  CPTK_IS_NOTHROW_CONSTRUCTIBLE, >>>> +  CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, >>>> +  CPTK_REF_CONVERTS_FROM_TEMPORARY >>>>   }; >>>>   /* The types that we are processing.  */ >>>> @@ -6520,7 +6522,7 @@ extern bool sufficient_parms_p >>>> (const_tree); >>>>   extern tree type_decays_to            (tree); >>>>   extern tree extract_call_expr            (tree); >>>>   extern tree build_trivial_dtor_call        (tree, bool = false); >>>> -extern bool ref_conv_binds_directly_p        (tree, tree); >>>> +extern bool ref_conv_binds_to_temporary_p    (tree, tree, bool = false); >>>>   extern tree build_user_type_conversion        (tree, tree, int, >>>>                            tsubst_flags_t); >>>>   extern tree build_new_function_call        (tree, vec **, >>>> @@ -7105,6 +7107,7 @@ extern tree forward_parm            (tree); >>>>   extern bool is_trivially_xible            (enum tree_code, tree, tree); >>>>   extern bool is_nothrow_xible            (enum tree_code, tree, tree); >>>>   extern bool is_xible                (enum tree_code, tree, tree); >>>> +extern bool reference_from_temporary        (tree, tree, bool); >>>>   extern tree get_defaulted_eh_spec        (tree, tsubst_flags_t = >>>> tf_warning_or_error); >>>>   extern bool maybe_explain_implicit_delete    (tree); >>>>   extern void explain_implicit_non_constexpr    (tree); >>>> diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc >>>> index 7e4db2e413b..44590830a61 100644 >>>> --- a/gcc/cp/cxx-pretty-print.cc >>>> +++ b/gcc/cp/cxx-pretty-print.cc >>>> @@ -2696,6 +2696,12 @@ pp_cxx_trait_expression (cxx_pretty_printer >>>> *pp, tree t) >>>>       case CPTK_IS_NOTHROW_CONSTRUCTIBLE: >>>>         pp_cxx_ws_string (pp, "__is_nothrow_constructible"); >>>>         break; >>>> +    case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: >>>> +      pp_cxx_ws_string (pp, "__reference_constructs_from_temporary"); >>>> +      break; >>>> +    case CPTK_REF_CONVERTS_FROM_TEMPORARY: >>>> +      pp_cxx_ws_string (pp, "__reference_converts_from_temporary"); >>>> +      break; >>>>       default: >>>>         gcc_unreachable (); >>>> diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc >>>> index 0dffd648b0b..dd9715b6725 100644 >>>> --- a/gcc/cp/method.cc >>>> +++ b/gcc/cp/method.cc >>>> @@ -2211,6 +2211,34 @@ is_xible (enum tree_code code, tree to, tree from) >>>>     return !!expr; >>>>   } >>>> +/* Return true iff conjunction_v, >>>> is_constructible> is >>>> +   true, and the initialization >>>> +     T t(VAL); // DIRECT_INIT_P >>>> +   or >>>> +     T t = VAL; // !DIRECT_INIT_P >>>> +   binds t to a temporary object whose lifetime is extended. >>>> +   VAL is defined in [meta.unary.prop]: >>>> +   -- If T is a reference or function type, VAL is an expression >>>> with the >>>> +   same type and value category as declval(). >>>> +   -- Otherwise, VAL is a prvalue that initially has type T.   */ >>>> + >>>> +bool >>>> +reference_from_temporary (tree to, tree from, bool direct_init_p) >>>> +{ >>>> +  /* Check is_reference.  */ >>>> +  if (!TYPE_REF_P (to)) >>>> +    return false; >>>> +  /* Check is_constructible. >>>> +     ??? This check doesn't seem to be necessary; if T isn't >>>> constructible >>>> +     from U, we won't be able to create a conversion.  */ >>>> +  if (!is_xible (INIT_EXPR, to, build_tree_list (NULL_TREE, from))) >>>> +    return false; >>> >>> I agree with the comment, did you try leaving this out?  If it stays I'd >>> think it needs to consider direct_init_p. >>> >>>> +  tree val = build_stub_object (from); >>>> +  if (!TYPE_REF_P (from) && TREE_CODE (from) != FUNCTION_TYPE) >>>> +    val = CLASS_TYPE_P (from) ? force_rvalue (val, tf_none) : >>>> rvalue (val); >>>> +  return ref_conv_binds_to_temporary_p (to, val, direct_init_p); >>>> +} >>>> + >>>>   /* Categorize various special_function_kinds.  */ >>>>   #define SFK_CTOR_P(sfk) \ >>>>     ((sfk) >= sfk_constructor && (sfk) <= sfk_move_constructor) >>>> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc >>>> index bf9ea3685f8..edee94bda13 100644 >>>> --- a/gcc/cp/parser.cc >>>> +++ b/gcc/cp/parser.cc >>>> @@ -5917,6 +5917,8 @@ cp_parser_primary_expression (cp_parser *parser, >>>>       case RID_IS_CONSTRUCTIBLE: >>>>       case RID_IS_NOTHROW_ASSIGNABLE: >>>>       case RID_IS_NOTHROW_CONSTRUCTIBLE: >>>> +    case RID_REF_CONSTRUCTS_FROM_TEMPORARY: >>>> +    case RID_REF_CONVERTS_FROM_TEMPORARY: >>>>         return cp_parser_trait_expr (parser, token->keyword); >>>>       // C++ concepts >>>> @@ -10988,6 +10990,14 @@ cp_parser_trait_expr (cp_parser* parser, >>>> enum rid keyword) >>>>         kind = CPTK_IS_NOTHROW_CONSTRUCTIBLE; >>>>         variadic = true; >>>>         break; >>>> +    case RID_REF_CONSTRUCTS_FROM_TEMPORARY: >>>> +      kind = CPTK_REF_CONSTRUCTS_FROM_TEMPORARY; >>>> +      binary = true; >>>> +      break; >>>> +    case RID_REF_CONVERTS_FROM_TEMPORARY: >>>> +      kind = CPTK_REF_CONVERTS_FROM_TEMPORARY; >>>> +      binary = true; >>>> +      break; >>>>       default: >>>>         gcc_unreachable (); >>>>       } >>>> @@ -13811,7 +13821,7 @@ warn_for_range_copy (tree decl, tree expr) >>>>     if (TYPE_REF_P (type)) >>>>       { >>>> -      if (glvalue_p (expr) && !ref_conv_binds_directly_p (type, expr)) >>>> +      if (glvalue_p (expr) && ref_conv_binds_to_temporary_p (type, >>>> expr)) >>>>       { >>>>         auto_diagnostic_group d; >>>>         if (warning_at (loc, OPT_Wrange_loop_construct, >>>> @@ -13842,7 +13852,7 @@ warn_for_range_copy (tree decl, tree expr) >>>>     tree rtype = cp_build_reference_type (type, /*rval*/false); >>>>     /* If we could initialize the reference directly, it wouldn't >>>> involve any >>>>        copies.  */ >>>> -  if (!ref_conv_binds_directly_p (rtype, expr)) >>>> +  if (ref_conv_binds_to_temporary_p (rtype, expr)) >>>>       return; >>> >>> I think this case wants the old handling of invalid conversions you >>> mentioned in your intro; we don't want to suggest changing to a >>> reference if that's ill-formed. >>> >>> In passing we might change the comment to "If we can initialize a >>> reference directly, suggest that to avoid the copy." and move it above >>> the rtype declaration. >> >> Hmm, and I suspect we get false positives when expr is a prvalue, so >> initializing a non-reference variable of the same cv-unqualified type >> involves no extra copy? > > I couldn't provoke a false positive here. Note that ref_conv_binds_to_temporary_p > always gets a reference so copy elision isn't applicable here. Ah, I see: if expr is a prvalue, that counts as binding a reference to a temporary, so we (properly) don't think the reference is an improvement. The function name reference_from_temporary seems to me to suggest a tree value rather than bool, maybe rename to ref_xes_from_temporary? OK either way. Jason