Go to file
Jonathan Wakely 01ba02caa9
libstdc++: Refactor std::hash specializations
This attempts to simplify and clean up our std::hash code. The primary
benefit is improved diagnostics for users when they do something wrong
involving std::hash or unordered containers. An additional benefit is
that for the unstable ABI (--enable-symvers=gnu-versioned-namespace) we
can reduce the memory footprint of several std::hash specializations.

In the current design, __hash_enum is a base class of the std::hash
primary template, but the partial specialization of __hash_enum for
non-enum types is disabled.  This means that if a user forgets to
specialize std::hash for their class type (or forgets to use a custom
hash function for unordered containers) they get error messages about
std::__hash_enum not being constructible.  This is confusing when there
is no enum type involved: why should users care about __hash_enum not
being constructible if they're not trying to hash enums?

This change makes the std::hash primary template only derive from
__hash_enum when the template argument type is an enum. Otherwise, it
derives directly from a new class template, __hash_not_enabled. This new
class template defines the deleted members that cause a given std::hash
specialization to be a disabled specialization (as per P0513R0). Now
when users try to use a disabled specialization, they get more
descriptive errors that mention __hash_not_enabled instead of
__hash_enum.

Additionally, adjust __hash_base to remove the deprecated result_type
and argument_type typedefs for C++20 and later.

In the current code we use a __poison_hash base class in the std::hash
specializations for std::unique_ptr, std::optional, and std::variant.
The primary template of __poison_hash has deleted special members, which
is used to conditionally disable the derived std::hash specialization.
This can also result in confusing diagnostics, because seeing "poison"
in an enabled specialization is misleading. Only some uses of
__poison_hash actually "poison" anything, i.e. cause a specialization to
be disabled. In other cases it's just an empty base class that does
nothing.

This change removes __poison_hash and changes the std::hash
specializations that were using it to conditionally derive from
__hash_not_enabled instead. When the std::hash specialization is
enabled, there is no more __poison_hash base class. However, to preserve
the ABI properties of those std::hash specializations, we need to
replace __poison_hash with some other empty base class. This is needed
because in the current code std::hash<std::variant<int, const int>> has
two __poison_hash<int> base classes, which must have unique addresses,
so sizeof(std::hash<std::variant<int, const int>>) == 2. To preserve
this unfortunate property, a new __hash_empty_base class is used as a
base class to re-introduce du0plicate base classes that increase the
class size. For the unstable ABI we don't use __hash_empty_base so the
std::hash<std::variant<T...>> specializations are always size 1, and
the class hierarchy is much simpler so will compile faster.

Additionally, remove the result_type and argument_type typedefs from all
disabled specializations of std::hash for std::unique_ptr,
std::optional, and std::variant. Those typedefs are useless for disabled
specializations, and although the standard doesn't say they must *not*
be present for disabled specializations, it certainly only requires them
for enabled specializations. Finally, for C++20 the typedefs are also
removed from enabled specializations of std::hash for std::unique_ptr,
std::optional, and std::variant.

libstdc++-v3/ChangeLog:

	* doc/xml/manual/evolution.xml: Document removal of nested types
	from std::hash specializations.
	* doc/html/manual/api.html: Regenerate.
	* include/bits/functional_hash.h (__hash_base): Remove
	deprecated nested types for C++20.
	(__hash_empty_base): Define new class template.
	(__is_hash_enabled_for): Define new variable template.
	(__poison_hash): Remove.
	(__hash_not_enabled): Define new class template.
	(__hash_enum): Remove partial specialization for non-enums.
	(hash): Derive from __hash_not_enabled for non-enums, instead of
	__hash_enum.
	* include/bits/unique_ptr.h (__uniq_ptr_hash): Derive from
	__hash_base. Conditionally derive from __hash_empty_base.
	(__uniq_ptr_hash<>): Remove disabled specialization.
	(hash): Do not derive from __hash_base unconditionally.
	Conditionally derive from either __uniq_ptr_hash or
	__hash_not_enabled.
	* include/std/optional (__optional_hash_call_base): Remove.
	(__optional_hash): Define new class template.
	(hash): Derive from either
	(hash): Conditionally derive from either __optional_hash or
	__hash_not_enabled. Remove nested typedefs.
	* include/std/variant (_Base_dedup): Replace __poison_hash with
	__hash_empty_base.
	(__variant_hash_call_base_impl): Remove.
	(__variant_hash): Define new class template.
	(hash): Conditionally derive from either __variant_hash or
	__hash_not_enabled. Remove nested typedefs.
	* testsuite/20_util/optional/hash.cc: Check whether nested types
	are present.
	* testsuite/20_util/variant/hash.cc: Likewise.
	* testsuite/20_util/optional/hash_abi.cc: New test.
	* testsuite/20_util/unique_ptr/hash/abi.cc: New test.
	* testsuite/20_util/unique_ptr/hash/types.cc: New test.
	* testsuite/20_util/variant/hash_abi.cc: New test.
