public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* RFC: Bug 92285 - Layout of istreambuf_iterator subobject depends on -std mode
@ 2019-10-30 12:20 Jonathan Wakely
  2019-10-30 12:39 ` Marc Glisse
  0 siblings, 1 reply; 3+ messages in thread
From: Jonathan Wakely @ 2019-10-30 12:20 UTC (permalink / raw)
  To: libstdc++

I've just noticed https://gcc.gnu.org/PR92285 which shows that this
program prints a different result in C++98 vs other modes:

#include <iterator>
#include <iostream>

struct I : std::iterator<std::input_iterator_tag, char>
{ };

struct J : I, std::istreambuf_iterator<char>
{ };

int main()
{
  std::cout << sizeof(J) << '\n';
}

For C++98 it prints 24 but for other modes it prints 16. The reason is
that std::istreambuf_iterator has a different base class:

  template<typename _CharT, typename _Traits>
    class istreambuf_iterator
    : public iterator<input_iterator_tag, _CharT, typename _Traits::off_type,
		      _CharT*,
#if __cplusplus >= 201103L
    // LWG 445.
		      _CharT>
#else
		      _CharT&>
#endif

This affects layout because std::iterator is an empty class, so
whether the two base classes can share the same address depends on
what istreambuf_iterator's base class is.

This isn't a disaster, because in practice it is probably very rare
for a type to have two std::iterator subobjects that could have the
same address. But technically it's still an ABI incompatibility
between C++98 and C++11/14/17 modes.

The solution is to make istreambuf_iterator always have the same base
class, but then conditionally override the reference member:

  template<typename _CharT, typename _Traits>
    class istreambuf_iterator
    : public iterator<input_iterator_tag, _CharT, typename _Traits::off_type,
		      _CharT*, ???>
    {
    public:
      using reference = ???;

Now the base class will always be the same, and so won't change layout
when __cplusplus changes.

We have two options:

1) Make the base class the same as it was in C++98, and override it
for other modes.  The program above would always print 24.  This makes
the layout always consistent with the GCC 4.6 layout, for all modes,
but incompatible with the default -std=gnu++14 mode since GCC 6 (and
incompatible with code explicitly using C++11 or C++14 in GCC 4.7 and
above).

Or:

2) Always use the new base class, and override it for C++98.  The
program above would always print 16.  This makes layout for C++98
compatible with the current -std=gnu++14 default, but no longer
compatible with C++98 code from previous releases.

Option 1 might be better for users of older enterprise distros, who are
still using GCC 4.x compilers and C++98 (because it's the default, and
possibly the only mode supported by their vendor, e.g. RHEL 7 users
using the system GCC).

Option 2 is probably better for everybody using recent versions of GCC
and recent standard modes. They probably don't care about C++98 (or
GCC 4.6) any more, and so always using the new layout won't affect
them.

I think I'm leaning towards option 2. Nobody has noticed this, so I
don't expect it to affect anybody if we change C++98 mode now to match
the C++14 default.

N.B. the decision should not be "choose the option that makes
sizeof(J) smaller", because I can easily create an example where C++98
prints 16 and other modes print 24, so we're not trying to optimize
for size. What matters is compatibility, not the absolute value.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: RFC: Bug 92285 - Layout of istreambuf_iterator subobject depends on -std mode
  2019-10-30 12:20 RFC: Bug 92285 - Layout of istreambuf_iterator subobject depends on -std mode Jonathan Wakely
@ 2019-10-30 12:39 ` Marc Glisse
  2019-10-30 12:51   ` Jonathan Wakely
  0 siblings, 1 reply; 3+ messages in thread
From: Marc Glisse @ 2019-10-30 12:39 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++

On Wed, 30 Oct 2019, Jonathan Wakely wrote:

> I've just noticed https://gcc.gnu.org/PR92285 which shows that this
> program prints a different result in C++98 vs other modes:
>
> #include <iterator>
> #include <iostream>
>
> struct I : std::iterator<std::input_iterator_tag, char>
> { };
>
> struct J : I, std::istreambuf_iterator<char>
> { };
>
> int main()
> {
> std::cout << sizeof(J) << '\n';
> }
>
> For C++98 it prints 24 but for other modes it prints 16. The reason is
> that std::istreambuf_iterator has a different base class:
>
> template<typename _CharT, typename _Traits>
>   class istreambuf_iterator
>   : public iterator<input_iterator_tag, _CharT, typename _Traits::off_type,
> 		      _CharT*,
> #if __cplusplus >= 201103L
>   // LWG 445.
> 		      _CharT>
> #else
> 		      _CharT&>
> #endif
>
> This affects layout because std::iterator is an empty class, so
> whether the two base classes can share the same address depends on
> what istreambuf_iterator's base class is.
>
> This isn't a disaster, because in practice it is probably very rare
> for a type to have two std::iterator subobjects that could have the
> same address. But technically it's still an ABI incompatibility
> between C++98 and C++11/14/17 modes.
>
> The solution is to make istreambuf_iterator always have the same base
> class, but then conditionally override the reference member:
>
> template<typename _CharT, typename _Traits>
>   class istreambuf_iterator
>   : public iterator<input_iterator_tag, _CharT, typename _Traits::off_type,
> 		      _CharT*, ???>
>   {
>   public:
>     using reference = ???;
>
> Now the base class will always be the same, and so won't change layout
> when __cplusplus changes.
>
> We have two options:
>
> 1) Make the base class the same as it was in C++98, and override it
> for other modes.  The program above would always print 24.  This makes
> the layout always consistent with the GCC 4.6 layout, for all modes,
> but incompatible with the default -std=gnu++14 mode since GCC 6 (and
> incompatible with code explicitly using C++11 or C++14 in GCC 4.7 and
> above).
>
> Or:
>
> 2) Always use the new base class, and override it for C++98.  The
> program above would always print 16.  This makes layout for C++98
> compatible with the current -std=gnu++14 default, but no longer
> compatible with C++98 code from previous releases.

3) Don't use any base class, write the 5 typedefs manually.

> N.B. the decision should not be "choose the option that makes
> sizeof(J) smaller", because I can easily create an example where C++98
> prints 16 and other modes print 24, so we're not trying to optimize
> for size. What matters is compatibility, not the absolute value.

3 is never bigger ;-)

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: RFC: Bug 92285 - Layout of istreambuf_iterator subobject depends on -std mode
  2019-10-30 12:39 ` Marc Glisse
