From patchwork Wed Apr 18 03:45:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 899863 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-476524-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="pCEtIldL"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40Qp1w370bz9s1d for ; Wed, 18 Apr 2018 13:46:09 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:mime-version:content-type; q=dns; s=default; b=kPAC6EhuZaoZSxgo1oTdxwO03CDPHTpHUhImmYAvS6U+Z6KxZs eJQOAViFXKgSt/Ti0Axuze8VaXFkq0H+3hlSfG0lbgMCqLmTXQnebcyxzTcn9HoV kWUmT/mytetAkSnMR+DJTPKQdYyN6ggRv1TALkyOKR8NjK3IaLrtc1k5A= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:mime-version:content-type; s= default; bh=2309YHWDdfxlMYKlDdpVgkKqJFY=; b=pCEtIldLvkyixK4euVN2 QHajKOXjMv5Id1V5H5IbWYpNNTIpxTNKuU0c0pioSuRO3k+RePWCVXA26fbb6hEq f+rywSfrlz7aNQEPBIM7BvGSCLNTCjxLxlnWE+j2Kxb6e7Cs5UPqSG+tL0mO0vUN gkUl6Y136ibLlqZCiF7wEaA= Received: (qmail 108236 invoked by alias); 18 Apr 2018 03:46:01 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 108219 invoked by uid 89); 18 Apr 2018 03:46:01 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3 autolearn=ham version=3.3.2 spammy=Suggestions X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Apr 2018 03:45:59 +0000 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B7A2131327CD; Wed, 18 Apr 2018 03:45:57 +0000 (UTC) Received: from free.home (ovpn04.gateway.prod.ext.phx2.redhat.com [10.5.9.4]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 7554217D5F; Wed, 18 Apr 2018 03:45:57 +0000 (UTC) Received: from livre (livre.home [172.31.160.2]) by free.home (8.15.2/8.15.2) with ESMTP id w3I3jo7N072864; Wed, 18 Apr 2018 00:45:50 -0300 From: Alexandre Oliva To: gcc-patches@gcc.gnu.org Cc: jason@redhat.com, nathan@acm.org Subject: [PATCH] [PR c++/85437] accept static_casted ptrmem in constexpr Date: Wed, 18 Apr 2018 00:45:50 -0300 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.91 (gnu/linux) MIME-Version: 1.0 A static_cast of a pointer to data member used to wrap the PTRMEM_CST in a NOP_EXPR, but the NOP_EXPR is taken, in constexpr, as evidence that there was a reinterpret_cast in the expression. While reinterpret_casts are to be rejected in constexprs, static_casts are ok. Thus, avoid introducing the NOP_EXPR in static_casts, folding the converted-to type into the PTRMEM_CST type. This requires PTRMEM_CST constant expansion to deal with such up and downcasts. --- I've tested this sucessfully with check-c++-all, but I'm not entirely happy with it, not just because the following testcase still fails (though the testcases in the patch pass), but also because the early folding and the extra work in cplus_expand_constant don't feel quite right. struct A { }; struct B { int x; }; struct C : A, B {}; constexpr int C::*pci = &B::x; constexpr int A::*pai = static_cast(pci); I've experimented with an alternative of marking NOP_EXPRs introduced by static_casts and const_casts with a flag (static_flag), but that felt even more fragile, since we drop and rebuild NOP_EXPRs all the time, redundant ones used to be dropped safely, and so both positive and negative marks for constexpr compatibility could be lost, leading to false positives or missed errors. Still, it seems like we'd be better off with some reliable means to tell constexpr-compatible casts from other conversions. NOP_EXPRs alone just don't cut it. Anyway, at this point I'd appreciate some guidance as to how to proceed. At this stage of GCC8 development, I'm even considering dropping the incorrect complaint about reinterpret_cast, even if that would regress the rejection of casts that don't belong in constexprs. Thoughts? Suggestions? Thanks in advance, --- for gcc/cp/ChangeLog PR c++/85437 * expr.c (cplus_expand_constant): Compute deltas for up and downcasts. * type.c (convert_ptrmem): Convert ptrmem type for static cast. for gcc/testsuite/ChangeLog PR c++/85437 * g++.dg/cpp0x/pr85437.C: New. * g++.dg/cpp0x/pr85437-2.C: New. * g++.dg/cpp0x/pr85437-3.C: New. --- gcc/cp/expr.c | 25 +++++++++++++++++++++++++ gcc/cp/typeck.c | 5 ++++- gcc/testsuite/g++.dg/cpp0x/pr85437-2.C | 7 +++++++ gcc/testsuite/g++.dg/cpp0x/pr85437-3.C | 7 +++++++ gcc/testsuite/g++.dg/cpp0x/pr85437.C | 16 ++++++++++++++++ 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr85437-2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr85437-3.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr85437.C diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index 15894fc0b594..28fe2e83398d 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -50,11 +50,36 @@ cplus_expand_constant (tree cst) while (!same_type_p (DECL_CONTEXT (member), TYPE_PTRMEM_CLASS_TYPE (type))) { + tree t1 = TYPE_MAIN_VARIANT (DECL_CONTEXT (member)); + tree t2 = TYPE_MAIN_VARIANT (TYPE_PTRMEM_CLASS_TYPE (type)); + + if (can_convert (t2, t1, 0)) + { + base_kind kind; + tree binfo = lookup_base (t1, t2, ba_unique, &kind, 0); + if (binfo != error_mark_node + && kind != bk_via_virtual) + cst = size_binop (MINUS_EXPR, cst, BINFO_OFFSET (binfo)); + break; + } + + if (can_convert (t1, t2, 0)) + { + base_kind kind; + tree binfo = lookup_base (t2, t1, ba_unique, &kind, 0); + if (binfo != error_mark_node + && kind != bk_via_virtual) + cst = size_binop (PLUS_EXPR, cst, BINFO_OFFSET (binfo)); + break; + } + /* The MEMBER must have been nestled within an anonymous aggregate contained in TYPE. Find the anonymous aggregate. */ member = lookup_anon_field (TYPE_PTRMEM_CLASS_TYPE (type), DECL_CONTEXT (member)); + if (!member) + break; cst = size_binop (PLUS_EXPR, cst, byte_position (member)); } cst = fold (build_nop (type, cst)); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index b449b1f7f539..0b88181e9574 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -6871,7 +6871,10 @@ convert_ptrmem (tree type, tree expr, bool allow_inverse_p, } - return build_nop (type, expr); + if (c_cast_p) + return build_nop (type, expr); + else + return cp_fold_convert (type, expr); } else return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, diff --git a/gcc/testsuite/g++.dg/cpp0x/pr85437-2.C b/gcc/testsuite/g++.dg/cpp0x/pr85437-2.C new file mode 100644 index 000000000000..57734a96b475 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr85437-2.C @@ -0,0 +1,7 @@ +// { dg-do compile { target c++11 } } + +struct A { }; +struct B : A { int x; }; + +constexpr int A::*abx += reinterpret_cast(&B::x); // { dg-error "reinterpret.*constant" } diff --git a/gcc/testsuite/g++.dg/cpp0x/pr85437-3.C b/gcc/testsuite/g++.dg/cpp0x/pr85437-3.C new file mode 100644 index 000000000000..a956df6b05a1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr85437-3.C @@ -0,0 +1,7 @@ +// { dg-do compile { target c++11 } } + +struct A { int y; }; +struct B { int x; }; +struct C : A, B {}; +constexpr int C::*pci = &B::x; +constexpr int A::*pai = static_cast(static_cast(&B::x)); diff --git a/gcc/testsuite/g++.dg/cpp0x/pr85437.C b/gcc/testsuite/g++.dg/cpp0x/pr85437.C new file mode 100644 index 000000000000..d02b1b600158 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr85437.C @@ -0,0 +1,16 @@ +// { dg-do compile { target c++11 } } + +struct A { int a; constexpr A() : a(0) {} }; +struct B : A { int x; constexpr B() : x(0) {} }; +struct X { int z; constexpr X() : z(0) {} }; +struct C : X, B {}; +constexpr int C::*cbx = &B::x; +constexpr int B::*bx = &B::x; +constexpr int A::*abx = static_cast(&B::x); + +constexpr const C y; +constexpr const B& yb = y; +constexpr const A& ya = y; +constexpr int const *pcbx = &(y.*cbx); +constexpr int const *pbx = &(y.*bx); +constexpr int const *pabx = &(ya.*abx);