From patchwork Fri Oct 14 21:54:28 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 682444 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org 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 3swhGj6rWKz9s3T for ; Sat, 15 Oct 2016 08:55:08 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=yD5M4MLe; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=W1t+BZrUK4fY9XBM+RREY5lD21SQq4VoNi4pipNSBgjFvt TbnrI9MNpwji/JXsdMxsjNd1s5myeVvXPFNhq7YvG6hn15HZDEfVP9NS0OQ3VtZ6 m94voeWVd1U81FB+V141pi2hwM+WNv9zye7lAbUEIN/FS6l9bxfLZYVnCo/9M= 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 :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=fMQEcb6rsngDn4lZ80wGfY+FOGw=; b=yD5M4MLeOO/4+2POnexK 0Sn2Hw/HF3UkV7SGcQBgttpxSlhkv4sAifyZq4yUMFrbE6SKmWBiz3qEhLGL5X+K BL/fzDWT68Lk7S228dzzj2QfKRnlvTXyR0qpMGt+OxvVDJEw6zlhq62QYw7SLUg9 HxyvnjukncEGOadVFOGsOLw= Received: (qmail 37739 invoked by alias); 14 Oct 2016 21:54:59 -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 37673 invoked by uid 89); 14 Oct 2016 21:54:54 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, RCVD_IN_SORBS_SPAM autolearn=ham version=3.3.2 spammy=ci, 1, 11, 1, 15, overlapping X-HELO: mail-oi0-f41.google.com Received: from mail-oi0-f41.google.com (HELO mail-oi0-f41.google.com) (209.85.218.41) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 14 Oct 2016 21:54:52 +0000 Received: by mail-oi0-f41.google.com with SMTP id m72so152352980oik.3 for ; Fri, 14 Oct 2016 14:54:52 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=IXXsLzrLM0R3VuxyGp/d86jfGNCQkd1+gk93HYSKgNU=; b=QfDLjc0pvSC6VWV6UvjEaKT6OXPt5mP0yx0qto5a/wbB9SxuUeY2td0/LiJFC7weYV P/J0loAkggbwORYePpXQV5YvCo8FAaw3CZsthxwMZ4cyJm3p4kWpeB5y1dLNajcgxgW/ 7QA4WfDsjYBAmJ1K7F5H7OtWUxXl7hyImO6FRTRm3AfQkx61dE5hoBVff9LnBcOAHzrQ qb066a5nExYdJnB71oViLv9G4r07xI5FfD5dqcJBo6cHG/nFT7jqIY7F7Ntx0e4OjVPs rZZG+FkvNUAa7uX33f8/hwBE4FMKL2Gx9Gh4V4txsKjWfrnPFGCsJt9OEkxNlX0zN+TM uSWQ== X-Gm-Message-State: AA6/9RkZI0sv5CP2HuXKqQajwvp47j2ijW/knLk0imjXT6lVt89U0qThshXUBMcNS+qkoOjpYOxdO5vmqHig+I+f X-Received: by 10.157.35.59 with SMTP id j56mr7528776otb.225.1476482090579; Fri, 14 Oct 2016 14:54:50 -0700 (PDT) MIME-Version: 1.0 Received: by 10.182.87.231 with HTTP; Fri, 14 Oct 2016 14:54:28 -0700 (PDT) From: Jason Merrill Date: Fri, 14 Oct 2016 17:54:28 -0400 Message-ID: Subject: C++ PATCH for P0017, C++17 aggregates with bases To: gcc-patches List X-IsSubscribed: yes Implementing this proposal was a pretty straightforward matter of changing the definition of aggregate and treating artificial base fields as initializable in aggregate initialization. For this to work with empty bases, I needed to create base fields for them, which we haven't done in the past. build_base_field warned about problems with empty base fields confusing the back end, but I wasn't able to find any such trouble. For the time being I'm only creating them in C++17 mode, to limit any regressions. Tested x86_64-pc-linux-gnu, applying to trunk. commit 99ba4ce4ec3daa3897b6bc971381ca4b1cdc54b1 Author: Jason Merrill Date: Fri Oct 14 07:45:02 2016 -0400 Implement P0017R1, C++17 aggregates with bases. * class.c (build_base_field_1): Split out from... (build_base_field): ...here. In C++17 mode, build a field for empty bases. * decl.c (xref_basetypes): In C++17 aggregates can have bases. (next_initializable_field): Allow base fields in C++17. * typeck2.c (process_init_constructor_record): Likewise. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 46f1bac..9a6ea97 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4452,6 +4452,34 @@ layout_empty_base (record_layout_info rli, tree binfo, return atend; } +/* Build the FIELD_DECL for BASETYPE as a base of T, add it to the chain of + fields at NEXT_FIELD, and return it. */ + +static tree +build_base_field_1 (tree t, tree basetype, tree *&next_field) +{ + /* Create the FIELD_DECL. */ + gcc_assert (CLASSTYPE_AS_BASE (basetype)); + tree decl = build_decl (input_location, + FIELD_DECL, NULL_TREE, CLASSTYPE_AS_BASE (basetype)); + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + DECL_FIELD_CONTEXT (decl) = t; + DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype); + DECL_SIZE_UNIT (decl) = CLASSTYPE_SIZE_UNIT (basetype); + SET_DECL_ALIGN (decl, CLASSTYPE_ALIGN (basetype)); + DECL_USER_ALIGN (decl) = CLASSTYPE_USER_ALIGN (basetype); + DECL_MODE (decl) = TYPE_MODE (basetype); + DECL_FIELD_IS_BASE (decl) = 1; + + /* Add the new FIELD_DECL to the list of fields for T. */ + DECL_CHAIN (decl) = *next_field; + *next_field = decl; + next_field = &DECL_CHAIN (decl); + + return decl; +} + /* Layout the base given by BINFO in the class indicated by RLI. *BASE_ALIGN is a running maximum of the alignments of any base class. OFFSETS gives the location of empty base @@ -4483,29 +4511,12 @@ build_base_field (record_layout_info rli, tree binfo, CLASSTYPE_EMPTY_P (t) = 0; /* Create the FIELD_DECL. */ - decl = build_decl (input_location, - FIELD_DECL, NULL_TREE, CLASSTYPE_AS_BASE (basetype)); - DECL_ARTIFICIAL (decl) = 1; - DECL_IGNORED_P (decl) = 1; - DECL_FIELD_CONTEXT (decl) = t; - if (CLASSTYPE_AS_BASE (basetype)) - { - DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype); - DECL_SIZE_UNIT (decl) = CLASSTYPE_SIZE_UNIT (basetype); - SET_DECL_ALIGN (decl, CLASSTYPE_ALIGN (basetype)); - DECL_USER_ALIGN (decl) = CLASSTYPE_USER_ALIGN (basetype); - DECL_MODE (decl) = TYPE_MODE (basetype); - DECL_FIELD_IS_BASE (decl) = 1; + decl = build_base_field_1 (t, basetype, next_field); - /* Try to place the field. It may take more than one try if we - have a hard time placing the field without putting two - objects of the same type at the same address. */ - layout_nonempty_base_or_field (rli, decl, binfo, offsets); - /* Add the new FIELD_DECL to the list of fields for T. */ - DECL_CHAIN (decl) = *next_field; - *next_field = decl; - next_field = &DECL_CHAIN (decl); - } + /* Try to place the field. It may take more than one try if we + have a hard time placing the field without putting two + objects of the same type at the same address. */ + layout_nonempty_base_or_field (rli, decl, binfo, offsets); } else { @@ -4541,6 +4552,13 @@ build_base_field (record_layout_info rli, tree binfo, create CONSTRUCTORs for the class by iterating over the FIELD_DECLs, and the back end does not handle overlapping FIELD_DECLs. */ + if (cxx_dialect >= cxx1z && !BINFO_VIRTUAL_P (binfo)) + { + tree decl = build_base_field_1 (t, basetype, next_field); + DECL_FIELD_OFFSET (decl) = BINFO_OFFSET (binfo); + DECL_FIELD_BIT_OFFSET (decl) = bitsize_zero_node; + SET_DECL_OFFSET_ALIGN (decl, BITS_PER_UNIT); + } /* An empty virtual base causes a class to be non-empty -- but in that case we do not need to clear CLASSTYPE_EMPTY_P @@ -6586,7 +6604,7 @@ layout_class_type (tree t, tree *virtuals_p) /* Make sure that empty classes are reflected in RLI at this point. */ - include_empty_classes(rli); + include_empty_classes (rli); /* Make sure not to create any structures with zero size. */ if (integer_zerop (rli_size_unit_so_far (rli)) && CLASSTYPE_EMPTY_P (t)) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index f761d0d..d9850e7 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5569,7 +5569,8 @@ next_initializable_field (tree field) while (field && (TREE_CODE (field) != FIELD_DECL || (DECL_C_BIT_FIELD (field) && !DECL_NAME (field)) - || DECL_ARTIFICIAL (field))) + || (DECL_ARTIFICIAL (field) + && !(cxx_dialect >= cxx1z && DECL_FIELD_IS_BASE (field))))) field = DECL_CHAIN (field); return field; @@ -13150,8 +13151,8 @@ xref_basetypes (tree ref, tree base_list) if (max_bases) { vec_alloc (BINFO_BASE_ACCESSES (binfo), max_bases); - /* An aggregate cannot have baseclasses. */ - CLASSTYPE_NON_AGGREGATE (ref) = 1; + /* A C++98 POD cannot have base classes. */ + CLASSTYPE_NON_LAYOUT_POD_P (ref) = true; if (TREE_CODE (ref) == UNION_TYPE) error ("derived union %qT invalid", ref); @@ -13179,6 +13180,13 @@ xref_basetypes (tree ref, tree base_list) if (access == access_default_node) access = default_access; + /* Before C++17, an aggregate cannot have base classes. In C++17, an + aggregate can't have virtual, private, or protected base classes. */ + if (cxx_dialect < cxx1z + || access != access_public_node + || via_virtual) + CLASSTYPE_NON_AGGREGATE (ref) = true; + if (PACK_EXPANSION_P (basetype)) basetype = PACK_EXPANSION_PATTERN (basetype); if (TREE_CODE (basetype) == TYPE_DECL) diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 121da32..022a478 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1352,6 +1352,7 @@ process_init_constructor_record (tree type, tree init, gcc_assert (TREE_CODE (type) == RECORD_TYPE); gcc_assert (!CLASSTYPE_VBASECLASSES (type)); gcc_assert (!TYPE_BINFO (type) + || cxx_dialect >= cxx1z || !BINFO_N_BASE_BINFOS (TYPE_BINFO (type))); gcc_assert (!TYPE_POLYMORPHIC_P (type)); @@ -1369,7 +1370,9 @@ process_init_constructor_record (tree type, tree init, if (!DECL_NAME (field) && DECL_C_BIT_FIELD (field)) continue; - if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field)) + if (TREE_CODE (field) != FIELD_DECL + || (DECL_ARTIFICIAL (field) + && !(cxx_dialect >= cxx1z && DECL_FIELD_IS_BASE (field)))) continue; /* If this is a bitfield, first convert to the declared type. */ diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base1.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base1.C new file mode 100644 index 0000000..37bb472 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base1.C @@ -0,0 +1,23 @@ +// { dg-options -std=c++1z } +// { dg-do run } + +struct base1 { int b1, b2 = 42; }; +struct base2 { + base2() { + b3 = 42; + } + int b3; +}; +struct derived : base1, base2 { + int d; +}; + +derived d1{{1, 2}, {}, 4}; +derived d2{{}, {}, 4}; + +#define assert(X) do { if (!(X)) __builtin_abort(); } while(0) +int main() +{ + assert (d1.b1 == 1 && d1.b2 == 2 && d1.b3 == 42 && d1.d == 4); + assert (d2.b1 == 0 && d2.b2 == 42 && d2.b3 == 42 && d2.d == 4); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base1a.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base1a.C new file mode 100644 index 0000000..4b28485 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base1a.C @@ -0,0 +1,15 @@ +// { dg-do compile { target { c++11 && c++14_down } } } + +struct base1 { int b1, b2 = 42; }; +struct base2 { + base2() { + b3 = 42; + } + int b3; +}; +struct derived : base1, base2 { + int d; +}; + +derived d1{{1, 2}, {}, 4}; // { dg-error "" } +derived d2{{}, {}, 4}; // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base2.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base2.C new file mode 100644 index 0000000..9da5ebf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base2.C @@ -0,0 +1,12 @@ +// { dg-options -std=c++1z } + +struct derived; +struct base { + friend struct derived; +private: + base(); +}; +struct derived : base {}; + +derived d1{}; // { dg-error "" "" { target c++1z } } +derived d2; // still OK diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base2a.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base2a.C new file mode 100644 index 0000000..821dce1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base2a.C @@ -0,0 +1,12 @@ +// { dg-do compile { target c++11 } } + +struct derived; +struct base { + friend struct derived; +private: + base(); +}; +struct derived : base {}; + +derived d1{}; // { dg-error "" "" { target c++1z } } +derived d2; // still OK diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base3.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base3.C new file mode 100644 index 0000000..4acbc0b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base3.C @@ -0,0 +1,11 @@ +// { dg-options -std=c++1z } + +struct derived; +struct base { }; +struct derived : base { + int i; +}; + +derived d1{1}; // { dg-error "base" } +derived d2{{},1}; // OK + diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base4.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base4.C new file mode 100644 index 0000000..fd93f4a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base4.C @@ -0,0 +1,21 @@ +// { dg-options -std=c++1z } +// { dg-do run } + +struct derived; +struct base { }; +struct derived : base { + int i; +}; + +bool flag; +base f() { + flag = true; + return base(); +} + +derived d2{f(),1}; + +int main() +{ + return (!flag || d2.i != 1); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base5.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base5.C new file mode 100644 index 0000000..85dd365 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base5.C @@ -0,0 +1,14 @@ +// { dg-options "-std=c++1z -w" } +// { dg-do run } + +struct A { }; +struct B: A { int i; }; +struct C: A, B { int j; }; + +constexpr C c = { {}, { {}, 1 }, 2 }; + +#define assert(X) do { if (!(X)) __builtin_abort(); } while(0) +int main() +{ + assert (c.i == 1 && c.j == 2); +}