@ 2019-10-30 12:51   ` Jonathan Wakely
  0 siblings, 0 replies; 3+ messages in thread
From: Jonathan Wakely @ 2019-10-30 12:51 UTC (permalink / raw)
  To: libstdc++

On 30/10/19 13:39 +0100, Marc Glisse wrote:
>On Wed, 30 Oct 2019, Jonathan Wakely wrote:
>>We have two options:
>>
>>1) Make the base class the same as it was in C++98, and override it
>>for other modes.  The program above would always print 24.  This makes
>>the layout always consistent with the GCC 4.6 layout, for all modes,
>>but incompatible with the default -std=gnu++14 mode since GCC 6 (and
>>incompatible with code explicitly using C++11 or C++14 in GCC 4.7 and
>>above).
>>
>>Or:
>>
>>2) Always use the new base class, and override it for C++98.  The
>>program above would always print 16.  This makes layout for C++98
>>compatible with the current -std=gnu++14 default, but no longer
>>compatible with C++98 code from previous releases.
>
>3) Don't use any base class, write the 5 typedefs manually.
>
>>N.B. the decision should not be "choose the option that makes
>>sizeof(J) smaller", because I can easily create an example where C++98
>>prints 16 and other modes print 24, so we're not trying to optimize
>>for size. What matters is compatibility, not the absolute value.
>
>3 is never bigger ;-)

Indeed, but it breaks compatibility with all previous versions and all
previous modes (and is non-conforming for C++98/11/14).

It's an option, but I don't like it.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2019-10-30 12:51 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-30 12:20 RFC: Bug 92285 - Layout of istreambuf_iterator subobject depends on -std mode Jonathan Wakely
2019-10-30 12:39 ` Marc Glisse
2019-10-30 12:51   ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).