2024-11-13 20:21:41 +00:00
.forgejo top-level: Add pull request template for Forgejo 2024-10-23 19:45:09 +01:00
.github
INSTALL
c++tools
config
contrib Daily bump. 2024-11-09 16:03:14 +00:00
fixincludes
gcc aarch64: Relax add_overloaded_function assert 2024-11-13 17:21:35 +00:00
gnattools
gotools
include Daily bump. 2024-11-02 00:19:21 +00:00
libada
libatomic
libbacktrace Daily bump. 2024-10-26 00:19:39 +00:00
libcc1
libcody
libcpp c: Handle C23 floating constant {d,D}{32,64,128} suffixes like {df,dd,dl} 2024-11-13 09:44:20 +01:00
libdecnumber
libffi Daily bump. 2024-10-26 00:19:39 +00:00
libgcc Daily bump. 2024-10-26 00:19:39 +00:00
libgfortran Daily bump. 2024-10-08 00:19:04 +00:00
libgm2
libgo syscall: don't define syscall stub on Hurd 2024-10-30 11:33:07 -07:00
libgomp Daily bump. 2024-11-12 00:19:15 +00:00
libgrust
libiberty Daily bump. 2024-11-02 00:19:21 +00:00
libitm
libobjc
libphobos
libquadmath
libsanitizer libsanitizer: Update LOCAL_PATCHES 2024-11-12 21:59:49 +08:00
libssp
libstdc++-v3 libstdc++: Refactor std::hash specializations 2024-11-13 20:21:41 +00:00
libvtv
lto-plugin
maintainer-scripts
zlib
.b4-config
.dir-locals.el
.gitattributes
.gitignore
ABOUT-NLS
COPYING
COPYING.LIB
COPYING.RUNTIME
COPYING3
COPYING3.LIB
ChangeLog Daily bump. 2024-11-06 00:18:35 +00:00
ChangeLog.jit
ChangeLog.tree-ssa
MAINTAINERS [MAINTAINERS] Add myself to write after approval and DCO. 2024-10-30 14:31:09 +05:30
Makefile.def
Makefile.in
Makefile.tpl
README
SECURITY.txt
ar-lib
compile
config-ml.in
config.guess
config.rpath
config.sub
configure Deprecate the ARM simulator 2024-11-05 13:12:07 +00:00
configure.ac Deprecate the ARM simulator 2024-11-05 13:12:07 +00:00
depcomp
install-sh
libtool-ldflags
libtool.m4
ltgcc.m4
ltmain.sh ltmain.sh: allow more flags at link-time 2024-09-25 19:05:24 +01:00
ltoptions.m4
ltsugar.m4
ltversion.m4
lt~obsolete.m4
missing
mkdep
mkinstalldirs
move-if-change
multilib.am
symlink-tree
test-driver
ylwrap

README

This directory contains the GNU Compiler Collection (GCC).

The GNU Compiler Collection is free software.  See the files whose
names start with COPYING for copying permission.  The manuals, and
some of the runtime libraries, are under different terms; see the
individual source files for details.

The directory INSTALL contains copies of the installation information
as HTML and plain text.  The source of this information is
gcc/doc/install.texi.  The installation information includes details
of what is included in the GCC sources and what files GCC installs.

See the file gcc/doc/gcc.texi (together with other files that it
includes) for usage and porting information.  An online readable
version of the manual is in the files gcc/doc/gcc.info*.

See http://gcc.gnu.org/bugs/ for how to report bugs usefully.

Copyright years on GCC source files may be listed using range
notation, e.g., 1987-2012, indicating that every year in the range,
inclusive, is a copyrightable year that could otherwise be listed
individually.