Bug 51626 - [4.6 Regression] [C++0x] can't use C++98 allocators with -std=c++0x
Summary: [4.6 Regression] [C++0x] can't use C++98 allocators with -std=c++0x
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.6.2
: P3 normal
Target Milestone: 4.6.3
Assignee: Jonathan Wakely
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2011-12-19 18:03 UTC by Jonathan Wakely
Modified: 2011-12-21 18:37 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work: 4.5.3, 4.7.0
Known to fail: 4.6.2
Last reconfirmed: 2011-12-19 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Wakely 2011-12-19 18:03:34 UTC
#include <memory>
#include <vector>

template <class T>
struct allocator98 : std::allocator<T>
{
    template <class U> struct rebind { typedef allocator98<U> other; };

    allocator98() { }

    template <class U> allocator98(const allocator98<U>&) { };

    void construct(T* p, const T& val) { std::allocator<T>::construct(p, val); }
};

int main()
{
    std::vector< int, allocator98<int> > v(1);
}

This fails in c++0x mode because std::__uninitialized_default_n_a() incorrectly assumes it's OK to call Alloc::construct with a single argument.  That is true for std::allocator in C++0x mode, but not true for most user-defined allocators written to the C++98 requirements.

This is the cause of https://svn.boost.org/trac/boost/ticket/5538

The bug is fixed in 4.7 because std::allocator_traits provides a default implementation of construct, ensuring backwards-compatibility with C++98-style allocators.

A workaround for user-defined allocators is to add:
  void construct(pointer p) { return construct(p, value_type()); }

The fix for libstdc++ would be to avoid calling construct with a single argument, or to backport a minimal version of allocator_traits from 4.7
Comment 1 Paolo Carlini 2011-12-19 18:38:56 UTC
Bah, in my opinion it's late to attempt sophisticated things in 4.6, either we can do something minimal or we should just tell people that in 4.6 a C++0x container wants a C++0x allocator.
Comment 2 Jonathan Wakely 2011-12-19 18:57:45 UTC
I agree with the sentiment, but unfortunately a C++11 allocator isn't required to provide a construct member at all.  17.6.3.5 p5 shows a minimal C++11 allocator, and that won't work either, so 4.6 doesn't correctly support user-defined C++98 allocators or user-defined C++11 allocators!

I think the minimal fix is for __uninitialized_default_n_a and __uninitialized_default_a to default construct an object of the iterator's value_type and pass that to __alloc.construct(addressof(*cur))

A less-minimal fix would be to change all the containers to use __uninitialized_fill_a instead of __uninitialized_default_a
Comment 3 Jonathan Wakely 2011-12-19 19:04:53 UTC
Unfortunately either of those would cause a regression for PR 32618
Comment 4 Jonathan Wakely 2011-12-19 22:40:19 UTC
suggested patch posted to http://gcc.gnu.org/ml/gcc-patches/2011-12/msg01421.html
Comment 5 Jonathan Wakely 2011-12-21 18:35:48 UTC
Author: redi
Date: Wed Dec 21 18:35:40 2011
New Revision: 182600

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=182600
Log:
	PR libstdc++/51626
	* include/bits/stl_uninitialized.h (_Construct_default_a_impl): Define
	overloaded functions to conditionally use allocator::construct.
	(_Construct_default_a): Define to dispatch to appropriate
	_Construct_default_a_impl overload.
	(__uninitialized_default_a, __uninitialized_default_n_a): Use
	_Construct_default_a.
	* testsuite/20_util/allocator/51626.cc: New.

Added:
    branches/gcc-4_6-branch/libstdc++-v3/testsuite/20_util/allocator/51626.cc
Modified:
    branches/gcc-4_6-branch/libstdc++-v3/ChangeLog
    branches/gcc-4_6-branch/libstdc++-v3/include/bits/stl_uninitialized.h
Comment 6 Jonathan Wakely 2011-12-21 18:37:23 UTC
fixed for 4.6.3