--- 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
@@ -41,7 +41,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])
 ])
@@ -77,8 +77,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
@@ -11,6 +11,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])
@@ -52,6 +53,7 @@ main ()
       *no)
         REPLACE_TSEARCH=1
         REPLACE_TWALK=1
+        REPLACE_TDESTROY=1
         ;;
     esac
   else
@@ -66,6 +68,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-h
+++ b/modules/search-h
@@ -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-h
 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
 ])
