From patchwork Fri Dec 17 03:26:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 49039 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1D15A3858420 for ; Fri, 17 Dec 2021 03:27:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1D15A3858420 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1639711672; bh=5mY+l/bBV2WEeOmoj6lESnzbtZH+BInRBcmZwzoYRgE=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=RTf9r+h1jwf3UGfI0O+dtY+Q++PWnlhV47h9kMQF/cSWjhLEsfqzZYwOC7RAtwa80 1OTZVjPkujkd+0731nGHJrHgTb92zARHXg+0lhvV275zBP+SgmqTqyLJUjvqwA3ogb V92J4YRQrKgwEs4p2IWbvKJ2r6ZlFqktU6Pq0PtY= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org 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 42A9A3858410 for ; Fri, 17 Dec 2021 03:27:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 42A9A3858410 Received: from mail-qt1-f200.google.com (mail-qt1-f200.google.com [209.85.160.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-315-kFsJmJ8FNPqLaOtHQMPfrw-1; Thu, 16 Dec 2021 22:26:59 -0500 X-MC-Unique: kFsJmJ8FNPqLaOtHQMPfrw-1 Received: by mail-qt1-f200.google.com with SMTP id v17-20020a05622a131100b002aea167e24aso1315423qtk.5 for ; Thu, 16 Dec 2021 19:26:59 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=5mY+l/bBV2WEeOmoj6lESnzbtZH+BInRBcmZwzoYRgE=; b=rCvdVpaVF88Bd6kiz0+5gWkwkXYD4KvGOnAAWsc4eVGiGgDd4TqMnNPVt5IeaIbqqs 9GP41SOIMTFA/g5cxzmyH5hN0TrJwtSenn183pGIHHRCB1fvbTKf87V+OYJP5PCX5ywa mTwat3GWSTQhjD/1lkGKbCoDPQHMioLfu5mVHC/79zvgbH6meSIai4ZPEsC0R71o5ST7 lv5r1wYz4Ozm/QqMqRGJS+GsktR2dAeK6q+3UNLLIkFrWKmLN/QnwPqsio+icfMPutQZ C8k535mKuFC4b6S8BTAKOZnJNOMrcR1rczYWxnGlViBH9BflK23GXTr1qfu8Wa+DA50M vTDw== X-Gm-Message-State: AOAM533yKwPBLNW/8RDZoa2FFt0YPaAUgFbFsqI5HEmapCp2fKuat9dp TJnrtNRRQAmI6EucFcT7J8vhzlr3y4KLl76ZolNTeEz6yddi/kxWJNmij5gk1Vvyqdtdcz9GsIP EO/0OKF7F5Cc/FMpsskYv6cSBEQxN6A5/iC6rU1HbqcNKOxtf+QTtlxfZIjZ7t0KJdA== X-Received: by 2002:ac8:7d09:: with SMTP id g9mr874630qtb.179.1639711618430; Thu, 16 Dec 2021 19:26:58 -0800 (PST) X-Google-Smtp-Source: ABdhPJyZ90/eP/krYCgFk0KX6x620qS+N35PzEp/efYXmzs/l/nzbK1Sjndf2aHOcnot0nxKsHodyw== X-Received: by 2002:ac8:7d09:: with SMTP id g9mr874610qtb.179.1639711617704; Thu, 16 Dec 2021 19:26:57 -0800 (PST) Received: from barrymore.redhat.com (130-44-159-43.s15913.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.159.43]) by smtp.gmail.com with ESMTPSA id h2sm3916924qkn.136.2021.12.16.19.26.56 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Dec 2021 19:26:57 -0800 (PST) To: gcc-patches@gcc.gnu.org Subject: [pushed] c++: layout of aggregate base with DMI [PR103681] Date: Thu, 16 Dec 2021 22:26:55 -0500 Message-Id: <20211217032655.711331-1-jason@redhat.com> X-Mailer: git-send-email 2.27.0 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-27.3 required=5.0 tests=BAYES_00, DKIM_INVALID, DKIM_SIGNED, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Jason Merrill via Gcc-patches From: Jason Merrill Reply-To: Jason Merrill Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" C++14 changed the definition of 'aggregate' to allow default member initializers, but such classes still need to be considered "non-POD for the purpose of layout" for ABI compatibility with C++11 code. It seems rare to derive from such a class, as evidenced by how long this bug has survived (since r216750 in 2014), but it's certainly worth fixing. We only warn when we were failing to allocate another field into the tail padding of the newly aggregate class; this is the only ABI impact. This also changes end_of_class to consider all data members, not just empty data members; that used to be an additional flag, removed in r9-5710, but I don't see any reason not to always include them. This makes the result of the function correspond to the ABI nvsize term and its nameless counterpart that does include virtual bases. When looking closely at other users of end_of_class, I realized that we were assuming that the latter corresponded to the ABI dsize term, but it doesn't if the class ends with an empty virtual base (in the rare case that the empty base can't be assigned offset 0), and this matters for layout of [[no_unique_address]]. So I added another mode that returns the desired value for that case. I'm not adding a warning for this ABI fix because it's a C++20 feature. Tested x86_64-pc-linux-gnu, applying to trunk. PR c++/103681 gcc/ChangeLog: * common.opt (fabi-version): Add v17. gcc/cp/ChangeLog: * cp-tree.h (struct lang_type): Add non_pod_aggregate. (CLASSTYPE_NON_POD_AGGREGATE): New. * class.c (check_field_decls): Set it. (check_bases_and_members): Check it. (check_non_pod_aggregate): New. (enum eoc_mode): New. (end_of_class): Always include non-empty fields. Add eoc_nv_or_dsize mode. (include_empty_classes, layout_class_type): Adjust. gcc/c-family/ChangeLog: * c-opts.c (c_common_post_options): Update defaults. gcc/testsuite/ChangeLog: * g++.dg/abi/macro0.C: Update value. * g++.dg/abi/no_unique_address6.C: New test. * g++.dg/abi/nsdmi-aggr1.C: New test. * g++.dg/abi/nsdmi-aggr1a.C: New test. --- gcc/common.opt | 4 + gcc/cp/cp-tree.h | 9 +- gcc/c-family/c-opts.c | 6 +- gcc/cp/class.c | 145 +++++++++++++----- gcc/testsuite/g++.dg/abi/macro0.C | 2 +- gcc/testsuite/g++.dg/abi/no_unique_address6.C | 23 +++ gcc/testsuite/g++.dg/abi/nsdmi-aggr1.C | 39 +++++ gcc/testsuite/g++.dg/abi/nsdmi-aggr1a.C | 35 +++++ 8 files changed, 217 insertions(+), 46 deletions(-) create mode 100644 gcc/testsuite/g++.dg/abi/no_unique_address6.C create mode 100644 gcc/testsuite/g++.dg/abi/nsdmi-aggr1.C create mode 100644 gcc/testsuite/g++.dg/abi/nsdmi-aggr1a.C base-commit: 807ad4bc854caea407aaa09993e4a3220290b0f0 diff --git a/gcc/common.opt b/gcc/common.opt index 8f8fc2f9ee7..4af89ce8fd2 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -990,6 +990,10 @@ Driver Undocumented ; Adds missing 'on' in mangling of operator names in some cases. ; Default in G++ 11. ; +; 17: Fixes layout of classes that inherit from aggregate classes with default +; member initializers in C++14 and up. +; Default in G++ 12. +; ; Additional positive integers will be assigned as new versions of ; the ABI become the default version of the ABI. fabi-version= diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7f32cf56383..191143025a3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2343,6 +2343,7 @@ struct GTY(()) lang_type { unsigned unique_obj_representations : 1; unsigned unique_obj_representations_set : 1; bool erroneous : 1; + bool non_pod_aggregate : 1; /* When adding a flag here, consider whether or not it ought to apply to a template instance if it applies to the template. If @@ -2351,7 +2352,7 @@ struct GTY(()) lang_type { /* There are some bits left to fill out a 32-bit word. Keep track of this by updating the size of this bitfield whenever you add or remove a flag. */ - unsigned dummy : 4; + unsigned dummy : 3; tree primary_base; vec *vcall_indices; @@ -2671,6 +2672,12 @@ struct GTY(()) lang_type { /* True if we saw errors while instantiating this class. */ #define CLASSTYPE_ERRONEOUS(NODE) \ (LANG_TYPE_CLASS_CHECK (NODE)->erroneous) + +/* True if this class is non-layout-POD only because it was not an aggregate + before C++14. If we run out of bits in lang_type, this could be replaced + with a hash_set only filled in when abi_version_crosses (17). */ +#define CLASSTYPE_NON_POD_AGGREGATE(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->non_pod_aggregate) /* Additional macros for inheritance information. */ diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index 93845d57dee..4c20e44f5b5 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -975,9 +975,9 @@ c_common_post_options (const char **pfilename) /* Change flag_abi_version to be the actual current ABI level, for the benefit of c_cpp_builtins, and to make comparison simpler. */ - const int latest_abi_version = 16; - /* Generate compatibility aliases for ABI v11 (7.1) by default. */ - const int abi_compat_default = 11; + const int latest_abi_version = 17; + /* Generate compatibility aliases for ABI v13 (8.2) by default. */ + const int abi_compat_default = 13; #define clamp(X) if (X == 0 || X > latest_abi_version) X = latest_abi_version clamp (flag_abi_version); diff --git a/gcc/cp/class.c b/gcc/cp/class.c index c30a44f039b..e70c535b3f2 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3857,9 +3857,14 @@ check_field_decls (tree t, tree *access_decls, /* Now that we've removed bit-field widths from DECL_INITIAL, anything left in DECL_INITIAL is an NSDMI that makes the class - non-aggregate in C++11. */ - if (DECL_INITIAL (field) && cxx_dialect < cxx14) - CLASSTYPE_NON_AGGREGATE (t) = true; + non-aggregate in C++11, and non-layout-POD always. */ + if (DECL_INITIAL (field)) + { + if (cxx_dialect < cxx14) + CLASSTYPE_NON_AGGREGATE (t) = true; + else + CLASSTYPE_NON_POD_AGGREGATE (t) = true; + } if (CP_TYPE_CONST_P (type)) { @@ -6045,6 +6050,16 @@ check_bases_and_members (tree t) TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) |= TYPE_CONTAINS_VPTR_P (t); TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_CONTAINS_VPTR_P (t); + /* Is this class non-layout-POD because it wasn't an aggregate in C++98? */ + if (CLASSTYPE_NON_POD_AGGREGATE (t)) + { + if (CLASSTYPE_NON_LAYOUT_POD_P (t)) + /* It's non-POD for another reason. */ + CLASSTYPE_NON_POD_AGGREGATE (t) = false; + else if (abi_version_at_least (17)) + CLASSTYPE_NON_LAYOUT_POD_P (t) = true; + } + /* If the only explicitly declared default constructor is user-provided, set TYPE_HAS_COMPLEX_DFLT. */ if (!TYPE_HAS_COMPLEX_DFLT (t) @@ -6341,12 +6356,17 @@ end_of_base (tree binfo) return size_binop (PLUS_EXPR, BINFO_OFFSET (binfo), size); } -/* Returns the offset of the byte just past the end of the base class or empty - data member with the highest offset in T. If INCLUDE_VIRTUALS_P is zero, - then only non-virtual bases are included. */ +/* Returns one of three variations of the ending offset of T. If MODE is + eoc_nvsize, the result is the ABI "nvsize" (i.e. sizeof before allocating + vbases). If MODE is eoc_vsize, the result is the sizeof after allocating + vbases but before rounding, which is not named in the ABI. If MODE is + eoc_nv_or_dsize, the result is the greater of "nvsize" and "dsize" (the size + of the actual data in the class, kinda), as used for allocation of + potentially-overlapping fields. */ +enum eoc_mode { eoc_nvsize, eoc_vsize, eoc_nv_or_dsize }; static tree -end_of_class (tree t, bool include_virtuals_p) +end_of_class (tree t, eoc_mode mode) { tree result = size_zero_node; vec *vbases; @@ -6358,8 +6378,7 @@ end_of_class (tree t, bool include_virtuals_p) for (binfo = TYPE_BINFO (t), i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i) { - if (!include_virtuals_p - && BINFO_VIRTUAL_P (base_binfo) + if (BINFO_VIRTUAL_P (base_binfo) && (!BINFO_PRIMARY_P (base_binfo) || BINFO_INHERITANCE_CHAIN (base_binfo) != TYPE_BINFO (t))) continue; @@ -6369,25 +6388,35 @@ end_of_class (tree t, bool include_virtuals_p) result = offset; } - /* Also consider empty data members. */ for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL - && !DECL_ARTIFICIAL (field) - && field_poverlapping_p (field) - && is_empty_class (TREE_TYPE (field))) + && !DECL_FIELD_IS_BASE (field)) { - /* Update sizeof(C) to max (sizeof(C), offset(D)+sizeof(D)) */ - offset = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (field), - TYPE_SIZE_UNIT (TREE_TYPE (field))); + tree size = DECL_SIZE_UNIT (field); + if (!size) + /* DECL_SIZE_UNIT can be null for a flexible array. */ + continue; + + if (is_empty_field (field)) + /* For empty fields DECL_SIZE_UNIT is 0, but we want the + size of the type (usually 1) for computing nvsize. */ + size = TYPE_SIZE_UNIT (TREE_TYPE (field)); + + offset = size_binop (PLUS_EXPR, byte_position (field), size); if (tree_int_cst_lt (result, offset)) result = offset; } - if (include_virtuals_p) + if (mode != eoc_nvsize) for (vbases = CLASSTYPE_VBASECLASSES (t), i = 0; vec_safe_iterate (vbases, i, &base_binfo); i++) { - offset = end_of_base (base_binfo); + if (mode == eoc_nv_or_dsize) + /* For dsize, don't count trailing empty bases. */ + offset = size_binop (PLUS_EXPR, BINFO_OFFSET (binfo), + CLASSTYPE_SIZE_UNIT (BINFO_TYPE (binfo))); + else + offset = end_of_base (base_binfo); if (tree_int_cst_lt (result, offset)) result = offset; } @@ -6395,6 +6424,45 @@ end_of_class (tree t, bool include_virtuals_p) return result; } +/* Warn as appropriate about the change in whether we pack into the tail + padding of FIELD, a base field which has a C++14 aggregate type with default + member initializers. */ + +static void +check_non_pod_aggregate (tree field) +{ + if (!abi_version_crosses (17) || cxx_dialect < cxx14) + return; + if (TREE_CODE (field) != FIELD_DECL + || (!DECL_FIELD_IS_BASE (field) + && !field_poverlapping_p (field))) + return; + tree next = DECL_CHAIN (field); + while (next && TREE_CODE (next) != FIELD_DECL) next = DECL_CHAIN (next); + if (!next) + return; + tree type = TREE_TYPE (field); + if (TYPE_IDENTIFIER (type) == as_base_identifier) + type = TYPE_CONTEXT (type); + if (!CLASS_TYPE_P (type) || !CLASSTYPE_NON_POD_AGGREGATE (type)) + return; + tree size = end_of_class (type, (DECL_FIELD_IS_BASE (field) + ? eoc_nvsize : eoc_nv_or_dsize)); + tree rounded = round_up_loc (input_location, size, DECL_ALIGN_UNIT (next)); + if (tree_int_cst_lt (rounded, TYPE_SIZE_UNIT (type))) + { + location_t loc = DECL_SOURCE_LOCATION (next); + if (DECL_FIELD_IS_BASE (next)) + warning_at (loc, OPT_Wabi,"offset of %qT base class for " + "%<-std=c++14%> and up changes in " + "%<-fabi-version=17%> (GCC 12)", TREE_TYPE (next)); + else + warning_at (loc, OPT_Wabi, "offset of %qD for " + "%<-std=c++14%> and up changes in " + "%<-fabi-version=17%> (GCC 12)", next); + } +} + /* Warn about bases of T that are inaccessible because they are ambiguous. For example: @@ -6468,7 +6536,7 @@ include_empty_classes (record_layout_info rli) because we are willing to overlay multiple bases at the same offset. However, now we need to make sure that RLI is big enough to reflect the entire class. */ - eoc = end_of_class (rli->t, CLASSTYPE_AS_BASE (rli->t) != NULL_TREE); + eoc = end_of_class (rli->t, eoc_vsize); rli_size = rli_size_unit_so_far (rli); if (TREE_CODE (rli_size) == INTEGER_CST && tree_int_cst_lt (rli_size, eoc)) @@ -6580,21 +6648,13 @@ layout_class_type (tree t, tree *virtuals_p) { /* if D is a potentially-overlapping data member, update sizeof(C) to max (sizeof(C), offset(D)+max (nvsize(D), dsize(D))). */ - tree nvsize = CLASSTYPE_SIZE_UNIT (type); - /* end_of_class doesn't always give dsize, but it does in the case of - a class with virtual bases, which is when dsize > nvsize. */ - tree dsize = end_of_class (type, /*vbases*/true); if (CLASSTYPE_EMPTY_P (type)) DECL_SIZE (field) = DECL_SIZE_UNIT (field) = size_zero_node; - else if (tree_int_cst_le (dsize, nvsize)) - { - DECL_SIZE_UNIT (field) = nvsize; - DECL_SIZE (field) = CLASSTYPE_SIZE (type); - } else { - DECL_SIZE_UNIT (field) = dsize; - DECL_SIZE (field) = bit_from_pos (dsize, bitsize_zero_node); + tree size = end_of_class (type, eoc_nv_or_dsize); + DECL_SIZE_UNIT (field) = size; + DECL_SIZE (field) = bit_from_pos (size, bitsize_zero_node); } } @@ -6760,16 +6820,19 @@ layout_class_type (tree t, tree *virtuals_p) instead, so that the backends can emit -Wpsabi warnings in the cases where the ABI changed. */ for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL - && DECL_C_BIT_FIELD (field) - /* We should not be confused by the fact that grokbitfield - temporarily sets the width of the bit field into - DECL_BIT_FIELD_REPRESENTATIVE (field). - check_bitfield_decl eventually sets DECL_SIZE (field) - to that width. */ - && (DECL_SIZE (field) == NULL_TREE - || integer_zerop (DECL_SIZE (field)))) - SET_DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD (field, 1); + { + if (TREE_CODE (field) == FIELD_DECL + && DECL_C_BIT_FIELD (field) + /* We should not be confused by the fact that grokbitfield + temporarily sets the width of the bit field into + DECL_BIT_FIELD_REPRESENTATIVE (field). + check_bitfield_decl eventually sets DECL_SIZE (field) + to that width. */ + && (DECL_SIZE (field) == NULL_TREE + || integer_zerop (DECL_SIZE (field)))) + SET_DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD (field, 1); + check_non_pod_aggregate (field); + } if (CLASSTYPE_NON_LAYOUT_POD_P (t) || CLASSTYPE_EMPTY_P (t)) { @@ -6792,7 +6855,7 @@ layout_class_type (tree t, tree *virtuals_p) used to compute TYPE_SIZE_UNIT. */ /* Set the size and alignment for the new type. */ - tree eoc = end_of_class (t, /*include_virtuals_p=*/0); + tree eoc = end_of_class (t, eoc_nvsize); TYPE_SIZE_UNIT (base_t) = size_binop (MAX_EXPR, fold_convert (sizetype, diff --git a/gcc/testsuite/g++.dg/abi/macro0.C b/gcc/testsuite/g++.dg/abi/macro0.C index f25f291dba6..2d07fcdc631 100644 --- a/gcc/testsuite/g++.dg/abi/macro0.C +++ b/gcc/testsuite/g++.dg/abi/macro0.C @@ -1,6 +1,6 @@ // This testcase will need to be kept in sync with c_common_post_options. // { dg-options "-fabi-version=0" } -#if __GXX_ABI_VERSION != 1016 +#if __GXX_ABI_VERSION != 1017 #error "Incorrect value of __GXX_ABI_VERSION" #endif diff --git a/gcc/testsuite/g++.dg/abi/no_unique_address6.C b/gcc/testsuite/g++.dg/abi/no_unique_address6.C new file mode 100644 index 00000000000..5df6995c619 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/no_unique_address6.C @@ -0,0 +1,23 @@ +// { dg-do compile { target c++20 } } + +#pragma GCC diagnostic ignored "-Winvalid-offsetof" + +struct E { }; + +struct A: virtual E { + // Deny the vbase offset 0 so it goes at the end. + [[no_unique_address]] E e1; + char c; +}; + +struct B : public A { + char d; +}; + +struct C { + [[no_unique_address]] A a; + char d; +}; + +#define SA(X) static_assert ((X),#X) +SA(__builtin_offsetof (B, d) == __builtin_offsetof (C, d)); diff --git a/gcc/testsuite/g++.dg/abi/nsdmi-aggr1.C b/gcc/testsuite/g++.dg/abi/nsdmi-aggr1.C new file mode 100644 index 00000000000..c212c439a67 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/nsdmi-aggr1.C @@ -0,0 +1,39 @@ +// PR c++/103681 +// { dg-do compile { target c++11 } } +// { dg-additional-options "-fabi-version=16 -Wabi" } + +struct A { + long l; + char c = -1; +}; +struct B : public A { + char d; + // { dg-warning "offset" "" { target c++14 } .-1 } +}; + +#define SA(X) static_assert(X,#X) +SA(sizeof (B) == sizeof (A)); +// { dg-error "static assertion" "" { target c++14 } .-1 } + +struct X { char d; }; +struct B2 : A, X { }; +// { dg-warning "offset" "" { target c++14 } .-1 } +SA(sizeof (B2) == sizeof (A)); +// { dg-error "static assertion" "" { target c++14 } .-1 } + +#if __cplusplus > 201800L + +struct C { + [[no_unique_address]] A a; + char d; + // { dg-warning "offset" "" { target c++20 } .-1 } +}; +SA(sizeof (C) == sizeof (A)); +// { dg-error "static assertion" "" { target c++20 } .-1 } + +struct C2 : A, X { }; +// { dg-warning "offset" "" { target c++20 } .-1 } +SA(sizeof (B2) == sizeof (A)); +// { dg-error "static assertion" "" { target c++20 } .-1 } + +#endif /* C++20 */ diff --git a/gcc/testsuite/g++.dg/abi/nsdmi-aggr1a.C b/gcc/testsuite/g++.dg/abi/nsdmi-aggr1a.C new file mode 100644 index 00000000000..e7a509dbc85 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/nsdmi-aggr1a.C @@ -0,0 +1,35 @@ +// PR c++/103681 +// { dg-do compile { target c++11 } } +// { dg-additional-options "-fabi-version=0 -Wabi=16" } + +struct A { + long l; + char c = -1; +}; +struct B : public A { + char d; + // { dg-warning "offset" "" { target c++14 } .-1 } +}; + +#define SA(X) static_assert(X,#X) +SA(sizeof (B) == sizeof (A)); + +struct X { char d; }; +struct B2 : A, X { }; +// { dg-warning "offset" "" { target c++14 } .-1 } +SA(sizeof (B2) == sizeof (A)); + +#if __cplusplus > 201800L + +struct C { + [[no_unique_address]] A a; + char d; + // { dg-warning "offset" "" { target c++20 } .-1 } +}; +SA(sizeof (C) == sizeof (A)); + +struct C2 : A, X { }; +// { dg-warning "offset" "" { target c++20 } .-1 } +SA(sizeof (B2) == sizeof (A)); + +#endif /* C++20 */