--- /dev/null
+--- a/lib/search.in.h
++++ b/lib/search.in.h
+@@ -112,6 +112,11 @@ _GL_CXXALIASWARN (lsearch);
+ # define twalk rpl_twalk
+ # endif
+ # endif
++# if @REPLACE_TDESTROY@
++# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++# define tdestroy rpl_tdestroy
++# endif
++# endif
+
+ /* See <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/search.h.html>
+ <https://pubs.opengroup.org/onlinepubs/9699919799/functions/tsearch.html>
+@@ -137,6 +142,7 @@ extern "C" {
+ # if !GNULIB_defined_search_fn_types
+ typedef int (*_gl_search_compar_fn) (const void *, const void *);
+ typedef void (*_gl_search_action_fn) (const void *, VISIT, int);
++typedef void (*_gl_search_free_fn) (void *);
+ # define GNULIB_defined_search_fn_types 1
+ # endif
+ # ifdef __cplusplus
+@@ -252,9 +258,36 @@ _GL_CXXALIAS_SYS (twalk, void,
+ _GL_CXXALIASWARN (twalk);
+ # endif
+
++/* Removes the whole tree pointed to by root,
++ freeing all resources allocated by the tsearch() function.
++ The FREE_NODE function is called:
++ - For the data in each tree node.
++ - Even when no such work is necessary, to a function doing nothing
++ The arguments passed to FREE_NODE are:
++ 1. The pointer to the data. */
++# if @REPLACE_TDESTROY@
++_GL_FUNCDECL_RPL (tdestroy, void,
++ (void *vroot, _gl_search_free_fn freefct)
++ _GL_ARG_NONNULL ((2)));
++_GL_CXXALIAS_RPL (tdestroy, void,
++ (void *vroot, _gl_search_free_fn freefct));
++# else
++# if !@HAVE_TDESTROY@
++_GL_FUNCDECL_SYS (tdestroy, void,
++ (void *vroot, _gl_search_free_fn freefct)
++ _GL_ARG_NONNULL ((2)));
++# endif
++_GL_CXXALIAS_SYS (tdestroy, void,
++ (void *vroot, _gl_search_free_fn freefct));
++# endif
++# if __GLIBC__ >= 2
++_GL_CXXALIASWARN (tdestroy);
++# endif
++
+ /* Flags used by tsearch.c. */
+ # define GNULIB_defined_tsearch (@REPLACE_TSEARCH@ || !@HAVE_TSEARCH@)
+ # define GNULIB_defined_twalk (@REPLACE_TWALK@ || !@HAVE_TWALK@)
++# define GNULIB_defined_tdestroy (@REPLACE_TDESTROY@ || !@HAVE_TDESTROY@)
+
+ #elif defined GNULIB_POSIXCHECK
+ # undef tsearch
+@@ -277,6 +310,11 @@ _GL_WARN_ON_USE (tdelete, "tdelete is un
+ _GL_WARN_ON_USE (twalk, "twalk is unportable - "
+ "use gnulib module tsearch for portability");
+ # endif
++# undef tdestroy
++# if HAVE_RAW_DECL_TDESTROY
++_GL_WARN_ON_USE (tdestroy, "tdestroy is unportable - "
++ "use gnulib module tsearch for portability");
++# endif
+ #endif
+
+
+--- a/lib/tsearch.c
++++ b/lib/tsearch.c
+@@ -98,12 +98,14 @@
+
+ typedef int (*__compar_fn_t) (const void *, const void *);
+ typedef void (*__action_fn_t) (const void *, VISIT, int);
++typedef void (*__free_fn_t) (void *);
+
+ #ifndef weak_alias
+ # define __tsearch tsearch
+ # define __tfind tfind
+ # define __tdelete tdelete
+ # define __twalk twalk
++# define __tdestroy tdestroy
+ #endif
+
+ #ifndef internal_function
+@@ -656,7 +658,7 @@ weak_alias (__twalk, twalk)
+ #endif /* GNULIB_defined_twalk */
+
+
+-#ifdef _LIBC
++#if defined(_LIBC) || GNULIB_defined_tdestroy
+
+ /* The standardized functions miss an important functionality: the
+ tree cannot be removed easily. We provide a function to do this. */
+@@ -683,6 +685,8 @@ __tdestroy (void *vroot, __free_fn_t fre
+ if (root != NULL)
+ tdestroy_recurse (root, freefct);
+ }
++#ifdef weak_alias
+ weak_alias (__tdestroy, tdestroy)
++#endif
+
+-#endif /* _LIBC */
++#endif /* defined(_LIBC) || GNULIB_defined_tdestroy */
+--- a/m4/search_h.m4
++++ b/m4/search_h.m4
+@@ -39,7 +39,7 @@ AC_DEFUN_ONCE([gl_SEARCH_H],
+ dnl Check for declarations of anything we want to poison if the
+ dnl corresponding gnulib module is not in use.
+ gl_WARN_ON_USE_PREPARE([[#include <search.h>
+- ]], [tdelete tfind tsearch twalk])
++ ]], [tdelete tfind tsearch twalk tdestroy])
+
+ AC_REQUIRE([AC_C_RESTRICT])
+ ])
+@@ -75,8 +75,10 @@ AC_DEFUN([gl_SEARCH_H_DEFAULTS],
+ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_LFIND], [1])
+ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_LSEARCH], [1])
+ dnl Assume proper GNU behavior unless another module says otherwise.
+- HAVE_TSEARCH=1; AC_SUBST([HAVE_TSEARCH])
+- HAVE_TWALK=1; AC_SUBST([HAVE_TWALK])
+- REPLACE_TSEARCH=0; AC_SUBST([REPLACE_TSEARCH])
+- REPLACE_TWALK=0; AC_SUBST([REPLACE_TWALK])
++ HAVE_TSEARCH=1; AC_SUBST([HAVE_TSEARCH])
++ HAVE_TWALK=1; AC_SUBST([HAVE_TWALK])
++ HAVE_TDESTROY=1; AC_SUBST([HAVE_TDESTROY])
++ REPLACE_TSEARCH=0; AC_SUBST([REPLACE_TSEARCH])
++ REPLACE_TWALK=0; AC_SUBST([REPLACE_TWALK])
++ REPLACE_TDESTROY=0; AC_SUBST([REPLACE_TDESTROY])
+ ])
+--- a/m4/tsearch.m4
++++ b/m4/tsearch.m4
+@@ -9,6 +9,7 @@ AC_DEFUN([gl_FUNC_TSEARCH],
+ AC_REQUIRE([gl_SEARCH_H_DEFAULTS])
+ gl_CHECK_FUNCS_ANDROID([tsearch], [[#include <search.h>]])
+ gl_CHECK_FUNCS_ANDROID([twalk], [[#include <search.h>]])
++ gl_CHECK_FUNCS_ANDROID([tdestroy], [[#include <search.h>]])
+ if test $ac_cv_func_tsearch = yes; then
+ dnl On OpenBSD 4.0, the return value of tdelete() is incorrect.
+ AC_REQUIRE([AC_PROG_CC])
+@@ -50,6 +51,7 @@ main ()
+ *no)
+ REPLACE_TSEARCH=1
+ REPLACE_TWALK=1
++ REPLACE_TDESTROY=1
+ ;;
+ esac
+ else
+@@ -64,6 +66,12 @@ main ()
+ future*) REPLACE_TWALK=1 ;;
+ esac
+ fi
++ if test $ac_cv_func_tdestroy != yes; then
++ HAVE_TDESTROY=0
++ case "$gl_cv_onwards_func_tdestroy" in
++ future*) REPLACE_TDESTROY=1 ;;
++ esac
++ fi
+ ])
+
+ # Prerequisites of lib/tsearch.c.
+--- a/modules/search
++++ b/modules/search
+@@ -37,8 +37,10 @@ search.h: search.in.h $(top_builddir)/co
+ -e 's/@''GNULIB_MDA_LSEARCH''@/$(GNULIB_MDA_LSEARCH)/g' \
+ -e 's|@''HAVE_TSEARCH''@|$(HAVE_TSEARCH)|g' \
+ -e 's|@''HAVE_TWALK''@|$(HAVE_TWALK)|g' \
++ -e 's|@''HAVE_TDESTROY''@|$(HAVE_TDESTROY)|g' \
+ -e 's|@''REPLACE_TSEARCH''@|$(REPLACE_TSEARCH)|g' \
+ -e 's|@''REPLACE_TWALK''@|$(REPLACE_TWALK)|g' \
++ -e 's|@''REPLACE_TDESTROY''@|$(REPLACE_TDESTROY)|g' \
+ -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
+ -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
+ -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
+--- a/modules/tsearch
++++ b/modules/tsearch
+@@ -11,7 +11,12 @@ search
+ configure.ac:
+ gl_FUNC_TSEARCH
+ gl_CONDITIONAL([GL_COND_OBJ_TSEARCH],
+- [test $HAVE_TSEARCH = 0 || test $HAVE_TWALK = 0 || test $REPLACE_TSEARCH = 1 || test $REPLACE_TWALK = 1])
++ [test $HAVE_TSEARCH = 0 ||
++ test $HAVE_TWALK = 0 ||
++ test $HAVE_TDESTROY = 0 ||
++ test $REPLACE_TSEARCH = 1 ||
++ test $REPLACE_TWALK = 1 ||
++ test $REPLACE_TDESTROY = 1])
+ AM_COND_IF([GL_COND_OBJ_TSEARCH], [
+ gl_PREREQ_TSEARCH
+ ])