[libcxx-commits] [PATCH] D124555: [libcxx][AIX][z/OS] basic_ios<wchar_t> cannot store fill character WCHAR_MAX

Chris Bowler via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jun 14 09:17:59 PDT 2022


cebowleratibm added a comment.

In D124555#3571553 <https://reviews.llvm.org/D124555#3571553>, @hubert.reinterpretcast wrote:

> In D124555#3566746 <https://reviews.llvm.org/D124555#3566746>, @ldionne wrote:
>
>>   template <class _Traits>
>>   struct _OptionalFill {
>>     _OptionalFill() : __set_(false) { }
>>     _OptionalFill& operator=(typename _Traits::int_type __x) { __set_ = true; __fill_ = __x; return *this; }
>>     bool __is_set() const { return __set_; }
>>     typename _Traits::int_type __fill() const { return __fill_; }
>>   
>>   private:
>>     typename _Traits::int_type __fill_;
>>     bool __set_;
>>   };
>>
>> Thoughts?
>
> From the AIX and z/OS perspective, the replacement of the two members with a member having two fields is not 100% binary compatible for all usage. At least if the `basic_ios` specialization is used as a non-virtual base class, any derived class members that could be allocated in the padding following the `bool` would now move. This could be preemptively avoided if the new class type is given a user-provided copy constructor or destructor and the new member made `[[no_unique_address]]`. I don't know if `[[no_unique_address]]` is usable is some form under C++98/03 though.

For background, the (customized) libc++ that is provided on AIX used the form where the bool member is injected directly in `basic_ios`.

I drafted an update with the `_OptionalFill` / `_SentinelFill` suggestion and have confirmed that there are layout differences on AIX in derived classes when the first derived member is 1 or 2 byte aligned.  Alternatively, even if all inheritance of `basic_ios` is virtual, there's still potential layout differences where a user derived class has multiple virtual bases and the second virtual base wants to start inside the padding.  I did try `[[no_unique_address]]`, however, the syntax is not accepted with `-std=c++03`.  Unless we want to version the 03 code from the C++11 forward code, I don't think there's a way to get a layout compatible type using this approach.

One idea Hubert and I discussed offline is to use a member declaration `bool __is_set[Boolean expression]` and have it deliberately zero-size when the `__is_set` member isn't needed.  We can still use `_OptionalFill` / `_SentinelFill` to control access to the member.

Another obstacle is that the proper check to enable to use of `_OptionalFill` looks like:

  using _FillType = _If<traits_type::eq_int_type(
                            std::numeric_limits<char_type>::max(),
                            traits_type::eof()),
                        _OptionalFill, _SentinelValueFill>;

but note that `eq_int_type` and `eof` can only participate in constant expressions where they are constexpr in C++11, so I again have a challenge in delivering a solution that works in C++03.  I'll need to use a wchar specialization and use something like `WEOF < (wint_t)WCHAR_MIN || (win_t)WCHAR_MAX < WEOF`.

Given my limited experience with LLVM libc++ some guidance along which fundamental approach we should take would be appreciated.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D124555/new/

https://reviews.llvm.org/D124555



More information about the libcxx-commits mailing list