[{"id":3687009,"web_url":"http://patchwork.ozlabs.org/comment/3687009/","msgid":"<CAKvuMXD1yPCW0jLSLc0ymq3wWgeS_fZcLbuSSzpL8mHG+TjGSg@mail.gmail.com>","list_archive_url":null,"date":"2026-05-06T11:52:19","subject":"Re: [PATCH v2 1/3] libstdc++: Replace uses of EBO with\n [[no_unique_address]]","submitter":{"id":90409,"url":"http://patchwork.ozlabs.org/api/people/90409/","name":"Tomasz Kamiński","email":"tkaminsk@redhat.com"},"content":"On Wed, May 6, 2026 at 12:13 PM Jonathan Wakely <jwakely@redhat.com> wrote:\n\n> Clang 9 added support for [[__no_unique_address__]] and we don't support\n> Intel icc any longer, so we can remove the code in <tuple> that works\n> around the absence of that attribute. We can also address a FIXME in\n> <bits/shared_ptr_base.h> and replace uses of EBO with the attribute.\n>\n> libstdc++-v3/ChangeLog:\n>\n>         * include/bits/shared_ptr_base.h (_Sp_ebo_helper): Simplify by\n>         using [[__no_unique_address__]] instead of EBO. Use the\n>         attribute unconditionally for the unstable ABI.\n>         (_Sp_counted_deleter::_Impl): Adjust uses of _Sp_ebo_helper.\n>         (_Sp_counted_ptr_inplace::_Impl): Likewise.\n>         * include/std/tuple (_Head_base): Remove implementation for\n>         compilers that don't support [[__no_unique_address__]]. Use the\n>         attribute unconditionally for the unstable ABI.\n> ---\n>\n> v2: Add the attribute to the data members of _Impl as well as to the\n> _M_obj data member of _Sp_ebo_helper. Otherwise the _M_obj subobject is\n> potentially overlapping, but the _M_ and _M_d ones are not. We need both\n> to be marked with the attribute.\n>\n> What we *really* want is [[no_unique_address(expr)]] so that we can get\n> rid of _Sp_ebo_helper entirely, and just do:\n>\n>   #if ! _GLIBCXX_INLINE_VERSION // Stable ABI\n>   template<typename T> __can_overlap = !__is_final(T) && __is_empty(T);\n>   #else // Unstable ABI\n>   template<typename T> __can_overlap = true;\n>   #endif\n>   [[no_unique_address(__can_overlap<_Del>)]] _M_del;\n>\n> I should propose that to WG21, and if rejected just get it added to GCC\n> and Clang.\n>\n\n\n>\n> Tested x86_64-linux.\n>\nLGTM with one suggestion.\n\n>\n>  libstdc++-v3/include/bits/shared_ptr_base.h | 65 +++++++++----------\n>  libstdc++-v3/include/std/tuple              | 69 ++++-----------------\n>  2 files changed, 43 insertions(+), 91 deletions(-)\n>\n> diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h\n> b/libstdc++-v3/include/bits/shared_ptr_base.h\n> index b92e3a4c90e4..3ab73f6e4a0d 100644\n> --- a/libstdc++-v3/include/bits/shared_ptr_base.h\n> +++ b/libstdc++-v3/include/bits/shared_ptr_base.h\n> @@ -513,57 +513,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>      inline void\n>      _Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept { }\n>\n> -  // FIXME: once __has_cpp_attribute(__no_unique_address__)) is true for\n> -  // all supported compilers we can greatly simplify _Sp_ebo_helper.\n> +#if ! __has_cpp_attribute(__no_unique_address__)\n> +#error \"support for [[__no_unique_address__]] attribute is required\"\n> +#endif\n> +\n> +#if ! _GLIBCXX_INLINE_VERSION\n>    // N.B. unconditionally applying the attribute could change layout for\n>    // final types, which currently cannot use EBO so have a unique address.\n> -\n> -  template<int _Nm, typename _Tp,\n> -          bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>\n> +  template<typename _Tp, bool = !__is_final(_Tp) && __is_empty(_Tp)>\n>      struct _Sp_ebo_helper;\n> +#else\n> +  template<typename _Tp, bool = true>\n> +    struct _Sp_ebo_helper;\n>\nThe name \"EBO helper\" no longer seems accurate, but\nI have no better suggestion.\n\n> +#endif\n>\n> -  /// Specialization using EBO.\n> -  template<int _Nm, typename _Tp>\n> -    struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp\n> +  /// Specialization using [[no_unique_address]].\n> +  template<typename _Tp>\n> +    struct _Sp_ebo_helper<_Tp, true>\n>      {\n> -      explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) { }\n> -      explicit _Sp_ebo_helper(_Tp&& __tp) : _Tp(std::move(__tp)) { }\n> -\n> -      static _Tp&\n> -      _S_get(_Sp_ebo_helper& __eboh) { return static_cast<_Tp&>(__eboh); }\n> +      [[__no_unique_address__]] _Tp _M_obj;\n>      };\n>\n> -  /// Specialization not using EBO.\n> -  template<int _Nm, typename _Tp>\n> -    struct _Sp_ebo_helper<_Nm, _Tp, false>\n> +#if ! _GLIBCXX_INLINE_VERSION\n> +  /// Specialization not using [[no_unique_address]].\n> +  template<typename _Tp>\n> +    struct _Sp_ebo_helper<_Tp, false>\n>      {\n> -      explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) { }\n> -      explicit _Sp_ebo_helper(_Tp&& __tp) : _M_tp(std::move(__tp)) { }\n> -\n> -      static _Tp&\n> -      _S_get(_Sp_ebo_helper& __eboh)\n> -      { return __eboh._M_tp; }\n> -\n> -    private:\n> -      _Tp _M_tp;\n> +      _Tp _M_obj;\n>      };\n> +#endif\n>\n>    // Support for custom deleter and/or allocator\n>    template<typename _Ptr, typename _Deleter, typename _Alloc,\n> _Lock_policy _Lp>\n>      class _Sp_counted_deleter final : public _Sp_counted_base<_Lp>\n>      {\n> -      class _Impl : _Sp_ebo_helper<0, _Deleter>, _Sp_ebo_helper<1, _Alloc>\n> +      class _Impl\n>        {\n> -       typedef _Sp_ebo_helper<0, _Deleter>     _Del_base;\n> -       typedef _Sp_ebo_helper<1, _Alloc>       _Alloc_base;\n> +       [[__no_unique_address__]] _Sp_ebo_helper<_Deleter> _M_d;\n> +       [[__no_unique_address__]] _Sp_ebo_helper<_Alloc>   _M_a;\n>\n>        public:\n>         _Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept\n> -       : _Del_base(std::move(__d)), _Alloc_base(__a), _M_ptr(__p)\n> +       : _M_d{std::move(__d)}, _M_a{__a}, _M_ptr(__p)\n>         { }\n>\n> -       _Deleter& _M_del() noexcept { return _Del_base::_S_get(*this); }\n> -       _Alloc& _M_alloc() noexcept { return _Alloc_base::_S_get(*this); }\n> +       _Deleter& _M_del() noexcept { return _M_d._M_obj; }\n> +       _Alloc& _M_alloc() noexcept { return _M_a._M_obj; }\n>\n>         _Ptr _M_ptr;\n>        };\n> @@ -645,14 +640,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>    template<typename _Tp, typename _Alloc, _Lock_policy _Lp>\n>      class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>\n>      {\n> -      class _Impl : _Sp_ebo_helper<0, _Alloc>\n> +      class _Impl\n>        {\n> -       typedef _Sp_ebo_helper<0, _Alloc>       _A_base;\n> +       [[__no_unique_address__]] _Sp_ebo_helper<_Alloc> _M_a;\n>\n>        public:\n> -       explicit _Impl(_Alloc __a) noexcept : _A_base(__a) { }\n> +       explicit _Impl(_Alloc __a) noexcept : _M_a{std::move(__a)} { }\n>\n> -       _Alloc& _M_alloc() noexcept { return _A_base::_S_get(*this); }\n> +       _Alloc& _M_alloc() noexcept { return _M_a._M_obj; }\n>\n>         __gnu_cxx::__aligned_buffer<__remove_cv_t<_Tp>> _M_storage;\n>        };\n> diff --git a/libstdc++-v3/include/std/tuple\n> b/libstdc++-v3/include/std/tuple\n> index f7caa79cda04..32800d8d7752 100644\n> --- a/libstdc++-v3/include/std/tuple\n> +++ b/libstdc++-v3/include/std/tuple\n> @@ -68,7 +68,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>    template<typename... _Elements>\n>      class tuple;\n>\n> +#if ! __has_cpp_attribute(__no_unique_address__)\n> +#error \"support for [[__no_unique_address__]] attribute is required\"\n> +#endif\n> +\n>    /// @cond undocumented\n> +#if ! _GLIBCXX_INLINE_VERSION\n>    template<typename _Tp>\n>      struct __is_empty_non_tuple : is_empty<_Tp> { };\n>\n> @@ -76,17 +81,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>    template<typename _El0, typename... _El>\n>      struct __is_empty_non_tuple<tuple<_El0, _El...>> : false_type { };\n>\n> -  // Use the Empty Base-class Optimization for empty, non-final types.\n> +  // Use [[no_unique_address]] for empty, non-final types.\n>    template<typename _Tp>\n>      using __empty_not_final\n>      = __conditional_t<__is_final(_Tp), false_type,\n>                       __is_empty_non_tuple<_Tp>>;\n> +#else\n> +  // For the unstable ABI we always use [[no_unique_address]].\n> +  template<typename>\n> +    using __empty_not_final = true_type;\n> +#endif\n>\n>    template<size_t _Idx, typename _Head,\n>            bool = __empty_not_final<_Head>::value>\n>      struct _Head_base;\n>\nWe forward declare  _Head_base anyway, so maybe instead of __empty_not_final\nwe should have two declarations: one that defaults to __conditional_t and\nanother.\nthat uses = true, as for _Sp_ebo_base. There seem to be non need for\nadditional\nclass template.\n\n>\n> -#if __has_cpp_attribute(__no_unique_address__)\n>    template<size_t _Idx, typename _Head>\n>      struct _Head_base<_Idx, _Head, true>\n>      {\n> @@ -141,61 +150,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>\n>        [[__no_unique_address__]] _Head _M_head_impl;\n>      };\n> -#else\n> -  template<size_t _Idx, typename _Head>\n> -    struct _Head_base<_Idx, _Head, true>\n> -    : public _Head\n> -    {\n> -      constexpr _Head_base()\n> -      : _Head() { }\n> -\n> -      constexpr _Head_base(const _Head& __h)\n> -      : _Head(__h) { }\n> -\n> -      constexpr _Head_base(const _Head_base&) = default;\n> -      constexpr _Head_base(_Head_base&&) = default;\n> -\n> -      template<typename _UHead>\n> -        constexpr _Head_base(_UHead&& __h)\n> -       : _Head(std::forward<_UHead>(__h)) { }\n> -\n> -      _GLIBCXX20_CONSTEXPR\n> -      _Head_base(allocator_arg_t, __uses_alloc0)\n> -      : _Head() { }\n> -\n> -      template<typename _Alloc>\n> -       _GLIBCXX20_CONSTEXPR\n> -       _Head_base(allocator_arg_t, __uses_alloc1<_Alloc> __a)\n> -       : _Head(allocator_arg, *__a._M_a) { }\n> -\n> -      template<typename _Alloc>\n> -       _GLIBCXX20_CONSTEXPR\n> -       _Head_base(allocator_arg_t, __uses_alloc2<_Alloc> __a)\n> -       : _Head(*__a._M_a) { }\n> -\n> -      template<typename _UHead>\n> -       _GLIBCXX20_CONSTEXPR\n> -       _Head_base(__uses_alloc0, _UHead&& __uhead)\n> -       : _Head(std::forward<_UHead>(__uhead)) { }\n> -\n> -      template<typename _Alloc, typename _UHead>\n> -       _GLIBCXX20_CONSTEXPR\n> -       _Head_base(__uses_alloc1<_Alloc> __a, _UHead&& __uhead)\n> -       : _Head(allocator_arg, *__a._M_a, std::forward<_UHead>(__uhead)) {\n> }\n> -\n> -      template<typename _Alloc, typename _UHead>\n> -       _GLIBCXX20_CONSTEXPR\n> -       _Head_base(__uses_alloc2<_Alloc> __a, _UHead&& __uhead)\n> -       : _Head(std::forward<_UHead>(__uhead), *__a._M_a) { }\n> -\n> -      static constexpr _Head&\n> -      _M_head(_Head_base& __b) noexcept { return __b; }\n> -\n> -      static constexpr const _Head&\n> -      _M_head(const _Head_base& __b) noexcept { return __b; }\n> -    };\n> -#endif\n>\n> +#if ! _GLIBCXX_INLINE_VERSION\n>\nNice improvment. Patrick once explained to me. that partial specialization\nmatching\nis linear in their number, so this may help a lot.\n\n>    template<size_t _Idx, typename _Head>\n>      struct _Head_base<_Idx, _Head, false>\n>      {\n> @@ -250,6 +206,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>\n>        _Head _M_head_impl;\n>      };\n> +#endif\n>\n>  #if __cpp_lib_tuple_like // >= C++23\n>    struct __tuple_like_tag_t { explicit __tuple_like_tag_t() = default; };\n> --\n> 2.54.0\n>\n>","headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=ZQlNk45+;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=ZQlNk45+","sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com","sourceware.org; spf=pass smtp.mailfrom=redhat.com","sourceware.org; arc=none smtp.remote-ip=170.10.133.124"],"Received":["from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g9YgQ2QNzz1yJq\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 06 May 2026 21:53:38 +1000 (AEST)","from vm01.sourceware.org (localhost [IPv6:::1])\n\tby sourceware.org (Postfix) with ESMTP id 4DE134BA799B\n\tfor <incoming@patchwork.ozlabs.org>; Wed,  6 May 2026 11:53:36 +0000 (GMT)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by sourceware.org (Postfix) with ESMTP id 3E4474BA23FE\n for <gcc-patches@gcc.gnu.org>; Wed,  6 May 2026 11:52:34 +0000 (GMT)","from mail-yw1-f199.google.com (mail-yw1-f199.google.com\n [209.85.128.199]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-614-QYvBHScOPVO6wy3aLWQK9w-1; Wed, 06 May 2026 07:52:32 -0400","by mail-yw1-f199.google.com with SMTP id\n 00721157ae682-7bd5c9e2e4aso121208327b3.2\n for <gcc-patches@gcc.gnu.org>; Wed, 06 May 2026 04:52:32 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 4DE134BA799B","OpenDKIM Filter v2.11.0 sourceware.org 3E4474BA23FE"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org 3E4474BA23FE","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org 3E4474BA23FE","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778068354; cv=none;\n b=YJsuNgnyN4AIT2FR8W9uvaKPejX6J9Tjta4snViwYfYw806zlb41uquZS+RnyNhi1qbKX86Y34zgcDqBkeXBCsHYhCdLDSMLy0OjZ7KeN6Uaof5j0fITTUQxiCJc+OuwmPuXmcuQXe0C6nUBx0IokjERygovq7MRIKj/RCSKm1w=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1778068354; c=relaxed/simple;\n bh=k79jKP+TOvIAwSwhHkMmt4WU87DRBPxCwh+V705pbks=;\n h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To;\n b=CiIyPxBFPu6ldIT5eBg4fO+4LOWqXMv3bfm24eae/06qS1EPDxjOlUy7lrAQvjC04zlrRnZeACDJjN1G1qqaraaARNmrXbMiimwW8pY597o7dCuwMlEzv8DsPOkuwnckgaMpHVlWMa3bqw5g3SJoia9JOj//j68yU6q1XqzHNAQ=","ARC-Authentication-Results":"i=1; sourceware.org;\n dkim=pass (1024-bit key, unprotected)\n header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=ZQlNk45+","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1778068353;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n in-reply-to:in-reply-to:references:references;\n bh=iSEOpa5H4Dst05jNNHKkrsW+9m0CfoYUf2OYGKs54N4=;\n b=ZQlNk45+CgWXL3GTD56U3opSFB4IlIJmm+X0SEwf4JigCdJhagjrRBsn/CeHKW+MOBJ2YQ\n OCEJPcilfPQ/LBs6SkDxxPckI/VHo9C0q1enssMVQW7GT7rXNzkTdxQn4BdOhn3gsL0HqM\n 8UIthHkA7QXcSpNYtQBnajJNIyqU42I=","X-MC-Unique":"QYvBHScOPVO6wy3aLWQK9w-1","X-Mimecast-MFC-AGG-ID":"QYvBHScOPVO6wy3aLWQK9w_1778068352","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1778068352; x=1778673152;\n h=cc:to:subject:message-id:date:from:in-reply-to:references\n :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=iSEOpa5H4Dst05jNNHKkrsW+9m0CfoYUf2OYGKs54N4=;\n b=rmD4SHL5EMEiCkDrFYuhybGZh9k0F098SZiPeETGpmrbM2N/RXksd3Q5Y1cdBQ5i4d\n 9/QjXP1pe6aJjRcAmk8tk+5vCHEX0i1T7ZirfBM9kTdjZQsxeWDhcA/ZwY7w/YN/Lfmt\n KmBVduVQ+4XWQ4OV9iIpFgiqCVdTmBgEijADfSEqBLJtDpWhSBHhkEZLMF3ApruEeoR/\n aGDbnxNC+atNoxFupGKQrQMP5kmVhQZBz9QWG+nFAtSYQfQXJMsltOgi/K/HJzt9Ss+j\n 1vC0hAOj5ZzPp5SGJpEcuaQ6Hzh7VsJPNE+oHrcP7FpKGTsNIDUhYiR8ou8mxYjdSwsg\n CCLQ==","X-Gm-Message-State":"AOJu0Yw7ErtkeMNyEmSFV6cEvr/gqZ4dWCpZVzo3dwULdPIJ2ilogCyn\n OKx3H8lO2yaqOnjJdae9wSgx1Y8cnG3xTIG2seqXnVhDwhPdn8T4RLb4dsO8eohsNV9OFR9e+eJ\n pZmvjatVur3v2PrOyt15gi1tWuVcbWBhJX94W6PYyeSK3pbFfqm9fCPS9jz2WYehaohsdXlRJEv\n MDQn0fdzXuffDKC35IfxLm6UsttIfIbmmLjw==","X-Gm-Gg":"AeBDieveEHIP5MRMriXGqgS3UoIDRe8PV3o15mbdmXtuaJd3+mo7lUBjhE+PJ2ZCKct\n Se5tUJ+4N+xkYMOcYI9GQ7TJA3yFSQkQCIh5l7NYWk/DwitL8MNrDhT4KIUnWT+dtxg6z50trjH\n Umdzv7FDhFurllYx/92aH1ZzeB4QoCHf8dXyKEeZWUXlEbCdZHG4+rNNSUkvS2jpS0XGssVMXo9\n ZPyuNgLaMsIQBFNa2YwJPLkM/w9V9BMmnncVRe0B5HwAcDBQu45IgGiUtsI5iDSSUef1Ge0Fwyn\n a0Q=","X-Received":["by 2002:a05:690c:56c7:b0:7bd:b048:88d with SMTP id\n 00721157ae682-7bdf5dc6e39mr31142467b3.14.1778068351946;\n Wed, 06 May 2026 04:52:31 -0700 (PDT)","by 2002:a05:690c:56c7:b0:7bd:b048:88d with SMTP id\n 00721157ae682-7bdf5dc6e39mr31142237b3.14.1778068351384; Wed, 06 May 2026\n 04:52:31 -0700 (PDT)"],"MIME-Version":"1.0","References":"<20260506085339.325517-1-jwakely@redhat.com>","In-Reply-To":"<20260506085339.325517-1-jwakely@redhat.com>","From":"Tomasz Kaminski <tkaminsk@redhat.com>","Date":"Wed, 6 May 2026 13:52:19 +0200","X-Gm-Features":"AVHnY4Ka_jFn8QojjQHz_9iD0LH796kbLmlbdtiXjmGakzszUooipWzt5k2cZlg","Message-ID":"\n <CAKvuMXD1yPCW0jLSLc0ymq3wWgeS_fZcLbuSSzpL8mHG+TjGSg@mail.gmail.com>","Subject":"Re: [PATCH v2 1/3] libstdc++: Replace uses of EBO with\n [[no_unique_address]]","To":"Jonathan Wakely <jwakely@redhat.com>","Cc":"gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"EyYtBAtJV88-jVbgp9d6L7jtKeJPZHZT5r9wED5opYs_1778068352","X-Mimecast-Originator":"redhat.com","Content-Type":"multipart/alternative; boundary=\"000000000000789f62065124ccee\"","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"}},{"id":3687023,"web_url":"http://patchwork.ozlabs.org/comment/3687023/","msgid":"<CACb0b4mMNJMZQCgGu_cJB_2Cgssafuw+w0iApbFpKTCfFeSdEQ@mail.gmail.com>","list_archive_url":null,"date":"2026-05-06T12:12:54","subject":"Re: [PATCH v2 1/3] libstdc++: Replace uses of EBO with\n [[no_unique_address]]","submitter":{"id":48004,"url":"http://patchwork.ozlabs.org/api/people/48004/","name":"Jonathan Wakely","email":"jwakely@redhat.com"},"content":"On Wed, 6 May 2026 at 12:52, Tomasz Kaminski <tkaminsk@redhat.com> wrote:\n>\n>\n>\n> On Wed, May 6, 2026 at 12:13 PM Jonathan Wakely <jwakely@redhat.com> wrote:\n>>\n>> Clang 9 added support for [[__no_unique_address__]] and we don't support\n>> Intel icc any longer, so we can remove the code in <tuple> that works\n>> around the absence of that attribute. We can also address a FIXME in\n>> <bits/shared_ptr_base.h> and replace uses of EBO with the attribute.\n>>\n>> libstdc++-v3/ChangeLog:\n>>\n>>         * include/bits/shared_ptr_base.h (_Sp_ebo_helper): Simplify by\n>>         using [[__no_unique_address__]] instead of EBO. Use the\n>>         attribute unconditionally for the unstable ABI.\n>>         (_Sp_counted_deleter::_Impl): Adjust uses of _Sp_ebo_helper.\n>>         (_Sp_counted_ptr_inplace::_Impl): Likewise.\n>>         * include/std/tuple (_Head_base): Remove implementation for\n>>         compilers that don't support [[__no_unique_address__]]. Use the\n>>         attribute unconditionally for the unstable ABI.\n>> ---\n>>\n>> v2: Add the attribute to the data members of _Impl as well as to the\n>> _M_obj data member of _Sp_ebo_helper. Otherwise the _M_obj subobject is\n>> potentially overlapping, but the _M_ and _M_d ones are not. We need both\n>> to be marked with the attribute.\n>>\n>> What we *really* want is [[no_unique_address(expr)]] so that we can get\n>> rid of _Sp_ebo_helper entirely, and just do:\n>>\n>>   #if ! _GLIBCXX_INLINE_VERSION // Stable ABI\n>>   template<typename T> __can_overlap = !__is_final(T) && __is_empty(T);\n>>   #else // Unstable ABI\n>>   template<typename T> __can_overlap = true;\n>>   #endif\n>>   [[no_unique_address(__can_overlap<_Del>)]] _M_del;\n>>\n>> I should propose that to WG21, and if rejected just get it added to GCC\n>> and Clang.\n>\n>\n>>\n>>\n>> Tested x86_64-linux.\n>\n> LGTM with one suggestion.\n>>\n>>\n>>  libstdc++-v3/include/bits/shared_ptr_base.h | 65 +++++++++----------\n>>  libstdc++-v3/include/std/tuple              | 69 ++++-----------------\n>>  2 files changed, 43 insertions(+), 91 deletions(-)\n>>\n>> diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h\n>> index b92e3a4c90e4..3ab73f6e4a0d 100644\n>> --- a/libstdc++-v3/include/bits/shared_ptr_base.h\n>> +++ b/libstdc++-v3/include/bits/shared_ptr_base.h\n>> @@ -513,57 +513,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>>      inline void\n>>      _Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept { }\n>>\n>> -  // FIXME: once __has_cpp_attribute(__no_unique_address__)) is true for\n>> -  // all supported compilers we can greatly simplify _Sp_ebo_helper.\n>> +#if ! __has_cpp_attribute(__no_unique_address__)\n>> +#error \"support for [[__no_unique_address__]] attribute is required\"\n>> +#endif\n>> +\n>> +#if ! _GLIBCXX_INLINE_VERSION\n>>    // N.B. unconditionally applying the attribute could change layout for\n>>    // final types, which currently cannot use EBO so have a unique address.\n>> -\n>> -  template<int _Nm, typename _Tp,\n>> -          bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>\n>> +  template<typename _Tp, bool = !__is_final(_Tp) && __is_empty(_Tp)>\n>>      struct _Sp_ebo_helper;\n>> +#else\n>> +  template<typename _Tp, bool = true>\n>> +    struct _Sp_ebo_helper;\n>\n> The name \"EBO helper\" no longer seems accurate, but\n> I have no better suggestion.\n\nYes, I had the same thought. Something like \"_Alloc_overlapping\" could\nwork, but is longer and unless you already understand what that means,\nit isn't any more understandable than \"EBO helper\".\n\n>>\n>> +#endif\n>>\n>> -  /// Specialization using EBO.\n>> -  template<int _Nm, typename _Tp>\n>> -    struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp\n>> +  /// Specialization using [[no_unique_address]].\n>> +  template<typename _Tp>\n>> +    struct _Sp_ebo_helper<_Tp, true>\n>>      {\n>> -      explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) { }\n>> -      explicit _Sp_ebo_helper(_Tp&& __tp) : _Tp(std::move(__tp)) { }\n>> -\n>> -      static _Tp&\n>> -      _S_get(_Sp_ebo_helper& __eboh) { return static_cast<_Tp&>(__eboh); }\n>> +      [[__no_unique_address__]] _Tp _M_obj;\n>>      };\n>>\n>> -  /// Specialization not using EBO.\n>> -  template<int _Nm, typename _Tp>\n>> -    struct _Sp_ebo_helper<_Nm, _Tp, false>\n>> +#if ! _GLIBCXX_INLINE_VERSION\n>> +  /// Specialization not using [[no_unique_address]].\n>> +  template<typename _Tp>\n>> +    struct _Sp_ebo_helper<_Tp, false>\n>>      {\n>> -      explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) { }\n>> -      explicit _Sp_ebo_helper(_Tp&& __tp) : _M_tp(std::move(__tp)) { }\n>> -\n>> -      static _Tp&\n>> -      _S_get(_Sp_ebo_helper& __eboh)\n>> -      { return __eboh._M_tp; }\n>> -\n>> -    private:\n>> -      _Tp _M_tp;\n>> +      _Tp _M_obj;\n>>      };\n>> +#endif\n>>\n>>    // Support for custom deleter and/or allocator\n>>    template<typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp>\n>>      class _Sp_counted_deleter final : public _Sp_counted_base<_Lp>\n>>      {\n>> -      class _Impl : _Sp_ebo_helper<0, _Deleter>, _Sp_ebo_helper<1, _Alloc>\n>> +      class _Impl\n>>        {\n>> -       typedef _Sp_ebo_helper<0, _Deleter>     _Del_base;\n>> -       typedef _Sp_ebo_helper<1, _Alloc>       _Alloc_base;\n>> +       [[__no_unique_address__]] _Sp_ebo_helper<_Deleter> _M_d;\n>> +       [[__no_unique_address__]] _Sp_ebo_helper<_Alloc>   _M_a;\n>>\n>>        public:\n>>         _Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept\n>> -       : _Del_base(std::move(__d)), _Alloc_base(__a), _M_ptr(__p)\n>> +       : _M_d{std::move(__d)}, _M_a{__a}, _M_ptr(__p)\n>>         { }\n>>\n>> -       _Deleter& _M_del() noexcept { return _Del_base::_S_get(*this); }\n>> -       _Alloc& _M_alloc() noexcept { return _Alloc_base::_S_get(*this); }\n>> +       _Deleter& _M_del() noexcept { return _M_d._M_obj; }\n>> +       _Alloc& _M_alloc() noexcept { return _M_a._M_obj; }\n>>\n>>         _Ptr _M_ptr;\n>>        };\n>> @@ -645,14 +640,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>>    template<typename _Tp, typename _Alloc, _Lock_policy _Lp>\n>>      class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>\n>>      {\n>> -      class _Impl : _Sp_ebo_helper<0, _Alloc>\n>> +      class _Impl\n>>        {\n>> -       typedef _Sp_ebo_helper<0, _Alloc>       _A_base;\n>> +       [[__no_unique_address__]] _Sp_ebo_helper<_Alloc> _M_a;\n>>\n>>        public:\n>> -       explicit _Impl(_Alloc __a) noexcept : _A_base(__a) { }\n>> +       explicit _Impl(_Alloc __a) noexcept : _M_a{std::move(__a)} { }\n>>\n>> -       _Alloc& _M_alloc() noexcept { return _A_base::_S_get(*this); }\n>> +       _Alloc& _M_alloc() noexcept { return _M_a._M_obj; }\n>>\n>>         __gnu_cxx::__aligned_buffer<__remove_cv_t<_Tp>> _M_storage;\n>>        };\n>> diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple\n>> index f7caa79cda04..32800d8d7752 100644\n>> --- a/libstdc++-v3/include/std/tuple\n>> +++ b/libstdc++-v3/include/std/tuple\n>> @@ -68,7 +68,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>>    template<typename... _Elements>\n>>      class tuple;\n>>\n>> +#if ! __has_cpp_attribute(__no_unique_address__)\n>> +#error \"support for [[__no_unique_address__]] attribute is required\"\n>> +#endif\n>> +\n>>    /// @cond undocumented\n>> +#if ! _GLIBCXX_INLINE_VERSION\n>>    template<typename _Tp>\n>>      struct __is_empty_non_tuple : is_empty<_Tp> { };\n>>\n>> @@ -76,17 +81,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>>    template<typename _El0, typename... _El>\n>>      struct __is_empty_non_tuple<tuple<_El0, _El...>> : false_type { };\n>>\n>> -  // Use the Empty Base-class Optimization for empty, non-final types.\n>> +  // Use [[no_unique_address]] for empty, non-final types.\n>>    template<typename _Tp>\n>>      using __empty_not_final\n>>      = __conditional_t<__is_final(_Tp), false_type,\n>>                       __is_empty_non_tuple<_Tp>>;\n>> +#else\n>> +  // For the unstable ABI we always use [[no_unique_address]].\n>> +  template<typename>\n>> +    using __empty_not_final = true_type;\n>> +#endif\n>>\n>>    template<size_t _Idx, typename _Head,\n>>            bool = __empty_not_final<_Head>::value>\n>>      struct _Head_base;\n>\n> We forward declare  _Head_base anyway, so maybe instead of __empty_not_final\n> we should have two declarations: one that defaults to __conditional_t and another.\n> that uses = true, as for _Sp_ebo_base. There seem to be non need for additional\n> class template.\n\nSo something like this:\n\n#if ! _GLIBCXX_INLINE_VERSION\n  template<typename _Tp>\n    struct __is_empty_non_tuple : is_empty<_Tp> { };\n\n  // Using EBO for elements that are tuples causes ambiguous base errors.\n  template<typename _El0, typename... _El>\n    struct __is_empty_non_tuple<tuple<_El0, _El...>> : false_type { };\n\n  // Use [[no_unique_address]] for empty, non-final types.\n  template<typename _Tp>\n    using __empty_not_final\n    = __conditional_t<__is_final(_Tp), false_type,\n              __is_empty_non_tuple<_Tp>>;\n\n  template<size_t _Idx, typename _Head,\n       bool = __empty_not_final<_Head>::value>\n    struct _Head_base;\n#else\n  // For the unstable ABI we always use [[no_unique_address]].\n  template<size_t _Idx, typename _Head, bool = true>\n    struct _Head_base;\n#endif\n\n  template<size_t _Idx, typename _Head, bool>\n    struct _Head_base\n    {\n\nSo instead of two partial specializations (for true/false) we would\nhave the primary template and the partial specialization for false.\nFor the unstable ABI, we would have only the primary template, so no\npartial specialization to match.\n\nWe could even go one step further and remove the bool parameter for\nthe unstable ABI, to reduce the length of the symbol names:\n\n#if ! _GLIBCXX_INLINE_VERSION\n  ...\n\n  template<size_t _Idx, typename _Head,\n       bool = __empty_not_final<_Head>::value>\n    struct _Head_base\n#else\n  // For the unstable ABI we always use [[no_unique_address]].\n  template<size_t _Idx, typename _Head>\n    struct _Head_base\n#endif\n    {\n      constexpr _Head_base()\n      : _M_head_impl() { }","headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=Aft/1vDy;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=Aft/1vDy","sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com","sourceware.org; spf=pass smtp.mailfrom=redhat.com","sourceware.org; arc=none smtp.remote-ip=170.10.129.124"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g9Z713FFDz1yJV\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 06 May 2026 22:14:04 +1000 (AEST)","from vm01.sourceware.org (localhost [IPv6:::1])\n\tby sourceware.org (Postfix) with ESMTP id 0CF124BA79AA\n\tfor <incoming@patchwork.ozlabs.org>; Wed,  6 May 2026 12:14:02 +0000 (GMT)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by sourceware.org (Postfix) with ESMTP id F0EF34BA2E3A\n for <gcc-patches@gcc.gnu.org>; Wed,  6 May 2026 12:13:12 +0000 (GMT)","from mail-yx1-f72.google.com (mail-yx1-f72.google.com\n [74.125.224.72]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-61-uvSwwJRqPKKhEoz__WlheQ-1; Wed, 06 May 2026 08:13:11 -0400","by mail-yx1-f72.google.com with SMTP id\n 956f58d0204a3-65c3132b7e5so9102976d50.2\n for <gcc-patches@gcc.gnu.org>; Wed, 06 May 2026 05:13:11 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 0CF124BA79AA","OpenDKIM Filter v2.11.0 sourceware.org F0EF34BA2E3A"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org F0EF34BA2E3A","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org F0EF34BA2E3A","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778069593; cv=none;\n b=t9I1dbDfngLrMN6BwuaBA5KFsAYVLwQQ1500ZXrURMGT7+f7nyg31PPFlUU2ddO7haiMk6Ebqf+fTYZ2C4NzEYQKAoggXzgRTUztGG6JjzGkmM134wySHWbeO2Ys1emmvI7EF5lo2ppl/XCibo5SCeCjw2Lceuha263r98j6EXU=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1778069593; c=relaxed/simple;\n bh=477W0mZiZ5vuhGnFflwmQ6yoNMxq0zF5QPXKeN02ZBI=;\n h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To;\n b=xE+hyUSi+mmMugfSR+Y8SGJoaEPl22wRRD6vCxzjcpbrrlAUAXaPvpNzrZfEWqh/BwBHXK/IC2dzjVLlF29T++bIfsCy1QAifK+DMX5WznRxoRFfnBDdnGTSKp5tCcSlxIP8sR0/xNWdEeD2NV+Ny6wf0ktkQb7xqEdx3jxV87I=","ARC-Authentication-Results":"i=1; sourceware.org;\n dkim=pass (1024-bit key, unprotected)\n header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=Aft/1vDy","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1778069592;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=5d62y1ANdpBjGGwx3wlZxPlVzrh4zbXj5KeGv0BVHL4=;\n b=Aft/1vDyB3EVeyPSgYZvEJAVmKf9LqjmWCqMkQs0ENAm66DE/Hgp6TfaiXMJxhV/NjWaqq\n EzeMPi7tC3LaiEcA43u5883PlSwMS7baKGLeUmbeZZcrzX8jXyugigpnYHUnYP8nGvTxJf\n +frwdu927DX5x3VO2H3OvOIU6oGm+pk=","X-MC-Unique":"uvSwwJRqPKKhEoz__WlheQ-1","X-Mimecast-MFC-AGG-ID":"uvSwwJRqPKKhEoz__WlheQ_1778069591","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1778069591; x=1778674391;\n h=content-transfer-encoding:cc:to:subject:message-id:date:from\n :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=5d62y1ANdpBjGGwx3wlZxPlVzrh4zbXj5KeGv0BVHL4=;\n b=WNGPKxkRsClLk9jLOjbOefObVQB22xCsObkkdhGUSzDU7bZ/CrdgyQCwBTknQv6pjF\n huH4lr83ojerMja1kPg1QwtYZVY0qleZq/WSBLCRj1DZxOSw5qUYdWWpR2Rxi5gNLP+k\n 0XZXXtuMXOSCDrL5c1w6Y51GC8XebWSocv/kp7FcT3GIZYrvERJfve7BlAE2uPSoY47g\n xVSKpwh6KFcqLFsIu6IXUwu/DL9hKEkbyj865l2arZp7I0IrQG53SopHQjyDTYjeDyKg\n /s2e9MVwVgLWgXWbbD5cBrWwsqSTbjQvGWusB9P/yiBuu/55bQzBsBeqJ2bjHs9QPEpD\n Kz0g==","X-Gm-Message-State":"AOJu0YyxXX2eTMBJD+ZMO6s4l+NTmTKh/Z35Hbxv7+a++/3Eqwyve4Lv\n kdoJD/ECYZOZvPlwfRSqPqXjhYFWfQyBhqdgaUbAt3ygQlFz2BUmBuvxR1kQGr1foSCHAJH+rHa\n zzrdvZWsk6WnTLKgK01Aa23NVbb8J8afpKG2P0lCLtgLtfJLQE8LnECpYqxBV1MukVTcc89tE4g\n wVk2IlYWvsg4rmwUq2wT6tc/4h7ZgyfVdNHQ==","X-Gm-Gg":"AeBDiesEhp2Qhy4VHfAZUEw9hqmErAgwfgH6trkakElq69Dw8yB5tcRWpvWG6hY2yZq\n nxAipVxjm3nUo8UKqAEkcPr/iYEM43WeG0i9Kag3s8Wq5NFg4+2Dr04wtCI9eW+ZvRhouL87rL3\n XhJOQtkE4RtUSftdrcQr05x/rYN7acGahK7eRIej8L97UgvFYurmq4QxwYoj+yOp0x2lwUxEbgv\n 2n13H36KrdfkppXPTXTZN4F9CLXD/TWi9BDDw6Q+hoHLulkYjUBx2lXg2/dCK7ANb7y/jNwEW38\n hQ==","X-Received":["by 2002:a53:420c:0:b0:652:9ca7:98f4 with SMTP id\n 956f58d0204a3-65c79e604f8mr2317666d50.63.1778069590714;\n Wed, 06 May 2026 05:13:10 -0700 (PDT)","by 2002:a53:420c:0:b0:652:9ca7:98f4 with SMTP id\n 956f58d0204a3-65c79e604f8mr2317641d50.63.1778069590148; Wed, 06 May 2026\n 05:13:10 -0700 (PDT)"],"MIME-Version":"1.0","References":"<20260506085339.325517-1-jwakely@redhat.com>\n <CAKvuMXD1yPCW0jLSLc0ymq3wWgeS_fZcLbuSSzpL8mHG+TjGSg@mail.gmail.com>","In-Reply-To":"\n <CAKvuMXD1yPCW0jLSLc0ymq3wWgeS_fZcLbuSSzpL8mHG+TjGSg@mail.gmail.com>","From":"Jonathan Wakely <jwakely@redhat.com>","Date":"Wed, 6 May 2026 13:12:54 +0100","X-Gm-Features":"AVHnY4I1JY48S1caZTFwf4IRrym60_lPq7pjxuWswrF8GHq6GSYxJymXa2bcRQ0","Message-ID":"\n <CACb0b4mMNJMZQCgGu_cJB_2Cgssafuw+w0iApbFpKTCfFeSdEQ@mail.gmail.com>","Subject":"Re: [PATCH v2 1/3] libstdc++: Replace uses of EBO with\n [[no_unique_address]]","To":"Tomasz Kaminski <tkaminsk@redhat.com>","Cc":"gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"cT-Kc8nuiz9yq4L5C8u1wUQE3VdihJ49vyL-NP77Jg8_1778069591","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"}},{"id":3687024,"web_url":"http://patchwork.ozlabs.org/comment/3687024/","msgid":"<CACb0b4mo7jmNkqa6WBM6ZQ4v+d9psjSY68t02Cb_QiFy6v7FNw@mail.gmail.com>","list_archive_url":null,"date":"2026-05-06T12:14:24","subject":"Re: [PATCH v2 1/3] libstdc++: Replace uses of EBO with\n [[no_unique_address]]","submitter":{"id":48004,"url":"http://patchwork.ozlabs.org/api/people/48004/","name":"Jonathan Wakely","email":"jwakely@redhat.com"},"content":"On Wed, 6 May 2026 at 13:12, Jonathan Wakely <jwakely@redhat.com> wrote:\n>\n> On Wed, 6 May 2026 at 12:52, Tomasz Kaminski <tkaminsk@redhat.com> wrote:\n> >\n> >\n> >\n> > On Wed, May 6, 2026 at 12:13 PM Jonathan Wakely <jwakely@redhat.com> wrote:\n> >>\n> >> Clang 9 added support for [[__no_unique_address__]] and we don't support\n> >> Intel icc any longer, so we can remove the code in <tuple> that works\n> >> around the absence of that attribute. We can also address a FIXME in\n> >> <bits/shared_ptr_base.h> and replace uses of EBO with the attribute.\n> >>\n> >> libstdc++-v3/ChangeLog:\n> >>\n> >>         * include/bits/shared_ptr_base.h (_Sp_ebo_helper): Simplify by\n> >>         using [[__no_unique_address__]] instead of EBO. Use the\n> >>         attribute unconditionally for the unstable ABI.\n> >>         (_Sp_counted_deleter::_Impl): Adjust uses of _Sp_ebo_helper.\n> >>         (_Sp_counted_ptr_inplace::_Impl): Likewise.\n> >>         * include/std/tuple (_Head_base): Remove implementation for\n> >>         compilers that don't support [[__no_unique_address__]]. Use the\n> >>         attribute unconditionally for the unstable ABI.\n> >> ---\n> >>\n> >> v2: Add the attribute to the data members of _Impl as well as to the\n> >> _M_obj data member of _Sp_ebo_helper. Otherwise the _M_obj subobject is\n> >> potentially overlapping, but the _M_ and _M_d ones are not. We need both\n> >> to be marked with the attribute.\n> >>\n> >> What we *really* want is [[no_unique_address(expr)]] so that we can get\n> >> rid of _Sp_ebo_helper entirely, and just do:\n> >>\n> >>   #if ! _GLIBCXX_INLINE_VERSION // Stable ABI\n> >>   template<typename T> __can_overlap = !__is_final(T) && __is_empty(T);\n> >>   #else // Unstable ABI\n> >>   template<typename T> __can_overlap = true;\n> >>   #endif\n> >>   [[no_unique_address(__can_overlap<_Del>)]] _M_del;\n> >>\n> >> I should propose that to WG21, and if rejected just get it added to GCC\n> >> and Clang.\n> >\n> >\n> >>\n> >>\n> >> Tested x86_64-linux.\n> >\n> > LGTM with one suggestion.\n> >>\n> >>\n> >>  libstdc++-v3/include/bits/shared_ptr_base.h | 65 +++++++++----------\n> >>  libstdc++-v3/include/std/tuple              | 69 ++++-----------------\n> >>  2 files changed, 43 insertions(+), 91 deletions(-)\n> >>\n> >> diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h\n> >> index b92e3a4c90e4..3ab73f6e4a0d 100644\n> >> --- a/libstdc++-v3/include/bits/shared_ptr_base.h\n> >> +++ b/libstdc++-v3/include/bits/shared_ptr_base.h\n> >> @@ -513,57 +513,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> >>      inline void\n> >>      _Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept { }\n> >>\n> >> -  // FIXME: once __has_cpp_attribute(__no_unique_address__)) is true for\n> >> -  // all supported compilers we can greatly simplify _Sp_ebo_helper.\n> >> +#if ! __has_cpp_attribute(__no_unique_address__)\n> >> +#error \"support for [[__no_unique_address__]] attribute is required\"\n> >> +#endif\n> >> +\n> >> +#if ! _GLIBCXX_INLINE_VERSION\n> >>    // N.B. unconditionally applying the attribute could change layout for\n> >>    // final types, which currently cannot use EBO so have a unique address.\n> >> -\n> >> -  template<int _Nm, typename _Tp,\n> >> -          bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>\n> >> +  template<typename _Tp, bool = !__is_final(_Tp) && __is_empty(_Tp)>\n> >>      struct _Sp_ebo_helper;\n> >> +#else\n> >> +  template<typename _Tp, bool = true>\n> >> +    struct _Sp_ebo_helper;\n> >\n> > The name \"EBO helper\" no longer seems accurate, but\n> > I have no better suggestion.\n>\n> Yes, I had the same thought. Something like \"_Alloc_overlapping\" could\n\nOops, I meant \"_Allow_overlapping\" not Alloc.\n\n> work, but is longer and unless you already understand what that means,\n> it isn't any more understandable than \"EBO helper\".\n>","headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=Ag5/uaqx;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=Ag5/uaqx","sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com","sourceware.org; spf=pass smtp.mailfrom=redhat.com","sourceware.org; arc=none smtp.remote-ip=170.10.129.124"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g9Z8y5RyPz1y04\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 06 May 2026 22:15:46 +1000 (AEST)","from vm01.sourceware.org (localhost [IPv6:::1])\n\tby sourceware.org (Postfix) with ESMTP id 2CF704BA7982\n\tfor <incoming@patchwork.ozlabs.org>; Wed,  6 May 2026 12:15:44 +0000 (GMT)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by sourceware.org (Postfix) with ESMTP id E8FA44BA23CB\n for <gcc-patches@gcc.gnu.org>; Wed,  6 May 2026 12:14:43 +0000 (GMT)","from mail-yx1-f71.google.com (mail-yx1-f71.google.com\n [74.125.224.71]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-79-3cKmOsLnMVaS42jRUignMA-1; Wed, 06 May 2026 08:14:42 -0400","by mail-yx1-f71.google.com with SMTP id\n 956f58d0204a3-651c15e69d7so11923616d50.0\n for <gcc-patches@gcc.gnu.org>; Wed, 06 May 2026 05:14:41 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 2CF704BA7982","OpenDKIM Filter v2.11.0 sourceware.org E8FA44BA23CB"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org E8FA44BA23CB","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org E8FA44BA23CB","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778069684; cv=none;\n b=f7ar4Jf+Drct0Daqp/7jDSTs1/BJfxaxfxW4SYKpDdLt4F7HsGFB38a/Hr7zckURAQwae1E+b6mMiNqUMvrGMX+qhr6WvMRhBla3NIvnLZVdYAqLCySLjfCVr1R0J5Ck0Ie1RHbic9J8838H+DrZ8kfgrYHLOQjV0yTRz9VRQyM=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1778069684; c=relaxed/simple;\n bh=amhYURBm7s/4BP0LkAuU/eXyFRbbyY+BiIzTFdhSMFs=;\n h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To;\n b=Vy1mi1g3NxLR1/PXyVXfngNeScrtcNXxBmezgs4lifG0wQybyTEUDpEKu5uMqH8Uej04HRubIm1nBd11hIayYSIDFyQlzcBYlQzbVFqUEkzd34uwz6/ZH3Nv4GF0ojB2soSyO7zkTrOgEeNdOdzvsf6QiqpgMwyeezOYHn6+jWU=","ARC-Authentication-Results":"i=1; sourceware.org;\n dkim=pass (1024-bit key, unprotected)\n header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=Ag5/uaqx","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1778069683;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=Du72thFE68vMoRD8VuHqBXBwprvjGIXOEhWZ6vTNzS0=;\n b=Ag5/uaqxH7CzdRVkG1a1cyPv1M8YWGOmDPGV2r5AuQ+bP5ka6bsRLlMDTGTFDiBPonpwEZ\n lwi1NJQRBstgmt37G8VT0X+gOLphYkPstqqdc7OLkOqwKsWbX2VJvrT+AShfeQkhrKI+g8\n hYOhFyafiK4BQ0LpBOA0V7DP4u95V78=","X-MC-Unique":"3cKmOsLnMVaS42jRUignMA-1","X-Mimecast-MFC-AGG-ID":"3cKmOsLnMVaS42jRUignMA_1778069681","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1778069681; x=1778674481;\n h=content-transfer-encoding:cc:to:subject:message-id:date:from\n :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=Du72thFE68vMoRD8VuHqBXBwprvjGIXOEhWZ6vTNzS0=;\n b=VXoXciaZpW4r+4vY8ZUWOZUdWa258MtQtdXZLUgi7GYjp9oymEUlO6Mn2ojVU2Qslq\n QaP2wE6adPy4TuGt2Gff2siqUvcqhzY4WXCNqHxbH9q+AuFeQnaRuyK8b9L9Da8Av/R1\n FCW1eciEjl9yyb9j0UIHloGH82QTaG0z8rc4DLjvwgVWTZYFEqs1i87bFBYihbkUH2c9\n bCSZgnPTbAZZHZvE26kqJQzaxcf7QNFKbUdUgpTQs6Xd4zRzDfJXZB+x/0MQYjIcYIOb\n 4xVQY+iZ8UHW37Mhwhpj1+E1xxiI6CswOBMKoI+yI3A5N6j0+3Yjfoos38ldM6zYtfeQ\n AUbw==","X-Gm-Message-State":"AOJu0Yxib8BAZA8M2Od3ON/n6646Elpcmqj0r/lXbGwUGnOkyHw0ltr/\n DJOvXwaiGjgyV+GuhZsxj04VS9lIoteqDAwbdlMOyiT8YtKImO55QDLuBD+y+HRdkx9I5gz1h71\n aDuxc4Jioys1SoTnDoGJKw9/CzqO3Icp/17FEN3NuUrNS49HpQyg9kr/DMuPyVx9RrImbzUGwuj\n DC1zrePaAT7zofoW4DFFreC54muZ0H1WTKKg==","X-Gm-Gg":"AeBDietV5N4KyqVCUTgO63uBaQoZDcmdX5mT4Rf9tELZ8aRmELKYTzSuZxo6ev+RtKe\n oEgngvXenDa88QGBCOSZSAgRa+M/DASqXMcXYazNat3vFi/vWdqiZOyizeYM5TFyms3HyH9dTgx\n LdlrJHE70dRDRCq4716PkWrbpWy/Ny28sTYQRGWAC/aYJsAP6eKTUXl/ZA5ycLPB4MTYj7bOZZq\n gxP86deq7R12+riUfh3guJD8q54g6gFGmo/KBJwfPBexzRTNavvMKvX02dSSZUJAWAq03/xtwVw\n bQ==","X-Received":["by 2002:a05:690e:1408:b0:65c:468:7b6f with SMTP id\n 956f58d0204a3-65c79cc750amr3452681d50.25.1778069680649;\n Wed, 06 May 2026 05:14:40 -0700 (PDT)","by 2002:a05:690e:1408:b0:65c:468:7b6f with SMTP id\n 956f58d0204a3-65c79cc750amr3452663d50.25.1778069680237; Wed, 06 May 2026\n 05:14:40 -0700 (PDT)"],"MIME-Version":"1.0","References":"<20260506085339.325517-1-jwakely@redhat.com>\n <CAKvuMXD1yPCW0jLSLc0ymq3wWgeS_fZcLbuSSzpL8mHG+TjGSg@mail.gmail.com>\n <CACb0b4mMNJMZQCgGu_cJB_2Cgssafuw+w0iApbFpKTCfFeSdEQ@mail.gmail.com>","In-Reply-To":"\n <CACb0b4mMNJMZQCgGu_cJB_2Cgssafuw+w0iApbFpKTCfFeSdEQ@mail.gmail.com>","From":"Jonathan Wakely <jwakely@redhat.com>","Date":"Wed, 6 May 2026 13:14:24 +0100","X-Gm-Features":"AVHnY4JETEPFgCSvXHVoh3mvi-uFmgDgXDHfYLzcJ9KGIXw556rbuwR7tYxDboQ","Message-ID":"\n <CACb0b4mo7jmNkqa6WBM6ZQ4v+d9psjSY68t02Cb_QiFy6v7FNw@mail.gmail.com>","Subject":"Re: [PATCH v2 1/3] libstdc++: Replace uses of EBO with\n [[no_unique_address]]","To":"Tomasz Kaminski <tkaminsk@redhat.com>","Cc":"gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"olIKhSF7Kd0pZj3uaAEDig2Ee-uELGZ4231nRhBm8Pg_1778069681","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"}},{"id":3687036,"web_url":"http://patchwork.ozlabs.org/comment/3687036/","msgid":"<CAKvuMXDt7sNg9ZK0Rnpu0+-oLpOTuYVM0Wmh5eP0aUHDBmVJtw@mail.gmail.com>","list_archive_url":null,"date":"2026-05-06T12:36:59","subject":"Re: [PATCH v2 1/3] libstdc++: Replace uses of EBO with\n [[no_unique_address]]","submitter":{"id":90409,"url":"http://patchwork.ozlabs.org/api/people/90409/","name":"Tomasz Kamiński","email":"tkaminsk@redhat.com"},"content":"On Wed, May 6, 2026 at 2:13 PM Jonathan Wakely <jwakely@redhat.com> wrote:\n\n> On Wed, 6 May 2026 at 12:52, Tomasz Kaminski <tkaminsk@redhat.com> wrote:\n> >\n> >\n> >\n> > On Wed, May 6, 2026 at 12:13 PM Jonathan Wakely <jwakely@redhat.com>\n> wrote:\n> >>\n> >> Clang 9 added support for [[__no_unique_address__]] and we don't support\n> >> Intel icc any longer, so we can remove the code in <tuple> that works\n> >> around the absence of that attribute. We can also address a FIXME in\n> >> <bits/shared_ptr_base.h> and replace uses of EBO with the attribute.\n> >>\n> >> libstdc++-v3/ChangeLog:\n> >>\n> >>         * include/bits/shared_ptr_base.h (_Sp_ebo_helper): Simplify by\n> >>         using [[__no_unique_address__]] instead of EBO. Use the\n> >>         attribute unconditionally for the unstable ABI.\n> >>         (_Sp_counted_deleter::_Impl): Adjust uses of _Sp_ebo_helper.\n> >>         (_Sp_counted_ptr_inplace::_Impl): Likewise.\n> >>         * include/std/tuple (_Head_base): Remove implementation for\n> >>         compilers that don't support [[__no_unique_address__]]. Use the\n> >>         attribute unconditionally for the unstable ABI.\n> >> ---\n> >>\n> >> v2: Add the attribute to the data members of _Impl as well as to the\n> >> _M_obj data member of _Sp_ebo_helper. Otherwise the _M_obj subobject is\n> >> potentially overlapping, but the _M_ and _M_d ones are not. We need both\n> >> to be marked with the attribute.\n> >>\n> >> What we *really* want is [[no_unique_address(expr)]] so that we can get\n> >> rid of _Sp_ebo_helper entirely, and just do:\n> >>\n> >>   #if ! _GLIBCXX_INLINE_VERSION // Stable ABI\n> >>   template<typename T> __can_overlap = !__is_final(T) && __is_empty(T);\n> >>   #else // Unstable ABI\n> >>   template<typename T> __can_overlap = true;\n> >>   #endif\n> >>   [[no_unique_address(__can_overlap<_Del>)]] _M_del;\n> >>\n> >> I should propose that to WG21, and if rejected just get it added to GCC\n> >> and Clang.\n> >\n> >\n> >>\n> >>\n> >> Tested x86_64-linux.\n> >\n> > LGTM with one suggestion.\n> >>\n> >>\n> >>  libstdc++-v3/include/bits/shared_ptr_base.h | 65 +++++++++----------\n> >>  libstdc++-v3/include/std/tuple              | 69 ++++-----------------\n> >>  2 files changed, 43 insertions(+), 91 deletions(-)\n> >>\n> >> diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h\n> b/libstdc++-v3/include/bits/shared_ptr_base.h\n> >> index b92e3a4c90e4..3ab73f6e4a0d 100644\n> >> --- a/libstdc++-v3/include/bits/shared_ptr_base.h\n> >> +++ b/libstdc++-v3/include/bits/shared_ptr_base.h\n> >> @@ -513,57 +513,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> >>      inline void\n> >>      _Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept { }\n> >>\n> >> -  // FIXME: once __has_cpp_attribute(__no_unique_address__)) is true\n> for\n> >> -  // all supported compilers we can greatly simplify _Sp_ebo_helper.\n> >> +#if ! __has_cpp_attribute(__no_unique_address__)\n> >> +#error \"support for [[__no_unique_address__]] attribute is required\"\n> >> +#endif\n> >> +\n> >> +#if ! _GLIBCXX_INLINE_VERSION\n> >>    // N.B. unconditionally applying the attribute could change layout\n> for\n> >>    // final types, which currently cannot use EBO so have a unique\n> address.\n> >> -\n> >> -  template<int _Nm, typename _Tp,\n> >> -          bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>\n> >> +  template<typename _Tp, bool = !__is_final(_Tp) && __is_empty(_Tp)>\n> >>      struct _Sp_ebo_helper;\n> >> +#else\n> >> +  template<typename _Tp, bool = true>\n> >> +    struct _Sp_ebo_helper;\n> >\n> > The name \"EBO helper\" no longer seems accurate, but\n> > I have no better suggestion.\n>\n> Yes, I had the same thought. Something like \"_Alloc_overlapping\" could\n> work, but is longer and unless you already understand what that means,\n> it isn't any more understandable than \"EBO helper\".\n>\n> >>\n> >> +#endif\n> >>\n> >> -  /// Specialization using EBO.\n> >> -  template<int _Nm, typename _Tp>\n> >> -    struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp\n> >> +  /// Specialization using [[no_unique_address]].\n> >> +  template<typename _Tp>\n> >> +    struct _Sp_ebo_helper<_Tp, true>\n> >>      {\n> >> -      explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) { }\n> >> -      explicit _Sp_ebo_helper(_Tp&& __tp) : _Tp(std::move(__tp)) { }\n> >> -\n> >> -      static _Tp&\n> >> -      _S_get(_Sp_ebo_helper& __eboh) { return\n> static_cast<_Tp&>(__eboh); }\n> >> +      [[__no_unique_address__]] _Tp _M_obj;\n> >>      };\n> >>\n> >> -  /// Specialization not using EBO.\n> >> -  template<int _Nm, typename _Tp>\n> >> -    struct _Sp_ebo_helper<_Nm, _Tp, false>\n> >> +#if ! _GLIBCXX_INLINE_VERSION\n> >> +  /// Specialization not using [[no_unique_address]].\n> >> +  template<typename _Tp>\n> >> +    struct _Sp_ebo_helper<_Tp, false>\n> >>      {\n> >> -      explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) { }\n> >> -      explicit _Sp_ebo_helper(_Tp&& __tp) : _M_tp(std::move(__tp)) { }\n> >> -\n> >> -      static _Tp&\n> >> -      _S_get(_Sp_ebo_helper& __eboh)\n> >> -      { return __eboh._M_tp; }\n> >> -\n> >> -    private:\n> >> -      _Tp _M_tp;\n> >> +      _Tp _M_obj;\n> >>      };\n> >> +#endif\n> >>\n> >>    // Support for custom deleter and/or allocator\n> >>    template<typename _Ptr, typename _Deleter, typename _Alloc,\n> _Lock_policy _Lp>\n> >>      class _Sp_counted_deleter final : public _Sp_counted_base<_Lp>\n> >>      {\n> >> -      class _Impl : _Sp_ebo_helper<0, _Deleter>, _Sp_ebo_helper<1,\n> _Alloc>\n> >> +      class _Impl\n> >>        {\n> >> -       typedef _Sp_ebo_helper<0, _Deleter>     _Del_base;\n> >> -       typedef _Sp_ebo_helper<1, _Alloc>       _Alloc_base;\n> >> +       [[__no_unique_address__]] _Sp_ebo_helper<_Deleter> _M_d;\n> >> +       [[__no_unique_address__]] _Sp_ebo_helper<_Alloc>   _M_a;\n> >>\n> >>        public:\n> >>         _Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept\n> >> -       : _Del_base(std::move(__d)), _Alloc_base(__a), _M_ptr(__p)\n> >> +       : _M_d{std::move(__d)}, _M_a{__a}, _M_ptr(__p)\n> >>         { }\n> >>\n> >> -       _Deleter& _M_del() noexcept { return _Del_base::_S_get(*this); }\n> >> -       _Alloc& _M_alloc() noexcept { return\n> _Alloc_base::_S_get(*this); }\n> >> +       _Deleter& _M_del() noexcept { return _M_d._M_obj; }\n> >> +       _Alloc& _M_alloc() noexcept { return _M_a._M_obj; }\n> >>\n> >>         _Ptr _M_ptr;\n> >>        };\n> >> @@ -645,14 +640,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> >>    template<typename _Tp, typename _Alloc, _Lock_policy _Lp>\n> >>      class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>\n> >>      {\n> >> -      class _Impl : _Sp_ebo_helper<0, _Alloc>\n> >> +      class _Impl\n> >>        {\n> >> -       typedef _Sp_ebo_helper<0, _Alloc>       _A_base;\n> >> +       [[__no_unique_address__]] _Sp_ebo_helper<_Alloc> _M_a;\n> >>\n> >>        public:\n> >> -       explicit _Impl(_Alloc __a) noexcept : _A_base(__a) { }\n> >> +       explicit _Impl(_Alloc __a) noexcept : _M_a{std::move(__a)} { }\n> >>\n> >> -       _Alloc& _M_alloc() noexcept { return _A_base::_S_get(*this); }\n> >> +       _Alloc& _M_alloc() noexcept { return _M_a._M_obj; }\n> >>\n> >>         __gnu_cxx::__aligned_buffer<__remove_cv_t<_Tp>> _M_storage;\n> >>        };\n> >> diff --git a/libstdc++-v3/include/std/tuple\n> b/libstdc++-v3/include/std/tuple\n> >> index f7caa79cda04..32800d8d7752 100644\n> >> --- a/libstdc++-v3/include/std/tuple\n> >> +++ b/libstdc++-v3/include/std/tuple\n> >> @@ -68,7 +68,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> >>    template<typename... _Elements>\n> >>      class tuple;\n> >>\n> >> +#if ! __has_cpp_attribute(__no_unique_address__)\n> >> +#error \"support for [[__no_unique_address__]] attribute is required\"\n> >> +#endif\n> >> +\n> >>    /// @cond undocumented\n> >> +#if ! _GLIBCXX_INLINE_VERSION\n> >>    template<typename _Tp>\n> >>      struct __is_empty_non_tuple : is_empty<_Tp> { };\n> >>\n> >> @@ -76,17 +81,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> >>    template<typename _El0, typename... _El>\n> >>      struct __is_empty_non_tuple<tuple<_El0, _El...>> : false_type { };\n> >>\n> >> -  // Use the Empty Base-class Optimization for empty, non-final types.\n> >> +  // Use [[no_unique_address]] for empty, non-final types.\n> >>    template<typename _Tp>\n> >>      using __empty_not_final\n> >>      = __conditional_t<__is_final(_Tp), false_type,\n> >>                       __is_empty_non_tuple<_Tp>>;\n> >> +#else\n> >> +  // For the unstable ABI we always use [[no_unique_address]].\n> >> +  template<typename>\n> >> +    using __empty_not_final = true_type;\n> >> +#endif\n> >>\n> >>    template<size_t _Idx, typename _Head,\n> >>            bool = __empty_not_final<_Head>::value>\n> >>      struct _Head_base;\n> >\n> > We forward declare  _Head_base anyway, so maybe instead of\n> __empty_not_final\n> > we should have two declarations: one that defaults to __conditional_t\n> and another.\n> > that uses = true, as for _Sp_ebo_base. There seem to be non need for\n> additional\n> > class template.\n>\n> So something like this:\n>\n> #if ! _GLIBCXX_INLINE_VERSION\n>   template<typename _Tp>\n>     struct __is_empty_non_tuple : is_empty<_Tp> { };\n>\n>   // Using EBO for elements that are tuples causes ambiguous base errors.\n>   template<typename _El0, typename... _El>\n>     struct __is_empty_non_tuple<tuple<_El0, _El...>> : false_type { };\n>\n>   // Use [[no_unique_address]] for empty, non-final types.\n>   template<typename _Tp>\n>     using __empty_not_final\n>     = __conditional_t<__is_final(_Tp), false_type,\n>               __is_empty_non_tuple<_Tp>>;\n>\n>   template<size_t _Idx, typename _Head,\n>        bool = __empty_not_final<_Head>::value>\n>\n    struct _Head_base;\n> #else\n>   // For the unstable ABI we always use [[no_unique_address]].\n>   template<size_t _Idx, typename _Head, bool = true>\n>     struct _Head_base;\n> #endif\n>\n>   template<size_t _Idx, typename _Head, bool>\n>     struct _Head_base\n>     {\n>\n> So instead of two partial specializations (for true/false) we would\n> have the primary template and the partial specialization for false.\n> For the unstable ABI, we would have only the primary template, so no\n> partial specialization to match.\n\nYes, even better.\nI would add bool /* true */> in the template head for primary\nspecialization,\nSo, it indicates when it is used.\n\n>\n\n\n> We could even go one step further and remove the bool parameter for\n> the unstable ABI, to reduce the length of the symbol names:\n>\nThe bool parameter is mangled as \"b1\", so I do not think there is so much\ngain.\n\n>\n> #if ! _GLIBCXX_INLINE_VERSION\n>   ...\n>\n>   template<size_t _Idx, typename _Head,\n>        bool = __empty_not_final<_Head>::value>\n>     struct _Head_base\n> #else\n>   // For the unstable ABI we always use [[no_unique_address]].\n>   template<size_t _Idx, typename _Head>\n>     struct _Head_base\n> #endif\n>     {\n>       constexpr _Head_base()\n>       : _M_head_impl() { }\n>\n>","headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=AAQVWNGL;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=AAQVWNGL","sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com","sourceware.org; spf=pass smtp.mailfrom=redhat.com","sourceware.org; arc=none smtp.remote-ip=170.10.133.124"],"Received":["from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g9Zg61HHNz1yJq\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 06 May 2026 22:38:24 +1000 (AEST)","from vm01.sourceware.org (localhost [IPv6:::1])\n\tby sourceware.org (Postfix) with ESMTP id DB1B74BA23CC\n\tfor <incoming@patchwork.ozlabs.org>; Wed,  6 May 2026 12:38:22 +0000 (GMT)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by sourceware.org (Postfix) with ESMTP id 445564BA23C7\n for <gcc-patches@gcc.gnu.org>; Wed,  6 May 2026 12:37:14 +0000 (GMT)","from mail-yw1-f200.google.com (mail-yw1-f200.google.com\n [209.85.128.200]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-194-i3trmBpRPBqlq-_AdF1vng-1; Wed, 06 May 2026 08:37:12 -0400","by mail-yw1-f200.google.com with SMTP id\n 00721157ae682-7bd5af04312so125113467b3.1\n for <gcc-patches@gcc.gnu.org>; Wed, 06 May 2026 05:37:12 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org DB1B74BA23CC","OpenDKIM Filter v2.11.0 sourceware.org 445564BA23C7"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org 445564BA23C7","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org 445564BA23C7","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778071034; cv=none;\n b=bELOXopoIIlNcG0d5KFG+WSGoZy607FV6clA21OBmdBNBqKciWhHG1Y0HU3klRhgcmkBJ4c7NjXmXrhJNYyO3+C0adKkNOospP5fFoaskZOfuBlT9WVf/3o9PNCPgJWofHZr8MzxJpx8uTkbhtPiMRipXtgKfn/p0iJFpXUdsnE=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1778071034; c=relaxed/simple;\n bh=PiuP0LYYRj5vp7Zqigy0yRgLQ8pnt1cHmn6ZTR7QkBc=;\n h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To;\n b=ugv+ob0exNiVayFDH4IEeoQ+eKGowCAZ9bwuEBuoeIUC64XGwwl3wJajLB8q6VXmUw+dNnMzbYpMIN96j2yepEs7mUmsJFUlf/2O6AmjRWD4oF8saHhz21xEbAl/RlqOKlb43jgYY0rZVugIIhV8yDwLl584ldUvVzUhzNb/jiE=","ARC-Authentication-Results":"i=1; sourceware.org;\n dkim=pass (1024-bit key, unprotected)\n header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=AAQVWNGL","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1778071033;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n in-reply-to:in-reply-to:references:references;\n bh=xN+T51L6bQ8ccBD4j5IZjfkJUgqCNmr8p46UuLJrogs=;\n b=AAQVWNGLZ5eHT3ZKeKN2l+o//HcHZ66lob2f+qlm/q3Wzvux21yVMIdWz6xpFGzXcZXJvH\n E8G/X81ONlYmCP9LitK44z/g6lKxouwTGmmAE/7PUOcyOG6NhWaO3EeXMijfF/OisQ+AKI\n BNQp2mGhyIYeN4faY2C7HWz370Xi6W4=","X-MC-Unique":"i3trmBpRPBqlq-_AdF1vng-1","X-Mimecast-MFC-AGG-ID":"i3trmBpRPBqlq-_AdF1vng_1778071032","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1778071032; x=1778675832;\n h=cc:to:subject:message-id:date:from:in-reply-to:references\n :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=xN+T51L6bQ8ccBD4j5IZjfkJUgqCNmr8p46UuLJrogs=;\n b=ctcKxdCUhYjbqHBrRN1fl/3dmOhgWzWcrYWvmTSZ937tFbtug8MdQeIqTovuVqFO1t\n 1uIEu/bPQEiF5+r24nAywzo37Pb5Z3fXPxxPNhpvjkfD9sBdkdtX794jc8P2zujFAERD\n C8FW9rfKZodQEIV+HtsAYsWybiKLLuV8+3akMzyzD6pzCsq+rSZzkMGda/1lBNEldh6z\n /Bilm2KR3299EyVuPQOsooZ2zFJR3Ne53k3GGJUhfDItWiD8bQmzp9dDrMZe9NaOFwHP\n 6wgT7iQLVrGWpKqLq0RYFTYTcIt9iNPxKn+M5A/YvdO700yK7jnevTBEX/4KzsmfRRxt\n OPJg==","X-Gm-Message-State":"AOJu0YzUxqGJVXYn4nR1CEsqvDdhJuzEuYPwnn3yTd3zc+MH/e7+f6Ql\n 26M/C9xbqcPCIY32/GXP5uEjNKIuhVnhOi+FBBrcRm2tslX9rktHVdRhlXsC9XMevsA2yb29CLR\n 0s2wZ2Ipn4ROQdEL+tJ6oYjjdAqDuI6F3jt+EfNSWThhz1wOaeWkuVpnIWRPYldVr33OF9lsfgp\n t9leiFB3dqNdFKVvii/lvNEqMgvXtSdSEqGQ==","X-Gm-Gg":"AeBDieuW1VjRJzrqFGRhOi9GZnS2uVBSYX/as6iHxLgFpBEHVB19Ti2mCnn8MNNMdG1\n kH2ektfBKTjcFwons/h0H9AAZz4mn4aDO2zyGrjX/ADgNszFYJwxpnpMgMMGCovYqQPvorIl7Iu\n UtOkgWVv67wgXrZkcCeQ1WvTuKifIR8B5KdDwWeefRylVwd+bahgph+d50/TWXFjcc8J7ZDzlV8\n Ea3EnKSBKN1e7NdZlGTWPuyeFS5nQDEaHjjUiccW1jXbmy3p9J+Ast21aPWsV8gasF/0E06Avik\n zyY=","X-Received":["by 2002:a05:690c:dd4:b0:7bd:a4dc:c23b with SMTP id\n 00721157ae682-7bdf5efad66mr36640817b3.49.1778071031858;\n Wed, 06 May 2026 05:37:11 -0700 (PDT)","by 2002:a05:690c:dd4:b0:7bd:a4dc:c23b with SMTP id\n 00721157ae682-7bdf5efad66mr36640567b3.49.1778071031340; Wed, 06 May 2026\n 05:37:11 -0700 (PDT)"],"MIME-Version":"1.0","References":"<20260506085339.325517-1-jwakely@redhat.com>\n <CAKvuMXD1yPCW0jLSLc0ymq3wWgeS_fZcLbuSSzpL8mHG+TjGSg@mail.gmail.com>\n <CACb0b4mMNJMZQCgGu_cJB_2Cgssafuw+w0iApbFpKTCfFeSdEQ@mail.gmail.com>","In-Reply-To":"\n <CACb0b4mMNJMZQCgGu_cJB_2Cgssafuw+w0iApbFpKTCfFeSdEQ@mail.gmail.com>","From":"Tomasz Kaminski <tkaminsk@redhat.com>","Date":"Wed, 6 May 2026 14:36:59 +0200","X-Gm-Features":"AVHnY4Ii5nqLpfZxli_RUyNyzWlUSR5wGPDOauk6GUlnqet_MWA2goEM3zsXnVA","Message-ID":"\n <CAKvuMXDt7sNg9ZK0Rnpu0+-oLpOTuYVM0Wmh5eP0aUHDBmVJtw@mail.gmail.com>","Subject":"Re: [PATCH v2 1/3] libstdc++: Replace uses of EBO with\n [[no_unique_address]]","To":"Jonathan Wakely <jwakely@redhat.com>","Cc":"gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"mRJOnbbhhhhRjMZBoHaaCXpyCvT5kmjOa6u_Vr4GTqo_1778071032","X-Mimecast-Originator":"redhat.com","Content-Type":"multipart/alternative; boundary=\"000000000000357c7c0651256ce4\"","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"}},{"id":3687047,"web_url":"http://patchwork.ozlabs.org/comment/3687047/","msgid":"<CACb0b4=LHHrh-xpetPDcCgg=R5tZrBjRbUaaUdYmRnr+qSSUZw@mail.gmail.com>","list_archive_url":null,"date":"2026-05-06T12:45:25","subject":"Re: [PATCH v2 1/3] libstdc++: Replace uses of EBO with\n [[no_unique_address]]","submitter":{"id":48004,"url":"http://patchwork.ozlabs.org/api/people/48004/","name":"Jonathan Wakely","email":"jwakely@redhat.com"},"content":"On Wed, 6 May 2026 at 13:37, Tomasz Kaminski <tkaminsk@redhat.com> wrote:\n>\n>\n>\n> On Wed, May 6, 2026 at 2:13 PM Jonathan Wakely <jwakely@redhat.com> wrote:\n>>\n>> On Wed, 6 May 2026 at 12:52, Tomasz Kaminski <tkaminsk@redhat.com> wrote:\n>> >\n>> >\n>> >\n>> > On Wed, May 6, 2026 at 12:13 PM Jonathan Wakely <jwakely@redhat.com> wrote:\n>> >>\n>> >> Clang 9 added support for [[__no_unique_address__]] and we don't support\n>> >> Intel icc any longer, so we can remove the code in <tuple> that works\n>> >> around the absence of that attribute. We can also address a FIXME in\n>> >> <bits/shared_ptr_base.h> and replace uses of EBO with the attribute.\n>> >>\n>> >> libstdc++-v3/ChangeLog:\n>> >>\n>> >>         * include/bits/shared_ptr_base.h (_Sp_ebo_helper): Simplify by\n>> >>         using [[__no_unique_address__]] instead of EBO. Use the\n>> >>         attribute unconditionally for the unstable ABI.\n>> >>         (_Sp_counted_deleter::_Impl): Adjust uses of _Sp_ebo_helper.\n>> >>         (_Sp_counted_ptr_inplace::_Impl): Likewise.\n>> >>         * include/std/tuple (_Head_base): Remove implementation for\n>> >>         compilers that don't support [[__no_unique_address__]]. Use the\n>> >>         attribute unconditionally for the unstable ABI.\n>> >> ---\n>> >>\n>> >> v2: Add the attribute to the data members of _Impl as well as to the\n>> >> _M_obj data member of _Sp_ebo_helper. Otherwise the _M_obj subobject is\n>> >> potentially overlapping, but the _M_ and _M_d ones are not. We need both\n>> >> to be marked with the attribute.\n>> >>\n>> >> What we *really* want is [[no_unique_address(expr)]] so that we can get\n>> >> rid of _Sp_ebo_helper entirely, and just do:\n>> >>\n>> >>   #if ! _GLIBCXX_INLINE_VERSION // Stable ABI\n>> >>   template<typename T> __can_overlap = !__is_final(T) && __is_empty(T);\n>> >>   #else // Unstable ABI\n>> >>   template<typename T> __can_overlap = true;\n>> >>   #endif\n>> >>   [[no_unique_address(__can_overlap<_Del>)]] _M_del;\n>> >>\n>> >> I should propose that to WG21, and if rejected just get it added to GCC\n>> >> and Clang.\n>> >\n>> >\n>> >>\n>> >>\n>> >> Tested x86_64-linux.\n>> >\n>> > LGTM with one suggestion.\n>> >>\n>> >>\n>> >>  libstdc++-v3/include/bits/shared_ptr_base.h | 65 +++++++++----------\n>> >>  libstdc++-v3/include/std/tuple              | 69 ++++-----------------\n>> >>  2 files changed, 43 insertions(+), 91 deletions(-)\n>> >>\n>> >> diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h\n>> >> index b92e3a4c90e4..3ab73f6e4a0d 100644\n>> >> --- a/libstdc++-v3/include/bits/shared_ptr_base.h\n>> >> +++ b/libstdc++-v3/include/bits/shared_ptr_base.h\n>> >> @@ -513,57 +513,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>> >>      inline void\n>> >>      _Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept { }\n>> >>\n>> >> -  // FIXME: once __has_cpp_attribute(__no_unique_address__)) is true for\n>> >> -  // all supported compilers we can greatly simplify _Sp_ebo_helper.\n>> >> +#if ! __has_cpp_attribute(__no_unique_address__)\n>> >> +#error \"support for [[__no_unique_address__]] attribute is required\"\n>> >> +#endif\n>> >> +\n>> >> +#if ! _GLIBCXX_INLINE_VERSION\n>> >>    // N.B. unconditionally applying the attribute could change layout for\n>> >>    // final types, which currently cannot use EBO so have a unique address.\n>> >> -\n>> >> -  template<int _Nm, typename _Tp,\n>> >> -          bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>\n>> >> +  template<typename _Tp, bool = !__is_final(_Tp) && __is_empty(_Tp)>\n>> >>      struct _Sp_ebo_helper;\n>> >> +#else\n>> >> +  template<typename _Tp, bool = true>\n>> >> +    struct _Sp_ebo_helper;\n>> >\n>> > The name \"EBO helper\" no longer seems accurate, but\n>> > I have no better suggestion.\n>>\n>> Yes, I had the same thought. Something like \"_Alloc_overlapping\" could\n>> work, but is longer and unless you already understand what that means,\n>> it isn't any more understandable than \"EBO helper\".\n>>\n>> >>\n>> >> +#endif\n>> >>\n>> >> -  /// Specialization using EBO.\n>> >> -  template<int _Nm, typename _Tp>\n>> >> -    struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp\n>> >> +  /// Specialization using [[no_unique_address]].\n>> >> +  template<typename _Tp>\n>> >> +    struct _Sp_ebo_helper<_Tp, true>\n>> >>      {\n>> >> -      explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) { }\n>> >> -      explicit _Sp_ebo_helper(_Tp&& __tp) : _Tp(std::move(__tp)) { }\n>> >> -\n>> >> -      static _Tp&\n>> >> -      _S_get(_Sp_ebo_helper& __eboh) { return static_cast<_Tp&>(__eboh); }\n>> >> +      [[__no_unique_address__]] _Tp _M_obj;\n>> >>      };\n>> >>\n>> >> -  /// Specialization not using EBO.\n>> >> -  template<int _Nm, typename _Tp>\n>> >> -    struct _Sp_ebo_helper<_Nm, _Tp, false>\n>> >> +#if ! _GLIBCXX_INLINE_VERSION\n>> >> +  /// Specialization not using [[no_unique_address]].\n>> >> +  template<typename _Tp>\n>> >> +    struct _Sp_ebo_helper<_Tp, false>\n>> >>      {\n>> >> -      explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) { }\n>> >> -      explicit _Sp_ebo_helper(_Tp&& __tp) : _M_tp(std::move(__tp)) { }\n>> >> -\n>> >> -      static _Tp&\n>> >> -      _S_get(_Sp_ebo_helper& __eboh)\n>> >> -      { return __eboh._M_tp; }\n>> >> -\n>> >> -    private:\n>> >> -      _Tp _M_tp;\n>> >> +      _Tp _M_obj;\n>> >>      };\n>> >> +#endif\n>> >>\n>> >>    // Support for custom deleter and/or allocator\n>> >>    template<typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp>\n>> >>      class _Sp_counted_deleter final : public _Sp_counted_base<_Lp>\n>> >>      {\n>> >> -      class _Impl : _Sp_ebo_helper<0, _Deleter>, _Sp_ebo_helper<1, _Alloc>\n>> >> +      class _Impl\n>> >>        {\n>> >> -       typedef _Sp_ebo_helper<0, _Deleter>     _Del_base;\n>> >> -       typedef _Sp_ebo_helper<1, _Alloc>       _Alloc_base;\n>> >> +       [[__no_unique_address__]] _Sp_ebo_helper<_Deleter> _M_d;\n>> >> +       [[__no_unique_address__]] _Sp_ebo_helper<_Alloc>   _M_a;\n>> >>\n>> >>        public:\n>> >>         _Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept\n>> >> -       : _Del_base(std::move(__d)), _Alloc_base(__a), _M_ptr(__p)\n>> >> +       : _M_d{std::move(__d)}, _M_a{__a}, _M_ptr(__p)\n>> >>         { }\n>> >>\n>> >> -       _Deleter& _M_del() noexcept { return _Del_base::_S_get(*this); }\n>> >> -       _Alloc& _M_alloc() noexcept { return _Alloc_base::_S_get(*this); }\n>> >> +       _Deleter& _M_del() noexcept { return _M_d._M_obj; }\n>> >> +       _Alloc& _M_alloc() noexcept { return _M_a._M_obj; }\n>> >>\n>> >>         _Ptr _M_ptr;\n>> >>        };\n>> >> @@ -645,14 +640,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>> >>    template<typename _Tp, typename _Alloc, _Lock_policy _Lp>\n>> >>      class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>\n>> >>      {\n>> >> -      class _Impl : _Sp_ebo_helper<0, _Alloc>\n>> >> +      class _Impl\n>> >>        {\n>> >> -       typedef _Sp_ebo_helper<0, _Alloc>       _A_base;\n>> >> +       [[__no_unique_address__]] _Sp_ebo_helper<_Alloc> _M_a;\n>> >>\n>> >>        public:\n>> >> -       explicit _Impl(_Alloc __a) noexcept : _A_base(__a) { }\n>> >> +       explicit _Impl(_Alloc __a) noexcept : _M_a{std::move(__a)} { }\n>> >>\n>> >> -       _Alloc& _M_alloc() noexcept { return _A_base::_S_get(*this); }\n>> >> +       _Alloc& _M_alloc() noexcept { return _M_a._M_obj; }\n>> >>\n>> >>         __gnu_cxx::__aligned_buffer<__remove_cv_t<_Tp>> _M_storage;\n>> >>        };\n>> >> diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple\n>> >> index f7caa79cda04..32800d8d7752 100644\n>> >> --- a/libstdc++-v3/include/std/tuple\n>> >> +++ b/libstdc++-v3/include/std/tuple\n>> >> @@ -68,7 +68,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>> >>    template<typename... _Elements>\n>> >>      class tuple;\n>> >>\n>> >> +#if ! __has_cpp_attribute(__no_unique_address__)\n>> >> +#error \"support for [[__no_unique_address__]] attribute is required\"\n>> >> +#endif\n>> >> +\n>> >>    /// @cond undocumented\n>> >> +#if ! _GLIBCXX_INLINE_VERSION\n>> >>    template<typename _Tp>\n>> >>      struct __is_empty_non_tuple : is_empty<_Tp> { };\n>> >>\n>> >> @@ -76,17 +81,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>> >>    template<typename _El0, typename... _El>\n>> >>      struct __is_empty_non_tuple<tuple<_El0, _El...>> : false_type { };\n>> >>\n>> >> -  // Use the Empty Base-class Optimization for empty, non-final types.\n>> >> +  // Use [[no_unique_address]] for empty, non-final types.\n>> >>    template<typename _Tp>\n>> >>      using __empty_not_final\n>> >>      = __conditional_t<__is_final(_Tp), false_type,\n>> >>                       __is_empty_non_tuple<_Tp>>;\n>> >> +#else\n>> >> +  // For the unstable ABI we always use [[no_unique_address]].\n>> >> +  template<typename>\n>> >> +    using __empty_not_final = true_type;\n>> >> +#endif\n>> >>\n>> >>    template<size_t _Idx, typename _Head,\n>> >>            bool = __empty_not_final<_Head>::value>\n>> >>      struct _Head_base;\n>> >\n>> > We forward declare  _Head_base anyway, so maybe instead of __empty_not_final\n>> > we should have two declarations: one that defaults to __conditional_t and another.\n>> > that uses = true, as for _Sp_ebo_base. There seem to be non need for additional\n>> > class template.\n>>\n>> So something like this:\n>>\n>> #if ! _GLIBCXX_INLINE_VERSION\n>>   template<typename _Tp>\n>>     struct __is_empty_non_tuple : is_empty<_Tp> { };\n>>\n>>   // Using EBO for elements that are tuples causes ambiguous base errors.\n>>   template<typename _El0, typename... _El>\n>>     struct __is_empty_non_tuple<tuple<_El0, _El...>> : false_type { };\n>>\n>>   // Use [[no_unique_address]] for empty, non-final types.\n>>   template<typename _Tp>\n>>     using __empty_not_final\n>>     = __conditional_t<__is_final(_Tp), false_type,\n>>               __is_empty_non_tuple<_Tp>>;\n>>\n>>   template<size_t _Idx, typename _Head,\n>>        bool = __empty_not_final<_Head>::value>\n>>\n>>     struct _Head_base;\n>> #else\n>>   // For the unstable ABI we always use [[no_unique_address]].\n>>   template<size_t _Idx, typename _Head, bool = true>\n>>     struct _Head_base;\n>> #endif\n>>\n>>   template<size_t _Idx, typename _Head, bool>\n>>     struct _Head_base\n>>     {\n>>\n>> So instead of two partial specializations (for true/false) we would\n>> have the primary template and the partial specialization for false.\n>> For the unstable ABI, we would have only the primary template, so no\n>> partial specialization to match.\n>\n> Yes, even better.\n> I would add bool /* true */> in the template head for primary specialization,\n> So, it indicates when it is used.\n>>\n>>\n>>\n>>\n>> We could even go one step further and remove the bool parameter for\n>> the unstable ABI, to reduce the length of the symbol names:\n>\n> The bool parameter is mangled as \"b1\", so I do not think there is so much\n> gain.\n\nYeah, it's only two bytes, although it's two bytes for each tuple\nelement, so it adds up across different specializations of std::tuple.\n\nBut we can make that change later if we want to, the unstable ABI is unstable.\n\n\n>>\n>>\n>> #if ! _GLIBCXX_INLINE_VERSION\n>>   ...\n>>\n>>   template<size_t _Idx, typename _Head,\n>>        bool = __empty_not_final<_Head>::value>\n>>     struct _Head_base\n>> #else\n>>   // For the unstable ABI we always use [[no_unique_address]].\n>>   template<size_t _Idx, typename _Head>\n>>     struct _Head_base\n>> #endif\n>>     {\n>>       constexpr _Head_base()\n>>       : _M_head_impl() { }\n>>","headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=P9IhVUPc;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=P9IhVUPc","sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com","sourceware.org; spf=pass smtp.mailfrom=redhat.com","sourceware.org; arc=none smtp.remote-ip=170.10.129.124"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g9ZsR4FZnz1y04\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 06 May 2026 22:47:23 +1000 (AEST)","from vm01.sourceware.org (localhost [IPv6:::1])\n\tby sourceware.org (Postfix) with ESMTP id B60BB4BA799B\n\tfor <incoming@patchwork.ozlabs.org>; Wed,  6 May 2026 12:47:21 +0000 (GMT)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by sourceware.org (Postfix) with ESMTP id CA27F4BA23E8\n for <gcc-patches@gcc.gnu.org>; Wed,  6 May 2026 12:45:44 +0000 (GMT)","from mail-yx1-f69.google.com (mail-yx1-f69.google.com\n [74.125.224.69]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-675-ErnfDNpnN0SthDVA1MZM5Q-1; Wed, 06 May 2026 08:45:43 -0400","by mail-yx1-f69.google.com with SMTP id\n 956f58d0204a3-65c37eafd67so9287940d50.2\n for <gcc-patches@gcc.gnu.org>; Wed, 06 May 2026 05:45:43 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org B60BB4BA799B","OpenDKIM Filter v2.11.0 sourceware.org CA27F4BA23E8"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org CA27F4BA23E8","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org CA27F4BA23E8","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778071544; cv=none;\n b=apdvIFA3b7ujGB5RR5vHrzC0LTFGugmn+KRzH/yWGRxCTggpLnw55zDaY4ecFUA3DE6jC3RIYTYpf8/08ZVXCe0WO7iDzs6BIjWYZ2xPSr1AxbA/MrvkojXRXqzPwLvPsMJZvpLgn9j7f6ElTET4NJn3ZkeWxLySo+VS/gFMUUc=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1778071544; c=relaxed/simple;\n bh=TiwKtEMKDGcw+ntjw/BqUWq0yLCWVEWnF3oLeHMyhyo=;\n h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To;\n b=PDPft0UItOlBYdIdIyUV1++EjQn94AY5J1+XoGvDXDe9UlQuIwDAyeYNAz2icyHqo6gkryvc56fUyh4RF7fkFsTMtFOCzBUe5fQ8ydQTSsR9BgpaBzBkXD86+fKLURRSGKqUIEWluMVMXNqu9XQr2OoxFH+w9me/AqgcOAjNpZw=","ARC-Authentication-Results":"i=1; sourceware.org;\n dkim=pass (1024-bit key, unprotected)\n header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=P9IhVUPc","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1778071544;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=e+ZUsCNgvzRFu5zfiAVWjzuVkuK2JgZK4RJ3RIHfmak=;\n b=P9IhVUPcL+H13XVzjwEtkeNJdpnJfMdACOwkWJvBUFVKuyu24/09e6OF2zY4s/lvXr6XxO\n uc+AA3VZHUQtDWQCANE4iCDfKENOIpkOxJrH2ONueVKzzADNirlPtcd2PaXDGLaJF9Rlqs\n qI4VeQ2YZ9a54XPcgSGU3Olr/yiy6yM=","X-MC-Unique":"ErnfDNpnN0SthDVA1MZM5Q-1","X-Mimecast-MFC-AGG-ID":"ErnfDNpnN0SthDVA1MZM5Q_1778071542","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1778071542; x=1778676342;\n h=content-transfer-encoding:cc:to:subject:message-id:date:from\n :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=e+ZUsCNgvzRFu5zfiAVWjzuVkuK2JgZK4RJ3RIHfmak=;\n b=r4wV0SF/33hrBOaUukZ9ku4SeMijYFBotQ3maBzK34WwZ15Vz4i8Bb22IVYtsMzmSM\n Jopxi2llsnYjYI9LSpFdb/EyT03CIh3E/gwb0FCoDx5ppsUrVh0btN/t/IEBjt0thcp8\n Nkxzbciq2jVoa8To6DThIeoGFBA3F7mDPVIOhh0oHMgXWKMzmqmT+WQTiMJkNdcQITgx\n RsNr+jd2q/22/bGXbPyb34Ys5ZvsEWprRC3UfjBgc+pDDTl8q7VccJfcOsQRhStd7JiO\n bg8OM6kWJNpCzgpXSNgWcrQt0dEZv1iRGDzTfI1xtsmArWHkmpZhnjpWn77P6uxN4Q3K\n w9Ig==","X-Gm-Message-State":"AOJu0Yy4bODL/rVzo5Xt4+41O1FcYetQddw7vO03MLWSyRIQg/JO/DKG\n eMin8s/eNFlCXdSFw7YFui1ooH7pTAbkZHXvbw7YFl+vly4UI/4eULnC5wXExJ5cz3xPLHUHA22\n sZBfWP5VaIsj4DtorX1Rp0KsQf/VI1nhqWqcgo0A3rK27gp/0zwwNcpfH7t92hH1PRev9ZsxqFF\n U06hFjeiqd90op2lIuIW5657n0GHMs6Mha9w==","X-Gm-Gg":"AeBDievYTHvdUWMUyl42NWOMHUidtacl5/5lC+g7J4Kz0+NutUnWuWD0mDjfmmm5Soz\n oyIUGQBXFcf4fKqWEi50cejNQ2uw5mGOrDqvVN/dkmzXpS16IZfTFEYIGS0VW5AVgDIIPBCpvKI\n J8dsxE6TB0yN5MGv+n0NCWSiLSkaCqZp6tsI7vS5etf+358KkY9lgMWLM6wHdAFhWpUC9L1acpY\n LmAwzIgGqizxCclcFCGJvUePSuq4hRuo8r08MJOYgd6JA8Gcssk7C8Ht/ZHJxzQICOhzBPzSzMJ\n ig==","X-Received":["by 2002:a05:690e:1619:b0:65c:7129:5c66 with SMTP id\n 956f58d0204a3-65c7999cb5dmr2712045d50.41.1778071542386;\n Wed, 06 May 2026 05:45:42 -0700 (PDT)","by 2002:a05:690e:1619:b0:65c:7129:5c66 with SMTP id\n 956f58d0204a3-65c7999cb5dmr2712033d50.41.1778071541881; Wed, 06 May 2026\n 05:45:41 -0700 (PDT)"],"MIME-Version":"1.0","References":"<20260506085339.325517-1-jwakely@redhat.com>\n <CAKvuMXD1yPCW0jLSLc0ymq3wWgeS_fZcLbuSSzpL8mHG+TjGSg@mail.gmail.com>\n <CACb0b4mMNJMZQCgGu_cJB_2Cgssafuw+w0iApbFpKTCfFeSdEQ@mail.gmail.com>\n <CAKvuMXDt7sNg9ZK0Rnpu0+-oLpOTuYVM0Wmh5eP0aUHDBmVJtw@mail.gmail.com>","In-Reply-To":"\n <CAKvuMXDt7sNg9ZK0Rnpu0+-oLpOTuYVM0Wmh5eP0aUHDBmVJtw@mail.gmail.com>","From":"Jonathan Wakely <jwakely@redhat.com>","Date":"Wed, 6 May 2026 13:45:25 +0100","X-Gm-Features":"AVHnY4K4Aql-Hu7i4Q0I83Eh_WQT5YvIbSN53-Twd-SCmfBkGpi5fE0a7N6OO6A","Message-ID":"\n <CACb0b4=LHHrh-xpetPDcCgg=R5tZrBjRbUaaUdYmRnr+qSSUZw@mail.gmail.com>","Subject":"Re: [PATCH v2 1/3] libstdc++: Replace uses of EBO with\n [[no_unique_address]]","To":"Tomasz Kaminski <tkaminsk@redhat.com>","Cc":"gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"z1U1RZ_yAEpAh5KihkdWzmoLszzySPVzTdVj-_WGi8c_1778071542","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"}}]