[libcxx-commits] [libcxx] [libc++] Annotate the data member of variant with no_unique_address (PR #137783)

Alex Aktsipetrov via libcxx-commits libcxx-commits at lists.llvm.org
Tue Apr 29 07:36:16 PDT 2025


https://github.com/gizmondo updated https://github.com/llvm/llvm-project/pull/137783

>From a8a7a2a107c502673dd3f6613893195ce825ae48 Mon Sep 17 00:00:00 2001
From: Alex Aktsipetrov <akts at google.com>
Date: Tue, 29 Apr 2025 12:20:15 +0200
Subject: [PATCH] [libc++] Annotate the data member of variant with
 no_unique_address attribute.

This allows clients to reuse tail padding after the index (if any), by applying
[[no_unique_address]] to variant fields.
---
 libcxx/include/__configuration/abi.h          |  2 ++
 libcxx/include/variant                        |  7 +++-
 .../variant.variant/variant_size.pass.cpp     | 19 ++++++++++
 ..._robust_against_no_unique_address.pass.cpp | 35 +++++++++++++++++++
 4 files changed, 62 insertions(+), 1 deletion(-)
 create mode 100644 libcxx/test/std/utilities/variant/variant.variant/variant_robust_against_no_unique_address.pass.cpp

diff --git a/libcxx/include/__configuration/abi.h b/libcxx/include/__configuration/abi.h
index 01a4a4c023983..f867fb12206a7 100644
--- a/libcxx/include/__configuration/abi.h
+++ b/libcxx/include/__configuration/abi.h
@@ -57,6 +57,8 @@
 // Use the smallest possible integer type to represent the index of the variant.
 // Previously libc++ used "unsigned int" exclusively.
 #  define _LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION
+// Allow to reuse tail padding after the index of the variant with [[no_unique_address]] attribute.
+#  define _LIBCPP_ABI_VARIANT_NO_UNIQUE_ADDRESS_OPTIMIZATION
 // Unstable attempt to provide a more optimized std::function
 #  define _LIBCPP_ABI_OPTIMIZED_FUNCTION
 // All the regex constants must be distinct and nonzero.
diff --git a/libcxx/include/variant b/libcxx/include/variant
index 74a464d27ead4..63f4a09a76025 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1319,7 +1319,12 @@ public:
 #    endif
 
 private:
-  __variant_detail::__impl<_Types...> __impl_;
+#define _LIBCPP_ABI_VARIANT_NO_UNIQUE_ADDRESS_OPTIMIZATION
+#    ifdef _LIBCPP_ABI_VARIANT_NO_UNIQUE_ADDRESS_OPTIMIZATION
+  _LIBCPP_NO_UNIQUE_ADDRESS
+#    endif // _LIBCPP_ABI_VARIANT_NO_UNIQUE_ADDRESS_OPTIMIZATION
+  __variant_detail::__impl<_Types...>
+      __impl_;
 
   friend struct __variant_detail::__access::__variant;
   friend struct __variant_detail::__visitation::__variant;
diff --git a/libcxx/test/libcxx/utilities/variant/variant.variant/variant_size.pass.cpp b/libcxx/test/libcxx/utilities/variant/variant.variant/variant_size.pass.cpp
index 2f1ea8bffb479..62abcd364c7ac 100644
--- a/libcxx/test/libcxx/utilities/variant/variant.variant/variant_size.pass.cpp
+++ b/libcxx/test/libcxx/utilities/variant/variant.variant/variant_size.pass.cpp
@@ -70,6 +70,22 @@ struct type_with_index {
 #endif
 };
 
+struct alignas(16) A16 {};
+struct VariantWithNoUniqueAddress {
+  TEST_NO_UNIQUE_ADDRESS std::variant<A16> a;
+  bool b;
+};
+struct VariantWithoutNoUniqueAddress {
+  std::variant<A16> a;
+  bool b;
+};
+constexpr bool ExpectSmallerSizeWithNoUniqueAddress =
+#ifdef _LIBCPP_ABI_VARIANT_NO_UNIQUE_ADDRESS_OPTIMIZATION
+    true;
+#else
+    false;
+#endif
+
 int main(int, char**) {
   test_index_type<unsigned char>();
   // This won't compile due to template depth issues.
@@ -84,5 +100,8 @@ int main(int, char**) {
   static_assert(sizeof(std::variant<char, int, long>) == sizeof(type_with_index<long>));
   static_assert(sizeof(std::variant<std::size_t, std::size_t, std::size_t>) == sizeof(type_with_index<std::size_t>));
 
+  static_assert((sizeof(VariantWithNoUniqueAddress) < sizeof(VariantWithoutNoUniqueAddress)) ==
+                ExpectSmallerSizeWithNoUniqueAddress);
+
   return 0;
 }
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant_robust_against_no_unique_address.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant_robust_against_no_unique_address.pass.cpp
new file mode 100644
index 0000000000000..06f598aa40329
--- /dev/null
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant_robust_against_no_unique_address.pass.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// <variant>
+
+#include <cassert>
+#include <variant>
+
+#include "test_macros.h"
+
+struct S {
+  TEST_NO_UNIQUE_ADDRESS std::variant<int, void*> a;
+  bool b;
+};
+
+TEST_CONSTEXPR_CXX20 bool test() {
+  S x{{}, true};
+  x.a.emplace<0>();
+  x.a.emplace<1>();
+  return x.b;
+}
+
+int main() {
+  assert(test());
+#if TEST_STD_VER >= 20
+  static_assert(test());
+#endif
+}



More information about the libcxx-commits mailing list