[libcxx-commits] [libcxx] [libc++][string] Fix unnecessary padding for basic_string's __short (PR #135973)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed Apr 16 08:04:36 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Gábor Spaits (spaits)

<details>
<summary>Changes</summary>

Originally, padding in the struct `__short` was done with arrays, but when no padding was required, we got undefined behavior due to a zero-length array. C++17 11.3.4 Arrays p1:
```
If the <<length of array>> is present, it shall be a converted constant
expression of type std::size_t and its value shall be greater than zero.
```
A fix was proposed in commit d95597dc06c510ad7fbf00a43583c54d38f79aa7, which worked around the undefined behavior by wrapping the padding array in a struct if there was padding required and omitting the array altogether, with the help of a specialization, when the padding is zero.

This change doesn't just work around the problem but changes the semantics of the code, introducing an issue.

Contrary to C, in C++ empty structs and classes must have a size greater than zero. C++ 17 12 Classes p4:
```
Complete objects and member subobjects of class type shall have nonzero size.
```
So whenever there is no padding required we insert an empty struct-sized padding, which is 1 byte on X86_64 (but we won't feel it there, since on that platform padding is required if I am correct).

A standard compliant solution, that keeps to the original behavior could be done using unnamed 0 width bit-fields. 

12.2.4 Bit-fields p2:
```
As a special case, an unnamed bit-field with a width of zero
specifies alignment of the next bit-field at an allocation unit boundary. Only when declaring an unnamed
bit-field may the value of the constant-expression be equal to zero.
```

---
Full diff: https://github.com/llvm/llvm-project/pull/135973.diff


1 Files Affected:

- (modified) libcxx/include/string (+2-10) 


``````````diff
diff --git a/libcxx/include/string b/libcxx/include/string
index e7e541e31432d..c82cb5074e5d9 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -715,14 +715,6 @@ struct __can_be_converted_to_string_view
 struct __uninitialized_size_tag {};
 struct __init_with_sentinel_tag {};
 
-template <size_t _PaddingSize>
-struct __padding {
-  char __padding_[_PaddingSize];
-};
-
-template <>
-struct __padding<0> {};
-
 template <class _CharT, class _Traits, class _Allocator>
 class basic_string {
 public:
@@ -827,7 +819,7 @@ private:
 
   struct __short {
     value_type __data_[__min_cap];
-    _LIBCPP_NO_UNIQUE_ADDRESS __padding<sizeof(value_type) - 1> __padding_;
+    value_type : 0;
     unsigned char __size_    : 7;
     unsigned char __is_long_ : 1;
   };
@@ -879,7 +871,7 @@ private:
       unsigned char __is_long_ : 1;
       unsigned char __size_    : 7;
     };
-    _LIBCPP_NO_UNIQUE_ADDRESS __padding<sizeof(value_type) - 1> __padding_;
+    value_type : 0;
     value_type __data_[__min_cap];
   };
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/135973


More information about the libcxx-commits mailing list