From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 104469 invoked by alias); 27 Jan 2016 13:46:41 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 104453 invoked by uid 89); 27 Jan 2016 13:46:40 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.5 required=5.0 tests=AWL,BAYES_00,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 spammy=improves, pr63579, PR63579 X-HELO: mail-qk0-f170.google.com Received: from mail-qk0-f170.google.com (HELO mail-qk0-f170.google.com) (209.85.220.170) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Wed, 27 Jan 2016 13:46:38 +0000 Received: by mail-qk0-f170.google.com with SMTP id s5so3337697qkd.0 for ; Wed, 27 Jan 2016 05:46:38 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:date :message-id:subject:from:to:cc:content-type; bh=2bAddbVeIcXrVbVv09rtgghr9/Dagxpix5xa6pJDRcs=; b=HHEr52y7dHR3RV8U7Ddm4IfPp0GiAkaUZlH5rpBN7v0WRJTyCqLa2qJMibqT4CJhK2 7fBTa/o597Y1ZTqGsDZuxIZJZVZ/o8gx0WaYRUcoJIg0FJZ0fTi4UV20ygzqYUXFShQL bdO62zMI8wgCF0WC7AEEzpcpdXo9vkiuEPdjGke+cEQWuCPMwX2lKwcnSQ9y74DF6Zj5 Xcm9huXGg5KW3Ri1XXxGnmHuNkBNlaHCYICdHwJexe+yWeT5/Ks5euD7P4mKyXs9nzU3 koqRTa9B7IPPGIBpElJ1zNzEOSUVWqF5NX4PopJuRnJpU9Wwxngt6x9aaTffY1xRDkxs +Okg== X-Gm-Message-State: AG10YOTbEkOYjeJbkECOdKwAHy5yC/+LBOLTl4g4l+RTr8FZ41u0qZPkge+y/8pqXwqHZZeXvocK33jfIkbd4g== MIME-Version: 1.0 X-Received: by 10.55.76.15 with SMTP id z15mr35122403qka.32.1453902396816; Wed, 27 Jan 2016 05:46:36 -0800 (PST) Received: by 10.55.4.210 with HTTP; Wed, 27 Jan 2016 05:46:36 -0800 (PST) In-Reply-To: References: <56A7C8AC.8070204@redhat.com> <20160126214000.GL3017@tucnak.redhat.com> <20160127082107.GN3017@tucnak.redhat.com> Date: Wed, 27 Jan 2016 13:46:00 -0000 Message-ID: Subject: Re: PING^1: [PATCH] Add TYPE_EMPTY_RECORD for C++ empty class From: "H.J. Lu" To: GCC Patches Cc: Jakub Jelinek , Jason Merrill , Richard Biener , Markus Trippelsdorf Content-Type: text/plain; charset=UTF-8 X-IsSubscribed: yes X-SW-Source: 2016-01/txt/msg02108.txt.bz2 On Wed, Jan 27, 2016 at 1:03 AM, Marc Glisse wrote: > On Wed, 27 Jan 2016, Jakub Jelinek wrote: > >> On Wed, Jan 27, 2016 at 09:10:14AM +0100, Marc Glisse wrote: >>>> >>>> Revised: >>>> >>>> /* Returns true if TYPE is POD of one-byte or less in size for the >>>> purpose >>>> of layout and an empty class or an class with empty classes. */ >>>> >>>> static bool >>>> is_empty_record (tree type) >>>> { >>>> if (type == error_mark_node) >>>> return false; >>>> >>>> if (!CLASS_TYPE_P (type)) >>>> return false; >>>> >>>> if (CLASSTYPE_NON_LAYOUT_POD_P (type)) >>>> return false; >>>> >>>> gcc_assert (COMPLETE_TYPE_P (type)); >>>> >>>> if (CLASSTYPE_EMPTY_P (type)) >>>> return true; >>>> >>>> if (int_size_in_bytes (type) > 1) >>>> return false; >>> >>> >>> That's completely arbitrary :-( >> >> >> Yeah. Because (adapted to be compilable with C): >> struct A1 {}; struct A2 {}; >> struct B1 { struct A1 a; struct A2 b; }; struct B2 { struct A1 a; struct >> A2 b; }; >> struct C1 { struct B1 a; struct B2 b; }; struct C2 { struct B1 a; struct >> B2 b; }; >> struct D1 { struct C1 a; struct C2 b; }; struct D2 { struct C1 a; struct >> C2 b; }; >> struct E1 { struct D1 a; struct D2 b; }; struct E2 { struct D1 a; struct >> D2 b; }; >> struct F1 { struct E1 a; struct E2 b; }; struct F2 { struct E1 a; struct >> E2 b; }; >> struct G1 { struct F1 a; struct F2 b; }; struct G2 { struct F1 a; struct >> F2 b; }; >> struct H1 { struct G1 a; struct G2 b; }; struct H2 { struct G1 a; struct >> G2 b; }; >> struct I1 { struct H1 a; struct H2 b; }; struct I2 { struct H1 a; struct >> H2 b; }; >> struct J1 { struct I1 a; struct I2 b; }; struct J2 { struct I1 a; struct >> I2 b; }; >> struct K1 { struct J1 a; struct J2 b; }; >> int v; >> __attribute__((noinline, noclone)) >> struct K1 foo (int a, struct K1 x, int b) >> { >> v = a + b; >> return x; >> } >> struct K1 k, m; >> void >> bar (void) >> { >> m = foo (1, k, 2); >> } >> then would have a different calling convention between C and C++, >> so where is the argument that we change anything just to make the two >> compatible? Though, of course, those two will never be compatible, >> it is enough to add struct L1 { int a; struct K1 b; int c; }; and >> that structure has 1024+8 bytes in C++ and 8 bytes in C. > > > I don't know how empty classes are used in C in practice, but it could make > sense to have ABI compatibility as long as no empty struct is used as a > member of another struct (I also suggested an attribute to let C++ use the > same layout as C here: PR63579). But then the usual definition of empty > would be sufficient. > >> As clang generates different code for the above between C and C++, it >> clearly special cases for some reason just the most common case. >> IMHO it is not worth to change GCC ABI... > > > I was interested in this change because it improves C++, C compatibility was > a convenient excuse ;-) > I opened a clang bug: https://llvm.org/bugs/show_bug.cgi?id=26337 I propose the following definitions: i. An empty record is: 1. A class without member. Or 2. An array of empty records. Or 3. A class with empty records. ii. An empty record type for parameter passing is POD for the purpose of layout and 1. A class without member. Or 2. A class with empty records. /* An empty record is: 1. A class without member. Or 2. An array of empty records. Or 3. A class with empty records. */ /* Returns true if TYPE is an empty record or an array of empty records. */ static bool is_empty_record_or_array_of_empty_record (tree type) { if (CLASS_TYPE_P (type)) { if (CLASSTYPE_EMPTY_P (type)) return true; tree field; for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL && !DECL_ARTIFICIAL (field) && !is_empty_record_or_array_of_empty_record (TREE_TYPE (field))) return false; return true; } else if (TREE_CODE (type) == ARRAY_TYPE) return is_empty_record_or_array_of_empty_record (TREE_TYPE (type)); return false; } /* Returns true if TYPE is POD for the purpose of layout and 1. A class without member. Or 2. A class with empty records. */ static bool is_empty_record_for_parm (tree type) { if (type == error_mark_node) return false; if (!CLASS_TYPE_P (type)) return false; if (CLASSTYPE_NON_LAYOUT_POD_P (type)) return false; gcc_assert (COMPLETE_TYPE_P (type)); if (CLASSTYPE_EMPTY_P (type)) return true; tree field; for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL && !DECL_ARTIFICIAL (field) && !is_empty_record_or_array_of_empty_record (TREE_TYPE (field))) return false; return true; } -- H.J.