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.129.124]) by sourceware.org (Postfix) with ESMTPS id 4938C3858034 for ; Wed, 29 Nov 2023 20:40:37 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4938C3858034 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 4938C3858034 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=1701290447; cv=none; b=wT34Exs8vsonp0HX22hp3Lsowp6MJ0/BMeqHkOpPFGBAnNvjSHe5E7GlWEgZHE0S248mUHZCwPe4LZo3/4NKJ8jgg3u1zQJXkQPdmcvJkmNMxTgxt1ovuonp7cKcvbNHw6tEXL/7ER9V2LHU8NPhBu3v/QHeS1p/MXYK/9uZN3Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701290447; c=relaxed/simple; bh=kkfncXRIPIfNVspBKPpGHZ1LrRVBmL1pjI7oqa7Rdek=; h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:To:From; b=holO8t/5xTZc6zHLyddgfm6t9d1VGjj5JdMZSN2uWHRf/tFvTrowOcNvXaWAB+d2rjGlHGNLWQKVbNPR7SpfbXJv+XWGsyP1QWG/ZgBvm4+ESmvB+v6NbH7ojjeR/yK3bhN6/cLUqD/mHsWjakt48apYjR9ihTNecFbnBrxekIo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1701290436; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XnOvRBeiCXgLxQNh9YGYa/ibYpLz5lvlfjZyGqorJ2E=; b=Hzd1dwk/aKpS+vbdgvF/KU+pfadGpp5YRKmY3+0noXYgxdwnpCTBv7v5rqhfC/YtTVh3bp 6LBtcWN6DZwVomgbXCr7BAbgVrUiupfXdYIGloF1RH/QxptxpoxtODRwIbdkPa4XifhTj3 XkH7Kslwk4fIpMeeasWsFEivX57W0OY= Received: from mail-qk1-f197.google.com (mail-qk1-f197.google.com [209.85.222.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-73-9Q6pR4C6N7O5b_7JKZnV9w-1; Wed, 29 Nov 2023 15:40:26 -0500 X-MC-Unique: 9Q6pR4C6N7O5b_7JKZnV9w-1 Received: by mail-qk1-f197.google.com with SMTP id af79cd13be357-77d8b1e25d9so46659485a.1 for ; Wed, 29 Nov 2023 12:40:26 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701290426; x=1701895226; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=XnOvRBeiCXgLxQNh9YGYa/ibYpLz5lvlfjZyGqorJ2E=; b=cT462SxCF+G3KbjcBd0eW2AbJmpEaSLc7kkVnN5j+s444novc8mNZChSqQZAFW1auQ 0kQy+CY5ya94QONX36tLP9C6ATnWVZfL22JKXyuqCJuvRL9q/u0gvHjouTgZnJp/ovgj ASBv/eaQr7lZ8rBqQb/2YMkhrZB8IonvTiPB/YUYvOFbR0vgf3V00He4xGYt47pbUkba QXQ9A5UZ0z3g7qK6lAPiNIdgkSyRiA5bbWKv8hHVG/6+pcjtv4Vpg1A5KEiV0XBnH1T4 eMgYYORYEjk2Jj8Wz9Z8Ijm1P7D8xOkFKwB2R7WlUQbm9RHBKCoArqP2AYzITAqwSKWt FJlQ== X-Gm-Message-State: AOJu0YwqqhnKzbSRwJCkJCG8Vis43XquiOZa4tsS9KPNXOM9xPLNIJfJ aHQrsPlScRIncyrrV/QXA/il5Z5YxBdhIV1ivG9U5B4PSYmmH5TZVXinrW9wq/jix8af2H4Mb3B zt5lgY8F1x8I40WveCw== X-Received: by 2002:ae9:ee0e:0:b0:77b:fe3e:91a5 with SMTP id i14-20020ae9ee0e000000b0077bfe3e91a5mr28763219qkg.37.1701290425998; Wed, 29 Nov 2023 12:40:25 -0800 (PST) X-Google-Smtp-Source: AGHT+IHgSpqRUvAu2nWVuCBsQVdtJYLFBx3i7D+gZkzUFbbvuKpRxpO6nJhYdVrAKfFb7jbrVMDJRQ== X-Received: by 2002:ae9:ee0e:0:b0:77b:fe3e:91a5 with SMTP id i14-20020ae9ee0e000000b0077bfe3e91a5mr28763190qkg.37.1701290425560; Wed, 29 Nov 2023 12:40:25 -0800 (PST) Received: from [192.168.1.145] (130-44-146-16.s12558.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.146.16]) by smtp.gmail.com with ESMTPSA id b2-20020a05620a270200b0077da28db10esm3237226qkp.125.2023.11.29.12.40.24 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 29 Nov 2023 12:40:25 -0800 (PST) Message-ID: <841b9c41-9efd-4bac-bba0-b960b131de7f@redhat.com> Date: Wed, 29 Nov 2023 15:40:24 -0500 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v2] c++: P2280R4, Using unknown refs in constant expr [PR106650] To: Marek Polacek Cc: GCC Patches References: <20231117214610.173872-1-polacek@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: 7bit X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,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 List-Id: On 11/29/23 13:56, Marek Polacek wrote: > On Mon, Nov 20, 2023 at 04:29:33PM -0500, Jason Merrill wrote: >> On 11/17/23 16:46, Marek Polacek wrote: >>> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? >>> >>> -- >8 -- >>> This patch is an attempt to implement (part of?) P2280, Using unknown >>> pointers and references in constant expressions. (Note that R4 seems to >>> only allow References to unknown/Accesses via this, but not Pointers to >>> unknown.) >> >> Indeed. That seems a bit arbitrary to me, but there it is. >> >> We were rejecting the testcase before because cxx_bind_parameters_in_call >> was trying to perform an lvalue->rvalue conversion on the reference itself; >> this isn't really a thing in the language, but worked to implement the >> reference bullet that the paper removes. Your approach to fixing that makes >> sense to me. >> >> We should do the same for VAR_DECL references, e.g. >> >> extern int (&r)[42]; >> constexpr int i = array_size (r); > > Argh, right. > >> You also need to allow (implict or explicit) use of 'this', as in: >> >> struct A >> { >> constexpr int f() { return 42; } >> void g() { constexpr int i = f(); } >> }; > > Ah, I thought that already worked, but not so. Apology apology. > >>> This patch works to the extent that the test case added in [expr.const] >>> works as expected, as well as the test in >>> >>> >>> Most importantly, the proposal makes this compile: >>> >>> template >>> constexpr auto array_size(T (&)[N]) -> size_t { >>> return N; >>> } >>> >>> void check(int const (¶m)[3]) { >>> constexpr auto s = array_size(param); >>> static_assert (s == 3); >>> } >>> >>> and I think it would be a pity not to have it in GCC 14. >>> >>> What still doesn't work (and I don't know if it should) is the test in $3.2: >>> >>> struct A2 { constexpr int f() { return 0; } }; >>> struct B2 : virtual A2 {}; >>> void f2(B2 &b) { constexpr int k = b.f(); } >>> >>> where we say >>> error: '* & b' is not a constant expression >> >> It seems like that is supposed to work, the problem is accessing the vtable >> to perform the conversion. I have WIP to recognize that conversion better >> in order to fix PR53288; this testcase can wait for that fix. > > Great. > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? OK. > -- >8 -- > This patch is an attempt to implement (part of?) P2280, Using unknown > pointers and references in constant expressions. (Note that R4 seems to > only allow References to unknown/Accesses via this, but not Pointers to > unknown.) > > This patch works to the extent that the test case added in [expr.const] > works as expected, as well as the test in > > > Most importantly, the proposal makes this compile: > > template > constexpr auto array_size(T (&)[N]) -> size_t { > return N; > } > > void check(int const (¶m)[3]) { > constexpr auto s = array_size(param); > static_assert (s == 3); > } > > and I think it would be a pity not to have it in GCC 14. > > What still doesn't work is the test in $3.2: > > struct A2 { constexpr int f() { return 0; } }; > struct B2 : virtual A2 {}; > void f2(B2 &b) { constexpr int k = b.f(); } > > where we say > error: '* & b' is not a constant expression > > This will be fixed in the future. > > PR c++/106650 > > gcc/cp/ChangeLog: > > * constexpr.cc (cxx_eval_constant_expression) : Allow > reference to unknown/this as per P2280. > : Allow reference to unknown as per P2280. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp0x/constexpr-array-ptr6.C: Remove dg-error. > * g++.dg/cpp0x/constexpr-ref12.C: Likewise. > * g++.dg/cpp0x/constexpr-ref2.C: Adjust dg-error. > * g++.dg/cpp0x/noexcept34.C: Remove dg-error. > * g++.dg/cpp1y/lambda-generic-const10.C: Likewise. > * g++.dg/cpp0x/constexpr-ref13.C: New test. > * g++.dg/cpp1z/constexpr-ref1.C: New test. > * g++.dg/cpp1z/constexpr-ref2.C: New test. > * g++.dg/cpp2a/constexpr-ref1.C: New test. > --- > gcc/cp/constexpr.cc | 8 ++- > .../g++.dg/cpp0x/constexpr-array-ptr6.C | 2 +- > gcc/testsuite/g++.dg/cpp0x/constexpr-ref12.C | 4 +- > gcc/testsuite/g++.dg/cpp0x/constexpr-ref13.C | 41 ++++++++++++++ > gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C | 4 +- > gcc/testsuite/g++.dg/cpp0x/noexcept34.C | 8 +-- > .../g++.dg/cpp1y/lambda-generic-const10.C | 2 +- > gcc/testsuite/g++.dg/cpp1z/constexpr-ref1.C | 26 +++++++++ > gcc/testsuite/g++.dg/cpp1z/constexpr-ref2.C | 23 ++++++++ > gcc/testsuite/g++.dg/cpp2a/constexpr-ref1.C | 54 +++++++++++++++++++ > 10 files changed, 161 insertions(+), 11 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-ref13.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-ref1.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-ref2.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-ref1.C > > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc > index 344107d494b..b17e176aded 100644 > --- a/gcc/cp/constexpr.cc > +++ b/gcc/cp/constexpr.cc > @@ -7336,7 +7336,9 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, > if (TREE_CODE (r) == TARGET_EXPR > && TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR) > r = TARGET_EXPR_INITIAL (r); > - if (DECL_P (r)) > + if (DECL_P (r) > + /* P2280 allows references to unknown. */ > + && !(VAR_P (t) && TYPE_REF_P (TREE_TYPE (t)))) > { > if (!ctx->quiet) > non_const_var_error (loc, r, /*fundef_p*/false); > @@ -7378,6 +7380,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, > r = build_constructor (TREE_TYPE (t), NULL); > TREE_CONSTANT (r) = true; > } > + else if (TYPE_REF_P (TREE_TYPE (t))) > + /* P2280 allows references to unknown... */; > + else if (is_this_parameter (t)) > + /* ...as well as the this pointer. */; > else > { > if (!ctx->quiet) > diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr6.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr6.C > index 1c065120314..d212665e51f 100644 > --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr6.C > +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr6.C > @@ -12,7 +12,7 @@ constexpr auto sz_d = size(array_double); > static_assert(sz_d == 3, "Array size failure"); > > void f(bool (¶m)[2]) { > - static_assert(size(param) == 2, "Array size failure"); // { dg-error "" } > + static_assert(size(param) == 2, "Array size failure"); > short data[] = {-1, 2, -45, 6, 88, 99, -345}; > static_assert(size(data) == 7, "Array size failure"); > } > diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref12.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref12.C > index 7c3ce66b4c9..f4500144946 100644 > --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref12.C > +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref12.C > @@ -40,7 +40,7 @@ void f(a ap, a& arp) > static_assert (g(ar2),""); // { dg-error "constant" } > static_assert (h(ar2),""); // { dg-error "constant" } > > - static_assert (arp.g(),""); // { dg-error "constant" } > - static_assert (g(arp),""); // { dg-error "constant" } > + static_assert (arp.g(),""); > + static_assert (g(arp),""); > static_assert (h(arp),""); // { dg-error "constant" } > } > diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref13.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref13.C > new file mode 100644 > index 00000000000..f26027552a0 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref13.C > @@ -0,0 +1,41 @@ > +// P2280R4 - Using unknown pointers and references in constant expressions > +// PR c++/106650 > +// { dg-do compile { target c++11 } } > + > +using size_t = decltype(sizeof(42)); > + > +template > +constexpr auto array_size(T (&)[N]) -> size_t { > + return N; > +} > + > +extern int (&r)[42]; > +constexpr int i = array_size (r); > + > +void check(int const (¶m)[3]) { > + int local[] = {1, 2, 3}; > + constexpr auto s0 = array_size(local); > + constexpr auto s1 = array_size(param); > +} > + > +template > +constexpr size_t array_size_ptr(T (*)[N]) { > + return N; > +} > + > +void check_ptr(int const (*param)[3]) { > + constexpr auto s2 = array_size_ptr(param); // { dg-error "not a constant" } > +} > + > +struct A > +{ > + constexpr int f() { return 42; } > + void g() { constexpr int i = f(); } > + void g2() { constexpr int i = this->f(); } > +}; > + > +struct B { > + constexpr static bool b = false; > + void g() noexcept(b) { } > + void g2() noexcept(this->b) { } > +}; > diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C > index 76973638d5f..d5327c2dcb2 100644 > --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C > +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C > @@ -4,8 +4,8 @@ > extern int *p; > constexpr int& ri = *p; // { dg-error "p" } > > -extern constexpr int &er; // { dg-error "not a definition" } > -constexpr int& ri2 = er; // { dg-error "er" } > +extern constexpr int &er; // { dg-error "not a definition|not a constant" } > +constexpr int& ri2 = er; > > void f(int j) > { > diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept34.C b/gcc/testsuite/g++.dg/cpp0x/noexcept34.C > index 963881b5ad6..5cb99675fd5 100644 > --- a/gcc/testsuite/g++.dg/cpp0x/noexcept34.C > +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept34.C > @@ -7,13 +7,13 @@ template struct A > { > constexpr int f () { return 0; } > bool b = true; > - void g () noexcept (f()) { } // { dg-error ".this. is not a constant" } > - void g2 () noexcept (this->f()) { } // { dg-error ".this. is not a constant" } > + void g () noexcept (f()) { } > + void g2 () noexcept (this->f()) { } > void g3 () noexcept (b) { } // { dg-error "use of .this. in a constant expression|use of parameter|.this. is not a constant" } > void g4 (int i) noexcept (i) { } // { dg-error "use of parameter" } > - void g5 () noexcept (A::f()) { } // { dg-error ".this. is not a constant" } > + void g5 () noexcept (A::f()) { } > void g6 () noexcept (foo(b)) { } // { dg-error "use of .this. in a constant expression|use of parameter|.this. is not a constant" } > - void g7 () noexcept (int{f()}) { } // { dg-error ".this. is not a constant" } > + void g7 () noexcept (int{f()}) { } > }; > > int main () > diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C > index 2f48dae4746..47a49f58419 100644 > --- a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C > +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C > @@ -11,7 +11,7 @@ int main() > constexpr auto x = f(); //ok, call constexpr const non-static method > > [](auto const &f) { > - constexpr auto x = f(); // { dg-error "" } > + constexpr auto x = f(); > }(f); > > [&]() { > diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-ref1.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-ref1.C > new file mode 100644 > index 00000000000..82771814a80 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-ref1.C > @@ -0,0 +1,26 @@ > +// P2280R4 - Using unknown pointers and references in constant expressions > +// PR c++/106650 > +// { dg-do compile { target c++17 } } > + > +#include > + > +template > +constexpr bool is_type(U &&) > +{ > + return std::is_same_v>; > +} > + > +auto visitor = [](auto&& v) { > + if constexpr(is_type(v)) { > + // ... > + } else if constexpr(is_type(v)) { > + // ... > + } > +}; > + > +void > +g (int i) > +{ > + visitor (i); > + constexpr bool b = is_type(i); > +} > diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-ref2.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-ref2.C > new file mode 100644 > index 00000000000..ca734378141 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-ref2.C > @@ -0,0 +1,23 @@ > +// P2280R4 - Using unknown pointers and references in constant expressions > +// PR c++/106650 > +// { dg-do compile { target c++17 } } > + > +template > +struct Widget { > + struct Config { > + static constexpr bool value = V; > + } config; > + > + void f() { > + if constexpr (config.value) { > + // ... > + } > + } > +}; > + > +void > +g () > +{ > + Widget w; > + w.f(); > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-ref1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-ref1.C > new file mode 100644 > index 00000000000..2ea865f8d5a > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-ref1.C > @@ -0,0 +1,54 @@ > +// P2280R4 - Using unknown pointers and references in constant expressions > +// PR c++/106650 > +// { dg-do compile { target c++20 } } > + > +#include > + > +using size_t = decltype(sizeof(42)); > + > +template > +constexpr size_t array_size(T (&)[N]) { > + return N; > +} > + > +void use_array(int const (&gold_medal_mel)[2]) { > + constexpr auto gold = array_size(gold_medal_mel); // OK > +} > + > +constexpr auto olympic_mile() { > + const int ledecky = 1500; > + return []{ return ledecky; }; > +} > +static_assert(olympic_mile()() == 1500); // OK > + > +struct Swim { > + constexpr int phelps() { return 28; } > + virtual constexpr int lochte() { return 12; } > + int coughlin = 12; > +}; > + > +constexpr int how_many(Swim& swam) { > + Swim* p = &swam; > + return (p + 1 - 1)->phelps(); > +} > + > +void splash(Swim& swam) { > + static_assert(swam.phelps() == 28); // OK > + static_assert((&swam)->phelps() == 28); // OK > + > + Swim* pswam = &swam; > + static_assert(pswam->phelps() == 28); // { dg-error "non-constant|not usable" } > + > + static_assert(how_many(swam) == 28); // OK > + static_assert(Swim().lochte() == 12); // OK > + > + static_assert(swam.lochte() == 12); // { dg-error "non-constant|not a constant" } > + > + static_assert(swam.coughlin == 12); // { dg-error "non-constant|not a constant" } > +} > + > +extern Swim dc; > +extern Swim& trident; > + > +constexpr auto& sandeno = typeid(dc); // OK, can only be typeid(Swim) > +constexpr auto& gallagher = typeid(trident); // { dg-error "not a constant" } > > base-commit: 634cf26c94de620e66aa124b8ec4d6c2be4b74b2