PR libstdc++/85965 delay static assertions until types are complete
authorJonathan Wakely <jwakely@redhat.com>
Tue, 26 Mar 2019 15:28:48 +0000 (15:28 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Tue, 26 Mar 2019 15:28:48 +0000 (15:28 +0000)
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

13 files changed:
libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/hashtable.h
libstdc++-v3/include/bits/stl_tree.h
libstdc++-v3/testsuite/23_containers/map/48101_neg.cc
libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc
libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc
libstdc++-v3/testsuite/23_containers/set/48101_neg.cc
libstdc++-v3/testsuite/23_containers/set/85965.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/unordered_map/48101_neg.cc
libstdc++-v3/testsuite/23_containers/unordered_multimap/48101_neg.cc
libstdc++-v3/testsuite/23_containers/unordered_multiset/48101_neg.cc
libstdc++-v3/testsuite/23_containers/unordered_set/48101_neg.cc
libstdc++-v3/testsuite/23_containers/unordered_set/85965.cc [new file with mode: 0644]

index 2e595b3eca8b4c5153780f8991699bff7c47a201..b15d12d3d8c78bf4cbba83b370273a28f3454395 100644 (file)
@@ -1,3 +1,21 @@
+2019-03-26  Jonathan Wakely  <jwakely@redhat.com>
+
+       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  <ville.voutilainen@gmail.com>
 
        PR libstdc++/89825
index 4737247994ac6f30209a4b72e4f15f9f8ec39bc0..da78c68434f77f4f4ed296b8c22d959fd45da5df 100644 (file)
@@ -192,11 +192,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static_assert(is_same<typename _Alloc::value_type, _Value>{},
          "unordered container must have the same value_type as its allocator");
 #endif
-      static_assert(__is_invocable<const _H1&, const _Key&>{},
-         "hash function must be invocable with an argument of key type");
-      static_assert(__is_invocable<const _Equal&, const _Key&, const _Key&>{},
-         "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<const _H1&, const _Key&>{},
+         "hash function must be invocable with an argument of key type");
+      static_assert(__is_invocable<const _Equal&, const _Key&, const _Key&>{},
+         "key equality predicate must be invocable with two arguments of "
+         "key type");
     }
 
   template<typename _Key, typename _Value,
index 47ae0ae9531f1ec280562384607825b6b90e5b14..7545ade3f7bc178527047989e96db769d3805b13 100644 (file)
@@ -440,17 +440,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       typedef __gnu_cxx::__alloc_traits<_Node_allocator> _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<const _Compare&, const _Key&, const _Key&>,
-         "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<const _Compare&, const _Key&, const _Key&>,
+                     "comparison object must be invocable as const");
+# endif // C++17
+#endif // C++11
+      }
 
       _Rb_tree&
       operator=(const _Rb_tree& __x);
index 066702d9d646200c0147ff1d6b1cd464dde6b695..355222058ffd533a21dd89c3310ec6d0043057ee 100644 (file)
 void
 test01()
 {
-  std::map<int, int, std::less<int*>> c;      // { dg-error "here" }
-  std::map<int, int, std::allocator<int>> c2; // { dg-error "here" }
+  std::map<int, int, std::less<int*>> c;
+  std::map<int, int, std::allocator<int>> c2;
 }
 
+// { dg-error "_Compare = std::less<int.>" "" { target *-*-* } 0 }
+// { dg-error "_Compare = std::allocator<int>" "" { target *-*-* } 0 }
 // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 }
index d46c4641433274a6f94f2f9791f96016e09cd70f..5f53ccee168ec943dc90b75e64a63e03709e43ee 100644 (file)
 void
 test01()
 {
-  std::multimap<int, int, std::less<int*>> c;      // { dg-error "here" }
-  std::multimap<int, int, std::allocator<int>> c2; // { dg-error "here" }
+  std::multimap<int, int, std::less<int*>> c;
+  std::multimap<int, int, std::allocator<int>> c2;
 }
 
+// { dg-error "_Compare = std::less<int.>" "" { target *-*-* } 0 }
+// { dg-error "_Compare = std::allocator<int>" "" { target *-*-* } 0 }
 // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 }
index 4aeac6e96d2dfd139c3b7e45df3c4f25d6aad233..71b90e80951c64cf8323515f37834bba4a805511 100644 (file)
@@ -23,7 +23,7 @@ void
 test01()
 {
   std::multiset<const int> c;             // { dg-error "here" }
-  std::multiset<int, std::less<long*>> c2; // { dg-error "here" }
+  std::multiset<int, std::less<long*>> c2;
 }
 
 // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 }
index e9797dec5d1d6986369a556772b663f446c7e8b5..e58c0627eb89b9bf90e1b0ac88be15c152c65911 100644 (file)
@@ -23,7 +23,7 @@ void
 test01()
 {
   std::set<const int> c;             // { dg-error "here" }
-  std::set<int, std::less<long*>> c2; // { dg-error "here" }
+  std::set<int, std::less<long*>> 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 (file)
index 0000000..54d501f
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <set>
+
+struct Base { };
+struct Derived; // derives from Base, but incomplete at this point
+
+struct Foo
+{
+  // PR libstdc++/85965
+  std::set<Derived*, std::less<Base*>> s;
+};
index 62be2eb29ee83f2bb85942f190af7bb107185785..6c3092554f3dc9e498627a7926b61eb6bed310cf 100644 (file)
@@ -23,7 +23,7 @@ void
 test01()
 {
   using namespace std;
-  unordered_map<int, int, equal_to<int>, hash<int>> c2;  // { dg-error "here" }
+  unordered_map<int, int, equal_to<int>, hash<int>> c2;
 }
 
 // { dg-error "hash function must be invocable" "" { target *-*-* } 0 }
index 54f380b82e3ca244d62f0a464c3b4c1bc5afb6e2..f5de313a8f172edbe54a834a2431838a24f21a1b 100644 (file)
@@ -23,7 +23,7 @@ void
 test01()
 {
   using namespace std;
-  unordered_multimap<int, int, equal_to<int>, hash<int>> c2; // { dg-error "here" }
+  unordered_multimap<int, int, equal_to<int>, hash<int>> c2;
 }
 
 // { dg-error "hash function must be invocable" "" { target *-*-* } 0 }
index 9149b386bd7ee6dc59445ed22b5981c6f37f08b1..d4e479aaf974d7e6ed25053f2de229ea57683808 100644 (file)
@@ -24,7 +24,7 @@ test01()
 {
   using namespace std;
   unordered_multiset<const int, hash<int>> c;          // { dg-error "here" }
-  unordered_multiset<int, equal_to<int>, hash<int>> c2; // { dg-error "here" }
+  unordered_multiset<int, equal_to<int>, hash<int>> c2;
 }
 
 // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 }
index e357eee6d1137537e473ab280d16ac01b65babe4..c7e27c536905ba60d1c5f280b79c42d6c7fc69f3 100644 (file)
@@ -24,7 +24,7 @@ test01()
 {
   using namespace std;
   unordered_set<const int, hash<int>> c;           // { dg-error "here" }
-  unordered_set<int, equal_to<int>, hash<int>> c2;  // { dg-error "here" }
+  unordered_set<int, equal_to<int>, hash<int>> 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 (file)
index 0000000..8b90b36
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <unordered_set>
+
+struct Base { };
+struct Derived; // derives from Base, but incomplete at this point
+
+struct Foo
+{
+  // PR libstdc++/85965
+  std::unordered_set<Derived*, std::equal_to<Base*>, std::hash<Base*>> u;
+};