From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22922 invoked by alias); 27 Nov 2014 16:59:50 -0000 Mailing-List: contact gcc-bugs-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-bugs-owner@gcc.gnu.org Received: (qmail 22900 invoked by uid 48); 27 Nov 2014 16:59:45 -0000 From: "palpatin91 at mail dot ru" To: gcc-bugs@gcc.gnu.org Subject: [Bug libstdc++/64096] New: std::list, set and map violate a rule about allocator::construct Date: Thu, 27 Nov 2014 16:59:00 -0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: libstdc++ X-Bugzilla-Version: 4.9.0 X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: palpatin91 at mail dot ru X-Bugzilla-Status: UNCONFIRMED X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: bug_id short_desc product version bug_status bug_severity priority component assigned_to reporter Message-ID: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-SW-Source: 2014-11/txt/msg03260.txt.bz2 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D64096 Bug ID: 64096 Summary: std::list, set and map violate a rule about allocator::construct Product: gcc Version: 4.9.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: palpatin91 at mail dot ru According to the 23.2.1p3 C++11 Standard: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D For the components affected by this subclause that declare an allocator_typ= e, objects stored in these components shall be constructed using the allocator_traits::construct function and destroyed using the allocator_traits::destroy function (20.6.8.2). These functi= ons are called only for the container=E2=80=99s element type, not for internal = types used by the container. [ Note: This means, for example, that a node-based contai= ner might need to construct nodes containing aligned buffers and call construct= to place the element into the buffer. =E2=80=94end note ] =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Here allocator_type is a direct template's type argument, and allocator_tra= its just call allocator's construct method, if it exists. However, std::list, s= et and map (and also multiset and multimap) violate this rule and call constru= ct method from an allocator of rebinded type, not of an original one. I know, = that we need rebinding for memory allocation, but for construct call we should u= se original one. 23.2.1p13 also proves this: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Given a container type X having an allocator_type identical to A and a value_type identical to T and given an lvalue m of type A, a pointer p of t= ype T*, an expression v of type T, and an rvalue rv of type T, the following te= rms are defined. (If X is not allocator-aware, the terms below are defined as i= f A were std::allocator.) =E2=80=94 T is CopyInsertable into X means that the following expression is well-formed: allocator_traits::construct(m, p, v); =E2=80=94 T is MoveInsertable into X means that the following expression is well-formed: allocator_traits::construct(m, p, rv); =E2=80=94 T is EmplaceConstructible into X from args, for zero or more argu= ments args, means that the following expression is well-formed: allocator_traits::construct(m, p, args); =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Now some code that confirms a bug: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D #include #include #include #include #include #include #include template struct my_allocator : public std::allocator { my_allocator() noexcept {} template my_allocator(const my_allocator& source) noexcept : std::allocator(source) {} template struct rebind { using other =3D my_allocator; }; template void construct(U*, Args&&...) { static_assert(!std::is_same::value, "Wrong construct"); } }; template bool operator=3D=3D(const my_allocator&, const my_allocator&) { return true; } template bool operator!=3D(const my_allocator&, const my_allocator&) { return false; } template<> struct my_allocator : public std::allocator { my_allocator() noexcept {} template my_allocator(const my_allocator& source) noexcept : std::allocator(source) {} template struct rebind { using other =3D my_allocator; }; }; using map_int_int_value_type =3D std::map::value_type; template<> struct my_allocator : public std::allocator { my_allocator() noexcept {} template my_allocator(const my_allocator& source) noexcept : std::allocator(source) {} template struct rebind { using other =3D my_allocator; }; }; int main() { { using container =3D std::vector>; container c; c.emplace_back(0); } { using container =3D std::list>; container c; c.emplace_back(0); } { using container =3D std::set, my_allocator= >; container c; c.emplace(0); } { using container =3D std::multiset, my_allocator>; container c; c.emplace(0); } { using container =3D std::unordered_set, std::equal_to, my_allocator>; container c; c.emplace(0); } { using container =3D std::unordered_multiset, std::equal_to, my_allocator>; container c; c.emplace(0); } { using container =3D std::map, my_allocator>; container c; c.emplace(0, 0); } { using container =3D std::multimap, my_allocator>; container c; c.emplace(0, 0); } { using container =3D std::unordered_map, std::equal_to, my_allocator>; container c; c.emplace(0, 0); } { using container =3D std::unordered_multimap, std::equal_to, my_allocator>; container c; c.emplace(0, 0); } { using container =3D std::deque>; container c; c.emplace_back(0); } } =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D We make a template allocator class, that print static_assert error message, when someone try to instantiate his construct method, and then make 2 specializations of this class template (for int and for std::pair), which inherit construct method from std::allocator and so don't gene= rate any error. The compiler's output is (I leave only important lines): =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D main.cpp: In instantiation of 'void my_allocator::construct(U*, Args&& .= ..) [with U =3D std::_List_node Args =3D {int}; T =3D std::_List_node= ]': ... main.cpp:24:9: error: static assertion failed: Wrong construct main.cpp: In instantiation of 'void my_allocator::construct(U*, Args&& .= ..) [with U =3D int; Args =3D {int}; T =3D std::_Rb_tree_node]': ... main.cpp:24:9: error: static assertion failed: Wrong construct main.cpp: In instantiation of 'void my_allocator::construct(U*, Args&& .= ..) [with U =3D std::pair Args =3D {int, int}; T =3D std::_Rb_tree_node >]': ... main.cpp:24:9: error: static assertion failed: Wrong construct =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D As we can see, std::list implementation tries to call construct for whole l= ist node (U =3D std::_List_node), and std::set and map (and also multiset = and multimap) call it for right type (int or std::pair), but fr= om rebinded allocator (T =3D std::_Rb_tree_node). All other containers (std::vector, std::deque and unordered ones) do everything right. >>From gcc-bugs-return-468789-listarch-gcc-bugs=gcc.gnu.org@gcc.gnu.org Thu Nov 27 17:08:06 2014 Return-Path: Delivered-To: listarch-gcc-bugs@gcc.gnu.org Received: (qmail 30831 invoked by alias); 27 Nov 2014 17:08:06 -0000 Mailing-List: contact gcc-bugs-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-bugs-owner@gcc.gnu.org Delivered-To: mailing list gcc-bugs@gcc.gnu.org Received: (qmail 30797 invoked by uid 48); 27 Nov 2014 17:08:01 -0000 From: "ams at gcc dot gnu.org" To: gcc-bugs@gcc.gnu.org Subject: [Bug middle-end/64032] [5 Regression] FAIL: gcc.dg/undefined-loop-2.c (test for warnings, line 18) Date: Thu, 27 Nov 2014 17:08:00 -0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: middle-end X-Bugzilla-Version: 5.0 X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: ams at gcc dot gnu.org X-Bugzilla-Status: NEW X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: ams at gcc dot gnu.org X-Bugzilla-Target-Milestone: 5.0 X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: Message-ID: In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 7bit X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-SW-Source: 2014-11/txt/msg03261.txt.bz2 Content-length: 651 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64032 --- Comment #2 from Andrew Stubbs --- When I configure for powerpc-linux-gnu, undefined-loop-2.c.003t.original contains this: if (((p != 0 ? (unsigned char) array1[i] != 0 : (unsigned char) array2[i] != 0) && i <= 4) && i <= 99) goto ; else goto ; When I configure for x86_64-linux-gnu, the same command and dump file contains this: if ((p != 0 ? (signed char) array1[i] != 0 : (signed char) array2[i] != 0) && i <= 4) goto ; else goto ; It looks like something has started optimizing the code really very early. This surprises me!