From patchwork Mon Nov 11 08:07:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1192818 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-512915-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="wOHIPI4O"; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="Ip+tspWl"; 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 47BNlQ5Rpnz9sNx for ; Mon, 11 Nov 2019 19:07:28 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:reply-to:mime-version :content-type:content-transfer-encoding; q=dns; s=default; b=Vhl lzUUQAZDssaC99/YiJgevI70zg+Czjh/PEDEhOorD3S4+oll9BVSImtWKJQ/cVSJ UU9zBFBJJSBcHYm/MCSuF3DaWoGeP8lA2uAVkYqtC2hKMTnpOmpO4L6MqP/VFb0N UsLnvwPFm7DKa+YEp6j3B0zvfjBui4Bhbka0wbJc= 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:date :from:to:cc:subject:message-id:reply-to:mime-version :content-type:content-transfer-encoding; s=default; bh=OzO+P4/dQ owWZbqcmSJwy/eOoFQ=; b=wOHIPI4Oq5yNEk1UKV7ZeLOi+VcL2gbIiMcRstyQQ vHEYXDSS/3f5WdGgNMExtJWVWq/FAsFo0ZwQEaRofflcsM6yvjvJboxiWyMR+vzl 2zqLD7ZUkxkk7yuzivEYLfPS0PTgXMVAsvcPd3Zb0BU8JcWgl8Ql9yt9+bZnYtly R8= Received: (qmail 79145 invoked by alias); 11 Nov 2019 08:07:20 -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 79133 invoked by uid 89); 11 Nov 2019 08:07:20 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-7.7 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3 autolearn=ham version=3.3.1 spammy=comparisons, regtest, dgexp, UD:dg.exp X-HELO: us-smtp-1.mimecast.com Received: from us-smtp-1.mimecast.com (HELO us-smtp-1.mimecast.com) (205.139.110.61) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 11 Nov 2019 08:07:18 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573459636; 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: content-transfer-encoding:content-transfer-encoding; bh=Mht4t9pM3z/DZgHa+ND6Sx634uZUrZkGa3WoLUGK/yI=; b=Ip+tspWlh15Sy2cCoxyDoJFnQoAy6gp0DHnkXDd5Q6vyoBLshpWgRZ45O61f8sscSLxcw8 QofVb0AjmE1rFL/7eo+q6oLVbCP3rzX9261/QXkj5PIpEcfPQzbQXAG8ckLAajZFP+IdFc +v9FKVIZ63QhcPdNPUD/Rx8uUiF8tCI= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-2-GknL9TzGNOKGxNbLxGvlHg-1; Mon, 11 Nov 2019 03:07:13 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id B8ED91804972 for ; Mon, 11 Nov 2019 08:07:12 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.36.118.135]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 49574608EF; Mon, 11 Nov 2019 08:07:12 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.15.2/8.15.2) with ESMTP id xAB87910023619; Mon, 11 Nov 2019 09:07:10 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.15.2/8.15.2/Submit) id xAB878e0023618; Mon, 11 Nov 2019 09:07:08 +0100 Date: Mon, 11 Nov 2019 09:07:08 +0100 From: Jakub Jelinek To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: [C++ PATCH] Implement P1946R0 - Allow defaulting comparisons by value Message-ID: <20191111080708.GV4650@tucnak> Reply-To: Jakub Jelinek MIME-Version: 1.0 User-Agent: Mutt/1.11.3 (2019-02-01) X-Mimecast-Spam-Score: 0 Content-Disposition: inline X-IsSubscribed: yes Hi! From https://www.reddit.com/r/cpp/comments/dtuov8/201911_belfast_iso_c_committee_trip_report/ I understood P1946R0 made it into C++20, so here is my attempt at implementing it, you had most of it implemented anyway because in system headers friend constexpr bool operator==(partial_ordering, partial_ordering) noexcept = default; etc. has been already accepted. Tested so far with make check-c++-all RUNTESTFLAGS=dg.exp=spaceship* and make check-target-libstdc++-v3 RUNTESTFLAGS=conformance.exp=18_support/comparisons/common/1.cc Ok for trunk if it passes full bootstrap/regtest? 2019-11-11 Jakub Jelinek Implement P1946R0 - Allow defaulting comparisons by value * method.c (early_check_defaulted_comparison): Remove unused variable i. For non-static data members always require argument type to be const C &, for friends allow either both arguments to be const C &, or both to be C. * g++.dg/cpp2a/spaceship-synth1-neg.C: New test. * g++.dg/cpp2a/spaceship-synth4.C: New test. * g++.dg/cpp2a/spaceship-synth5.C: New test. Jakub --- gcc/cp/method.c.jj 2019-11-07 21:21:27.097760879 +0100 +++ gcc/cp/method.c 2019-11-11 08:28:22.633822845 +0100 @@ -1098,34 +1098,39 @@ early_check_defaulted_comparison (tree f ok = false; } - int i = DECL_NONSTATIC_MEMBER_FUNCTION_P (fn); - if (i && type_memfn_quals (TREE_TYPE (fn)) != TYPE_QUAL_CONST) + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + && type_memfn_quals (TREE_TYPE (fn)) != TYPE_QUAL_CONST) { error_at (loc, "defaulted %qD must be %", fn); ok = false; } - tree parmnode = FUNCTION_FIRST_USER_PARMTYPE (fn); - for (; parmnode != void_list_node; parmnode = TREE_CHAIN (parmnode)) + tree firstparmnode = FUNCTION_FIRST_USER_PARMTYPE (fn); + for (tree parmnode = firstparmnode; parmnode != void_list_node; + parmnode = TREE_CHAIN (parmnode)) { - ++i; tree parmtype = TREE_VALUE (parmnode); - diagnostic_t kind = DK_UNSPECIFIED; - int opt = 0; - if (same_type_p (parmtype, ctx)) - /* The draft specifies const reference, but let's also allow by-value - unless -Wpedantic, hopefully it will be added soon. */ - kind = DK_PEDWARN, - opt = OPT_Wpedantic; - else if (TREE_CODE (parmtype) != REFERENCE_TYPE - || TYPE_QUALS (TREE_TYPE (parmtype)) != TYPE_QUAL_CONST - || !(same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (parmtype), ctx))) - kind = DK_ERROR; - if (kind) - emit_diagnostic (kind, loc, opt, "defaulted %qD must have " - "parameter type %", fn, ctx); - if (kind == DK_ERROR) - ok = false; + /* a non-static const member of C having one parameter of type const C&, + or a friend of C having either two parameters of type const C& or two + parameters of type C. */ + if ((!DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + && !same_type_p (TREE_VALUE (firstparmnode), parmtype)) + || ((DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + || !same_type_p (parmtype, ctx)) + && (TREE_CODE (parmtype) != REFERENCE_TYPE + || TYPE_QUALS (TREE_TYPE (parmtype)) != TYPE_QUAL_CONST + || !(same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (parmtype), ctx))))) + { + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) + error_at (loc, "defaulted %qD must have parameter type " + "%", fn, ctx); + else + error_at (loc, "defaulted %qD must have parameter types " + "%, % or " + "%qT, %qT", fn, ctx, ctx, ctx, ctx); + ok = false; + break; + } } /* We still need to deduce deleted/constexpr/noexcept and maybe return. */ --- gcc/testsuite/g++.dg/cpp2a/spaceship-synth1-neg.C.jj 2019-11-11 08:23:34.040215264 +0100 +++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth1-neg.C 2019-11-11 08:32:56.206659041 +0100 @@ -0,0 +1,15 @@ +// Test with all operators explicitly defaulted. +// { dg-do compile { target c++2a } } + +#include + +struct D +{ + int i; + auto operator<=>(D& x) const = default; // { dg-error "defaulted \[^\n\r]* must have parameter type 'const D&'" } + bool operator==(int x) const = default; // { dg-error "defaulted \[^\n\r]* must have parameter type 'const D&'" } + bool operator!=(const int& x) const = default; // { dg-error "defaulted \[^\n\r]* must have parameter type 'const D&'" } + friend bool operator<(int& x, D& y) = default; // { dg-error "defaulted \[^\n\r]* must have parameter types 'const D&', 'const D&' or 'D', 'D'" } + friend bool operator<=(const D& x, D y) = default; // { dg-error "defaulted \[^\n\r]* must have parameter types 'const D&', 'const D&' or 'D', 'D'" } + friend bool operator>(D x, const D& y) = default; // { dg-error "defaulted \[^\n\r]* must have parameter types 'const D&', 'const D&' or 'D', 'D'" } +}; --- gcc/testsuite/g++.dg/cpp2a/spaceship-synth4.C.jj 2019-11-10 16:35:34.296158460 +0100 +++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth4.C 2019-11-10 16:37:05.881767368 +0100 @@ -0,0 +1,43 @@ +// Test with all operators explicitly defaulted. +// { dg-do run { target c++2a } } + +#include + +struct D +{ + int i; + friend auto operator<=>(const D& x, const D& y) = default; + friend bool operator==(const D& x, const D& y) = default; + friend bool operator!=(const D& x, const D& y) = default; + friend bool operator<(const D& x, const D& y) = default; + friend bool operator<=(const D& x, const D& y) = default; + friend bool operator>(const D& x, const D& y) = default; + friend bool operator>=(const D& x, const D& y) = default; +}; + +#define assert(X) do { if (!(X)) __builtin_abort(); } while (0) + +int main() +{ + D d{42}; + D d2{24}; + + assert (is_eq (d <=> d)); + assert (is_lteq (d <=> d)); + assert (is_gteq (d <=> d)); + assert (is_lt (d2 <=> d)); + assert (is_lteq (d2 <=> d)); + assert (is_gt (d <=> d2)); + assert (is_gteq (d <=> d2)); + + assert (d == d); + assert (!(d2 == d)); + assert (!(d == d2)); + assert (d != d2); + assert (!(d2 != d2)); + + assert (d2 < d); + assert (d2 <= d); + assert (d > d2); + assert (d >= d2); +} --- gcc/testsuite/g++.dg/cpp2a/spaceship-synth5.C.jj 2019-11-10 16:41:54.673380871 +0100 +++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth5.C 2019-11-11 08:32:49.270764604 +0100 @@ -0,0 +1,43 @@ +// Test with all operators explicitly defaulted. +// { dg-do run { target c++2a } } + +#include + +struct D +{ + int i; + friend auto operator<=>(D x, D y) = default; + friend bool operator==(D x, D y) = default; + friend bool operator!=(D x, D y) = default; + friend bool operator<(D x, D y) = default; + friend bool operator<=(D x, D y) = default; + friend bool operator>(D x, D y) = default; + friend bool operator>=(const D x, const D y) = default; +}; + +#define assert(X) do { if (!(X)) __builtin_abort(); } while (0) + +int main() +{ + D d{42}; + D d2{24}; + + assert (is_eq (d <=> d)); + assert (is_lteq (d <=> d)); + assert (is_gteq (d <=> d)); + assert (is_lt (d2 <=> d)); + assert (is_lteq (d2 <=> d)); + assert (is_gt (d <=> d2)); + assert (is_gteq (d <=> d2)); + + assert (d == d); + assert (!(d2 == d)); + assert (!(d == d2)); + assert (d != d2); + assert (!(d2 != d2)); + + assert (d2 < d); + assert (d2 <= d); + assert (d > d2); + assert (d >= d2); +}