From patchwork Fri Mar 8 08:56:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1909564 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=E+39RUnp; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Trg5X13pwz23qc for ; Fri, 8 Mar 2024 19:56:46 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DEB9C3856089 for ; Fri, 8 Mar 2024 08:56:43 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 55B66385C422 for ; Fri, 8 Mar 2024 08:56:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 55B66385C422 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 55B66385C422 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709888185; cv=none; b=U9Npuz5sM7o05k6c2uona7U0kXi++k3sLhThVund6sCw6cylJhh/Tl9gp4FkIesB4gUToN5bdEPg0HKxPCe7S8aECqw4TBhykliYeP5ugdip8rCGV4OiVP28OWNDHQEMhlaQTcrKzGOq/w5S6dOHJQjBbkQst8uxzhb/92xvUbM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709888185; c=relaxed/simple; bh=FzeehaoknypVDuG+YKaj1TSvsxkXURoA+FBU/T4DwgA=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=g4I7avkwZZyJLR4BNfUx1RYRQzX9HFSQDl+ezHIpjOPBnOKQCYAzkRhbqQIki0rXgTirIiqS1vsOnOb1t5xzEXLXtSHiy18046nrRIB5xwzz+6JlnngmzbtCJK+dRcZ+RjYCfRDAxsNQPHcuP4zTtcwy0Vh4IHjQJJEVpCso3tc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1709888182; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type; bh=vmywZIZeTXfpHPW7DEd6AqRgsNPhwTAMPTT4Z4lsDdc=; b=E+39RUnpoqPDhgFfYmyDfeHAxVtBFLQ/ZkWKBbERaCePbeJcNoCecWVg+tp58aetlKy0h/ 7dqwszd427jkLfPNG1fLCSu695V0g8bmNJ/V0Eq00bixGByeVvFWEQ/blCj1BFmpWLhZER I8IcnXMuqFKMS14T9tfL/Wrp2syTScA= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-141-EB0m-BEAM7-PUwwXWmOLLQ-1; Fri, 08 Mar 2024 03:56:21 -0500 X-MC-Unique: EB0m-BEAM7-PUwwXWmOLLQ-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id DDE40101A5BB for ; Fri, 8 Mar 2024 08:56:20 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.45.226.25]) by smtp.corp.redhat.com (Postfix) with ESMTPS id A31D7492BFD; Fri, 8 Mar 2024 08:56:20 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 4288uIwb2678944 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Fri, 8 Mar 2024 09:56:19 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 4288uItt2678943; Fri, 8 Mar 2024 09:56:18 +0100 Date: Fri, 8 Mar 2024 09:56:18 +0100 From: Jakub Jelinek To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] c++: Fix constexpr evaluation of parameters passed by invisible reference [PR111284] Message-ID: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.10 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-3.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Jakub Jelinek Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Hi! My r9-6136 changes to make a copy of constexpr function bodies before genericization modifies it broke the constant evaluation of non-POD arguments passed by value. In the callers such arguments are passed as reference to usually a TARGET_EXPR, but on the callee side until genericization they are just direct uses of a PARM_DECL with some class type. In cxx_bind_parameters_in_call I've used convert_from_reference to pretend it is passed by value and then cxx_eval_constant_expression is called there and evaluates that as an rvalue, followed by adjust_temp_type if the types don't match exactly (e.g. const Foo argument and passing to it reference to Foo TARGET_EXPR). The reason this doesn't work is that when the TARGET_EXPR in the caller is constant initialized, this for it is the address of the TARGET_EXPR_SLOT, but if the code later on pretends the PARM_DECL is just initialized to the rvalue of the constant evaluation of the TARGET_EXPR, it is as if there is a bitwise copy of the TARGET_EXPR to the callee, so this in the callee is then address of the PARM_DECL in the callee. The following patch attempts to fix that by constexpr evaluation of such arguments in the caller as an lvalue instead of rvalue, and on the callee side when seeing such a PARM_DECL, if we want an lvalue, lookup the value (lvalue) saved in ctx->globals (if any), and if wanting an rvalue, recursing with vc_prvalue on the looked up value (because it is there as an lvalue, nor rvalue). adjust_temp_type doesn't work for lvalues of non-scalarish types, for such types it relies on changing the type of a CONSTRUCTOR, but on the other side we know what we pass to the argument is addressable, so the patch on type mismatch takes address of the argument value, casts to reference to the desired type and dereferences it. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2024-03-08 Jakub Jelinek PR c++/111284 * constexpr.cc (cxx_bind_parameters_in_call): For PARM_DECLs with TREE_ADDRESSABLE types use vc_glvalue rather than vc_prvalue for cxx_eval_constant_expression and if it doesn't have the same type as it should, cast the reference type to reference to type before convert_from_reference and instead of adjust_temp_type take address of the arg, cast to reference to type and then convert_from_reference. (cxx_eval_constant_expression) : For lval case on parameters with TREE_ADDRESSABLE types lookup result in ctx->globals if possible. Otherwise if lookup in ctx->globals was successful for parameter with TREE_ADDRESSABLE type, recurse with vc_prvalue on the returned value. * g++.dg/cpp1z/constexpr-111284.C: New test. * g++.dg/cpp1y/constexpr-lifetime7.C: Expect one error on a different line. Jakub --- gcc/cp/constexpr.cc.jj 2024-02-13 10:29:57.979155641 +0100 +++ gcc/cp/constexpr.cc 2024-03-07 19:35:01.032412221 +0100 @@ -1877,13 +1877,21 @@ cxx_bind_parameters_in_call (const const x = build_address (x); } if (TREE_ADDRESSABLE (type)) - /* Undo convert_for_arg_passing work here. */ - x = convert_from_reference (x); - /* Normally we would strip a TARGET_EXPR in an initialization context - such as this, but here we do the elision differently: we keep the - TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm. */ - arg = cxx_eval_constant_expression (ctx, x, vc_prvalue, - non_constant_p, overflow_p); + { + /* Undo convert_for_arg_passing work here. */ + if (TYPE_REF_P (TREE_TYPE (x)) + && !same_type_p (type, TREE_TYPE (TREE_TYPE (x)))) + x = cp_fold_convert (build_reference_type (type), x); + x = convert_from_reference (x); + arg = cxx_eval_constant_expression (ctx, x, vc_glvalue, + non_constant_p, overflow_p); + } + else + /* Normally we would strip a TARGET_EXPR in an initialization context + such as this, but here we do the elision differently: we keep the + TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm. */ + arg = cxx_eval_constant_expression (ctx, x, vc_prvalue, + non_constant_p, overflow_p); /* Check we aren't dereferencing a null pointer when calling a non-static member function, which is undefined behaviour. */ if (i == 0 && DECL_OBJECT_MEMBER_FUNCTION_P (fun) @@ -1909,7 +1917,16 @@ cxx_bind_parameters_in_call (const const { /* Make sure the binding has the same type as the parm. But only for constant args. */ - if (!TYPE_REF_P (type)) + if (TREE_ADDRESSABLE (type)) + { + if (!same_type_p (type, TREE_TYPE (arg))) + { + arg = build_fold_addr_expr (arg); + arg = cp_fold_convert (build_reference_type (type), arg); + arg = convert_from_reference (arg); + } + } + else if (!TYPE_REF_P (type)) arg = adjust_temp_type (type, arg); if (!TREE_CONSTANT (arg)) *non_constant_args = true; @@ -7499,9 +7516,19 @@ cxx_eval_constant_expression (const cons case PARM_DECL: if (lval && !TYPE_REF_P (TREE_TYPE (t))) - /* glvalue use. */; + { + /* glvalue use. */ + if (TREE_ADDRESSABLE (TREE_TYPE (t))) + if (tree v = ctx->global->get_value (t)) + r = v; + } else if (tree v = ctx->global->get_value (t)) - r = v; + { + r = v; + if (TREE_ADDRESSABLE (TREE_TYPE (t))) + r = cxx_eval_constant_expression (ctx, r, vc_prvalue, + non_constant_p, overflow_p); + } else if (lval) /* Defer in case this is only used for its type. */; else if (ctx->global->is_outside_lifetime (t)) --- gcc/testsuite/g++.dg/cpp1z/constexpr-111284.C.jj 2024-03-07 16:27:48.113651999 +0100 +++ gcc/testsuite/g++.dg/cpp1z/constexpr-111284.C 2024-03-07 16:26:49.565466606 +0100 @@ -0,0 +1,19 @@ +// PR c++/111284 +// { dg-do compile { target c++17 } } + +struct S { + S () = default; + constexpr S (const S &) noexcept : s{this} {} + constexpr S & operator= (const S &) noexcept { return *this; } + constexpr bool foo () const noexcept { return s == this; } + S *s = this; +}; + +constexpr bool +bar (S x) noexcept +{ + return x.foo (); +} + +static_assert (bar (S {}), ""); +static_assert ([] (S x) { return x.foo (); } (S {}), ""); --- gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime7.C.jj 2023-12-13 19:09:33.252657826 +0100 +++ gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime7.C 2024-03-07 19:49:49.342334090 +0100 @@ -87,7 +87,7 @@ constexpr bool n1 = test_access(); // { dg-message "in .constexpr." "" { target c++20 } } constexpr bool n3 = test_scope(); // { dg-message "in .constexpr." "" { target c++20 } } constexpr bool n4 = test_destroy_temp(); // { dg-message "in .constexpr." "" { target c++20 } } -constexpr bool n5 = test_parameter(NonTrivial{}); // { dg-error "destroying" "" { target c++20 } } +constexpr bool n5 = test_parameter(NonTrivial{}); // { dg-message "in .constexpr." "" { target c++20 } } constexpr bool n6 = test_bindings(); #endif