This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: [patch, libstdc++] In debug mode, diagnose empty initializer_list in min/max/minmax
- From: Eelis van der Weegen <eelis at eelis dot net>
- To: Jonathan Wakely <jwakely at redhat dot com>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>, libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Thu, 25 Feb 2016 21:07:20 +0100
- Subject: Re: [patch, libstdc++] In debug mode, diagnose empty initializer_list in min/max/minmax
- Authentication-results: sourceware.org; auth=none
- References: <56CCC918 dot 9040905 at eelis dot net> <20160223223951 dot GA3162 at redhat dot com>
On 2016-02-23 23:39, Jonathan Wakely wrote:
On 23/02/16 22:03 +0100, Eelis wrote:
The std::min, std::max, and std::minmax overloads that take a std::initializer_list all require that the list is not empty. The attached patch adds debug mode checks for this.
Nice, thanks for the patch.
Hi Jonathan,
Thanks for the review! Updated patch attached.
I couldn't find precedent in the libstdc++ testsuite of tests that test __glibcxx_assert assertions, so I put these under {min,max,minmax}/assert/, analogous to {min,max,minmax}/debug/. Is that ok?
Otherwise this looks good, but will have to wait until after the GCC 6 release now.
No hurry at all. :)
Cheers,
Eelis
Index: libstdc++-v3/include/debug/formatter.h
===================================================================
--- libstdc++-v3/include/debug/formatter.h (revision 233636)
+++ libstdc++-v3/include/debug/formatter.h (working copy)
@@ -127,7 +127,8 @@
// others
__msg_equal_allocs,
__msg_insert_range_from_self,
- __msg_irreflexive_ordering
+ __msg_irreflexive_ordering,
+ __msg_empty_init_list
};
class _Error_formatter
Index: libstdc++-v3/src/c++11/debug.cc
===================================================================
--- libstdc++-v3/src/c++11/debug.cc (revision 233636)
+++ libstdc++-v3/src/c++11/debug.cc (working copy)
@@ -188,7 +188,8 @@
"allocators must be equal",
"attempt to insert with an iterator range [%1.name;, %2.name;) from this"
" container",
- "comparison doesn't meet irreflexive requirements, assert(!(a < a))"
+ "comparison doesn't meet irreflexive requirements, assert(!(a < a))",
+ "%1;(): empty initializer_list"
};
void
Index: libstdc++-v3/include/debug/macros.h
===================================================================
--- libstdc++-v3/include/debug/macros.h (revision 233636)
+++ libstdc++-v3/include/debug/macros.h (working copy)
@@ -69,6 +69,12 @@
._M_iterator(_First, #_First) \
._M_iterator(_Last, #_Last))
+// Verify that the initializer_list is non-empty.
+#define __glibcxx_check_non_empty_init_list(_List) \
+_GLIBCXX_DEBUG_VERIFY(_List.size() != 0, \
+ _M_message(__gnu_debug::__msg_empty_init_list) \
+ ._M_string(__func__))
+
/** Verify that we can insert into *this with the iterator _Position.
* Insertion into a container at a specific position requires that
* the iterator be nonsingular, either dereferenceable or past-the-end,
Index: libstdc++-v3/include/debug/debug.h
===================================================================
--- libstdc++-v3/include/debug/debug.h (revision 233636)
+++ libstdc++-v3/include/debug/debug.h (working copy)
@@ -87,9 +87,13 @@
// Verify that the container is nonempty
# define __glibcxx_requires_nonempty() \
__glibcxx_assert(! this->empty())
+// Verify that the initializer_list is non-empty.
+# define __glibcxx_requires_non_empty_init_list(_List) \
+ __glibcxx_assert(_List.size() != 0)
#else
# define __glibcxx_requires_non_empty_range(_First,_Last)
# define __glibcxx_requires_nonempty()
+# define __glibcxx_requires_non_empty_init_list(_List)
#endif
#else
@@ -99,6 +103,8 @@
# define __glibcxx_requires_cond(_Cond,_Msg) _GLIBCXX_DEBUG_VERIFY(_Cond,_Msg)
# define __glibcxx_requires_valid_range(_First,_Last) \
__glibcxx_check_valid_range(_First,_Last)
+# define __glibcxx_requires_non_empty_init_list(_List) \
+ __glibcxx_check_non_empty_init_list(_List)
# define __glibcxx_requires_non_empty_range(_First,_Last) \
__glibcxx_check_non_empty_range(_First,_Last)
# define __glibcxx_requires_sorted(_First,_Last) \
Index: libstdc++-v3/include/bits/stl_algo.h
===================================================================
--- libstdc++-v3/include/bits/stl_algo.h (revision 233636)
+++ libstdc++-v3/include/bits/stl_algo.h (working copy)
@@ -3452,25 +3452,37 @@
_GLIBCXX14_CONSTEXPR
inline _Tp
min(initializer_list<_Tp> __l)
- { return *std::min_element(__l.begin(), __l.end()); }
+ {
+ __glibcxx_requires_non_empty_init_list(__l);
+ return *std::min_element(__l.begin(), __l.end());
+ }
template<typename _Tp, typename _Compare>
_GLIBCXX14_CONSTEXPR
inline _Tp
min(initializer_list<_Tp> __l, _Compare __comp)
- { return *std::min_element(__l.begin(), __l.end(), __comp); }
+ {
+ __glibcxx_requires_non_empty_init_list(__l);
+ return *std::min_element(__l.begin(), __l.end(), __comp);
+ }
template<typename _Tp>
_GLIBCXX14_CONSTEXPR
inline _Tp
max(initializer_list<_Tp> __l)
- { return *std::max_element(__l.begin(), __l.end()); }
+ {
+ __glibcxx_requires_non_empty_init_list(__l);
+ return *std::max_element(__l.begin(), __l.end());
+ }
template<typename _Tp, typename _Compare>
_GLIBCXX14_CONSTEXPR
inline _Tp
max(initializer_list<_Tp> __l, _Compare __comp)
- { return *std::max_element(__l.begin(), __l.end(), __comp); }
+ {
+ __glibcxx_requires_non_empty_init_list(__l);
+ return *std::max_element(__l.begin(), __l.end(), __comp);
+ }
template<typename _Tp>
_GLIBCXX14_CONSTEXPR
@@ -3477,6 +3489,7 @@
inline pair<_Tp, _Tp>
minmax(initializer_list<_Tp> __l)
{
+ __glibcxx_requires_non_empty_init_list(__l);
pair<const _Tp*, const _Tp*> __p =
std::minmax_element(__l.begin(), __l.end());
return std::make_pair(*__p.first, *__p.second);
@@ -3487,6 +3500,7 @@
inline pair<_Tp, _Tp>
minmax(initializer_list<_Tp> __l, _Compare __comp)
{
+ __glibcxx_requires_non_empty_init_list(__l);
pair<const _Tp*, const _Tp*> __p =
std::minmax_element(__l.begin(), __l.end(), __comp);
return std::make_pair(*__p.first, *__p.second);
Index: libstdc++-v3/testsuite/25_algorithms/max/assert/empty_neg.cc
===================================================================
--- libstdc++-v3/testsuite/25_algorithms/max/assert/empty_neg.cc (revision 0)
+++ libstdc++-v3/testsuite/25_algorithms/max/assert/empty_neg.cc (working copy)
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+//
+// { dg-options "-std=gnu++11" }
+// { dg-do run { xfail *-*-* } }
+
+#define _GLIBCXX_ASSERTIONS
+
+#include <algorithm>
+
+void test01()
+{
+ std::max<int>({}); // error: empty initializer_list
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
Index: libstdc++-v3/testsuite/25_algorithms/max/debug/empty_neg.cc
===================================================================
--- libstdc++-v3/testsuite/25_algorithms/max/debug/empty_neg.cc (revision 0)
+++ libstdc++-v3/testsuite/25_algorithms/max/debug/empty_neg.cc (working copy)
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+//
+// { dg-options "-std=gnu++11" }
+// { dg-do run { xfail *-*-* } }
+
+#define _GLIBCXX_DEBUG
+
+#include <algorithm>
+
+void test01()
+{
+ std::max<int>({}); // error: empty initializer_list
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
Index: libstdc++-v3/testsuite/25_algorithms/min/assert/empty_neg.cc
===================================================================
--- libstdc++-v3/testsuite/25_algorithms/min/assert/empty_neg.cc (revision 0)
+++ libstdc++-v3/testsuite/25_algorithms/min/assert/empty_neg.cc (working copy)
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+//
+// { dg-options "-std=gnu++11" }
+// { dg-do run { xfail *-*-* } }
+
+#define _GLIBCXX_ASSERTIONS
+
+#include <algorithm>
+
+void test01()
+{
+ std::min<int>({}); // error: empty initializer_list
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
Index: libstdc++-v3/testsuite/25_algorithms/min/debug/empty_neg.cc
===================================================================
--- libstdc++-v3/testsuite/25_algorithms/min/debug/empty_neg.cc (revision 0)
+++ libstdc++-v3/testsuite/25_algorithms/min/debug/empty_neg.cc (working copy)
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+//
+// { dg-options "-std=gnu++11" }
+// { dg-do run { xfail *-*-* } }
+
+#define _GLIBCXX_DEBUG
+
+#include <algorithm>
+
+void test01()
+{
+ std::min<int>({}); // error: empty initializer_list
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
Index: libstdc++-v3/testsuite/25_algorithms/minmax/assert/empty_neg.cc
===================================================================
--- libstdc++-v3/testsuite/25_algorithms/minmax/assert/empty_neg.cc (revision 0)
+++ libstdc++-v3/testsuite/25_algorithms/minmax/assert/empty_neg.cc (working copy)
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+//
+// { dg-options "-std=gnu++11" }
+// { dg-do run { xfail *-*-* } }
+
+#define _GLIBCXX_ASSERTIONS
+
+#include <algorithm>
+
+void test01()
+{
+ std::minmax<int>({}); // error: empty initializer_list
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
Index: libstdc++-v3/testsuite/25_algorithms/minmax/debug/empty_neg.cc
===================================================================
--- libstdc++-v3/testsuite/25_algorithms/minmax/debug/empty_neg.cc (revision 0)
+++ libstdc++-v3/testsuite/25_algorithms/minmax/debug/empty_neg.cc (working copy)
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+//
+// { dg-options "-std=gnu++11" }
+// { dg-do run { xfail *-*-* } }
+
+#define _GLIBCXX_DEBUG
+
+#include <algorithm>
+
+void test01()
+{
+ std::minmax<int>({}); // error: empty initializer_list
+}
+
+int main()
+{
+ test01();
+ return 0;
+}