From 7ac205673caade367552a567a98e27940f17cf35 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 26 Mar 2019 15:28:48 +0000 Subject: [PATCH] PR libstdc++/85965 delay static assertions until types are complete The static assertions added for PR libstdc++/48101 were at class scope and so were evaluated too eagerly, when it might not be possible to determine whether the function objects are invocable with the key types. The problematic cases are where the key type is not known to be convertible to the argument type(s) of the function object until later, after a type has been completed. Specifically, if the key type is a pointer to a derived class and the function object's argument type is a pointer to a base class, then the derived-to-base conversion is only valid once the derived type is complete. By moving the static assertions to the destructor they will only be evaluated when the destructor is instantiated, at which point whether the key type can be passed to the function object should be knowable. The ideal place to do the checks would be only when the function objects are actually invoked, but that would mean adding the checks in numerous places, so the destructor is used instead. The tests need to be adjusted because the "required from here" line is now the location of the destructor, not the point of instantiation in the test file. For the map and multimap tests which check two specializations, the dg-error matching the assertion text matches both cases. Also check the diagnostic output for the template arguments, to ensure both specializations trigger the assertion. PR libstdc++/85965 * include/bits/hashtable.h (_Hashtable): Move static assertions to destructor so they are not evaluated until the _Key type is complete. * include/bits/stl_tree.h (_Rb_tree): Likewise. * testsuite/23_containers/set/85965.cc: New test. * testsuite/23_containers/unordered_set/85965.cc: New test. * testsuite/23_containers/map/48101_neg.cc: Replace "here" errors with regexp matching the corresponding _Rb_tree specialization. * testsuite/23_containers/multimap/48101_neg.cc: Likewise. * testsuite/23_containers/multiset/48101_neg.cc: Remove "here" error. * testsuite/23_containers/set/48101_neg.cc: Likewise. * testsuite/23_containers/unordered_map/48101_neg.cc: Likewise. * testsuite/23_containers/unordered_multimap/48101_neg.cc: Likewise. * testsuite/23_containers/unordered_multiset/48101_neg.cc: Likewise. * testsuite/23_containers/unordered_set/48101_neg.cc: Likewise. From-SVN: r269949 --- libstdc++-v3/ChangeLog | 18 ++++++++++++ libstdc++-v3/include/bits/hashtable.h | 11 +++---- libstdc++-v3/include/bits/stl_tree.h | 27 +++++++++-------- .../testsuite/23_containers/map/48101_neg.cc | 6 ++-- .../23_containers/multimap/48101_neg.cc | 6 ++-- .../23_containers/multiset/48101_neg.cc | 2 +- .../testsuite/23_containers/set/48101_neg.cc | 2 +- .../testsuite/23_containers/set/85965.cc | 29 +++++++++++++++++++ .../23_containers/unordered_map/48101_neg.cc | 2 +- .../unordered_multimap/48101_neg.cc | 2 +- .../unordered_multiset/48101_neg.cc | 2 +- .../23_containers/unordered_set/48101_neg.cc | 2 +- .../23_containers/unordered_set/85965.cc | 29 +++++++++++++++++++ 13 files changed, 111 insertions(+), 27 deletions(-) create mode 100644 libstdc++-v3/testsuite/23_containers/set/85965.cc create mode 100644 libstdc++-v3/testsuite/23_containers/unordered_set/85965.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 2e595b3eca8..b15d12d3d8c 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,21 @@ +2019-03-26 Jonathan Wakely + + PR libstdc++/85965 + * include/bits/hashtable.h (_Hashtable): Move static assertions to + destructor so they are not evaluated until the _Key type is complete. + * include/bits/stl_tree.h (_Rb_tree): Likewise. + * testsuite/23_containers/set/85965.cc: New test. + * testsuite/23_containers/unordered_set/85965.cc: New test. + * testsuite/23_containers/map/48101_neg.cc: Replace "here" errors + with regexp matching the corresponding _Rb_tree specialization. + * testsuite/23_containers/multimap/48101_neg.cc: Likewise. + * testsuite/23_containers/multiset/48101_neg.cc: Remove "here" error. + * testsuite/23_containers/set/48101_neg.cc: Likewise. + * testsuite/23_containers/unordered_map/48101_neg.cc: Likewise. + * testsuite/23_containers/unordered_multimap/48101_neg.cc: Likewise. + * testsuite/23_containers/unordered_multiset/48101_neg.cc: Likewise. + * testsuite/23_containers/unordered_set/48101_neg.cc: Likewise. + 2019-03-26 Ville Voutilainen PR libstdc++/89825 diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h index 4737247994a..da78c68434f 100644 --- a/libstdc++-v3/include/bits/hashtable.h +++ b/libstdc++-v3/include/bits/hashtable.h @@ -192,11 +192,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(is_same{}, "unordered container must have the same value_type as its allocator"); #endif - static_assert(__is_invocable{}, - "hash function must be invocable with an argument of key type"); - static_assert(__is_invocable{}, - "key equality predicate must be invocable with two arguments of " - "key type"); using __traits_type = _Traits; using __hash_cached = typename __traits_type::__hash_cached; @@ -1356,6 +1351,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { clear(); _M_deallocate_buckets(); + + static_assert(__is_invocable{}, + "hash function must be invocable with an argument of key type"); + static_assert(__is_invocable{}, + "key equality predicate must be invocable with two arguments of " + "key type"); } template _Alloc_traits; -#if __cplusplus >= 201103L - static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{}, - "comparison object must be invocable with two arguments of key type"); -# if __cplusplus >= 201703L - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 2542. Missing const requirements for associative containers - static_assert(is_invocable_v, - "comparison object must be invocable as const"); -# endif // C++17 -#endif // C++11 - protected: typedef _Rb_tree_node_base* _Base_ptr; typedef const _Rb_tree_node_base* _Const_Base_ptr; @@ -985,7 +974,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif ~_Rb_tree() _GLIBCXX_NOEXCEPT - { _M_erase(_M_begin()); } + { + _M_erase(_M_begin()); + +#if __cplusplus >= 201103L + static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{}, + "comparison object must be invocable " + "with two arguments of key type"); +# if __cplusplus >= 201703L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2542. Missing const requirements for associative containers + static_assert(is_invocable_v, + "comparison object must be invocable as const"); +# endif // C++17 +#endif // C++11 + } _Rb_tree& operator=(const _Rb_tree& __x); diff --git a/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc index 066702d9d64..355222058ff 100644 --- a/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc @@ -23,8 +23,10 @@ void test01() { - std::map> c; // { dg-error "here" } - std::map> c2; // { dg-error "here" } + std::map> c; + std::map> c2; } +// { dg-error "_Compare = std::less" "" { target *-*-* } 0 } +// { dg-error "_Compare = std::allocator" "" { target *-*-* } 0 } // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc index d46c4641433..5f53ccee168 100644 --- a/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc @@ -23,8 +23,10 @@ void test01() { - std::multimap> c; // { dg-error "here" } - std::multimap> c2; // { dg-error "here" } + std::multimap> c; + std::multimap> c2; } +// { dg-error "_Compare = std::less" "" { target *-*-* } 0 } +// { dg-error "_Compare = std::allocator" "" { target *-*-* } 0 } // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc index 4aeac6e96d2..71b90e80951 100644 --- a/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc @@ -23,7 +23,7 @@ void test01() { std::multiset c; // { dg-error "here" } - std::multiset> c2; // { dg-error "here" } + std::multiset> c2; } // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc index e9797dec5d1..e58c0627eb8 100644 --- a/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc @@ -23,7 +23,7 @@ void test01() { std::set c; // { dg-error "here" } - std::set> c2; // { dg-error "here" } + std::set> c2; } // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/23_containers/set/85965.cc b/libstdc++-v3/testsuite/23_containers/set/85965.cc new file mode 100644 index 00000000000..54d501f6c4f --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/set/85965.cc @@ -0,0 +1,29 @@ +// Copyright (C) 2019 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 +// . + +// { dg-do compile { target c++11 } } + +#include + +struct Base { }; +struct Derived; // derives from Base, but incomplete at this point + +struct Foo +{ + // PR libstdc++/85965 + std::set> s; +}; diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/48101_neg.cc index 62be2eb29ee..6c3092554f3 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/48101_neg.cc @@ -23,7 +23,7 @@ void test01() { using namespace std; - unordered_map, hash> c2; // { dg-error "here" } + unordered_map, hash> c2; } // { dg-error "hash function must be invocable" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/48101_neg.cc index 54f380b82e3..f5de313a8f1 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/48101_neg.cc @@ -23,7 +23,7 @@ void test01() { using namespace std; - unordered_multimap, hash> c2; // { dg-error "here" } + unordered_multimap, hash> c2; } // { dg-error "hash function must be invocable" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/48101_neg.cc index 9149b386bd7..d4e479aaf97 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/48101_neg.cc @@ -24,7 +24,7 @@ test01() { using namespace std; unordered_multiset> c; // { dg-error "here" } - unordered_multiset, hash> c2; // { dg-error "here" } + unordered_multiset, hash> c2; } // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/48101_neg.cc index e357eee6d11..c7e27c53690 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_set/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/48101_neg.cc @@ -24,7 +24,7 @@ test01() { using namespace std; unordered_set> c; // { dg-error "here" } - unordered_set, hash> c2; // { dg-error "here" } + unordered_set, hash> c2; } // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/85965.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/85965.cc new file mode 100644 index 00000000000..8b90b369901 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/85965.cc @@ -0,0 +1,29 @@ +// Copyright (C) 2019 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 +// . + +// { dg-do compile { target c++11 } } + +#include + +struct Base { }; +struct Derived; // derives from Base, but incomplete at this point + +struct Foo +{ + // PR libstdc++/85965 + std::unordered_set, std::hash> u; +}; -- 2.30.2