libstdc++: Plugin to dump possibly needed missing exports
Jakub Jelinek
jakub@redhat.com
Mon Aug 4 08:58:21 GMT 2025
On Sun, Aug 03, 2025 at 02:50:28PM +0200, Jonathan Wakely wrote:
> > Wonder how to automatically discover other missing exports (like in
> > PR121373
> > std::byteswap), maybe one could dig that stuff somehow from the raw
> > dump (look for identifiers in std namespace (and perhaps inlined namespaces
> > thereof at least) which don't start with underscore.
To answer that question, I wrote a simple plugin which just dumps the names
(which do not start with underscore) in std namespace (and its inlined
namespaces) and for non-inline namespaces in there which do not start with
underscore also recurses on those namespaces.
/home/jakub/src/gcc/obj98/gcc/xg++ -B/home/jakub/src/gcc/obj98/gcc/ -B/usr/local/x86_64-pc-linux-gnu/bin/ -nostdinc++ -B/home/jakub/src/gcc/obj98/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs -B/home/jakub/src/gcc/obj98/x86_64-pc-linux-gnu/libstdc++-v3/libsupc++/.libs -I/home/jakub/src/gcc/obj98/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu -I/home/jakub/src/gcc/obj98/x86_64-pc-linux-gnu/libstdc++-v3/include -I/home/jakub/src/gcc/libstdc++-v3/libsupc++ -L/home/jakub/src/gcc/obj98/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs -L/home/jakub/src/gcc/obj98/x86_64-pc-linux-gnu/libstdc++-v3/libsupc++/.libs -g -O2 -fchecking=1 /tmp/std_plugin.cc -I. -I/home/jakub/src/gcc/gcc/testsuite -I/home/jakub/src/gcc/gcc -I/home/jakub/src/gcc/obj98/gcc -I/home/jakub/src/gcc/include -I/home/jakub/src/gcc/libcpp/include -I/home/jakub/src/gcc/obj98/gettext/intl -DIN_GCC -fPIC -shared -fno-rtti -o std_plugin.so
/home/jakub/src/gcc/obj98/gcc/cc1plus -quiet -nostdinc++ -v -I /home/jakub/src/gcc/obj98/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu -I /home/jakub/src/gcc/obj98/x86_64-pc-linux-gnu/libstdc++-v3/include -I /home/jakub/src/gcc/libstdc++-v3/libsupc++ -I /home/jakub/src/gcc/libstdc++-v3/include/backward -I /home/jakub/src/gcc/libstdc++-v3/testsuite/util -iprefix /home/jakub/src/gcc/obj98/gcc/../lib/gcc/x86_64-pc-linux-gnu/16.0.0/ -isystem /home/jakub/src/gcc/obj98/gcc/include -isystem /home/jakub/src/gcc/obj98/gcc/include-fixed -iplugindir=/home/jakub/src/gcc/obj98/gcc/plugin -D_GNU_SOURCE /tmp/std_test.cc -iplugindir=/home/jakub/src/gcc/obj98/gcc/plugin -quiet -dumpbase std_test.cc -dumpbase-ext .cc -mtune=generic -march=x86-64 -O -std=c++20 -version -fdiagnostics-color=never -fdiagnostics-urls=never -fno-diagnostics-show-caret -fno-diagnostics-show-line-numbers -fdiagnostics-path-format=separate-events -fdiagnostics-text-art-charset=none -fno-diagnostics-show-event-links -fmessage-length=0 -fplugin=./std_plugin.so -o std_test.s 2>&1 | sed -n 's/^cc1plus: note: //p' | sort -u | while read i; do fgrep -q "$i" *.in || echo $i; done
Repeated for -std=c++20, -std=c++23, -std=c++26, I get following missing
cases. Sure, the list contains known stuff that has been removed from
C++17, C++20 etc., so I think it needs manual inspection what to include and
what not (or file with using directives for stuff that has been removed to
serve as a black list, yes, I know this has been removed from newer
standards and doesn't need to be exported from the std modules).
Jakub
-------------- next part --------------
#include "gcc-plugin.h"
#include <stdlib.h>
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "intl.h"
#include "cp/cp-tree.h"
#include "diagnostic.h"
int plugin_is_GPL_compatible;
#define STAT_HACK_P(N) ((N) && TREE_CODE (N) == OVERLOAD && OVL_LOOKUP_P (N))
#define STAT_TYPE_VISIBLE_P(N) TREE_USED (OVERLOAD_CHECK (N))
#define STAT_TYPE(N) TREE_TYPE (N)
#define STAT_DECL(N) OVL_FUNCTION (N)
#define STAT_TYPE_HIDDEN_P(N) OVL_HIDDEN_P (N)
#define STAT_DECL_HIDDEN_P(N) OVL_DEDUP_P (N)
void plugin_dump_ns (tree, char *);
void
plugin_dump_decl (tree decl, char *scope)
{
if (VAR_P (decl) && DECL_ARTIFICIAL (decl))
return;
tree name = DECL_NAME (decl);
if (!name)
return;
if (IDENTIFIER_ANON_P (name))
return;
if (TREE_CODE (decl) == CONST_DECL)
return;
if (TREE_CODE (decl) == NAMESPACE_DECL && DECL_NAMESPACE_INLINE_P (decl))
{
plugin_dump_ns (decl, scope);
return;
}
if (IDENTIFIER_POINTER (name)[0] == '_'
|| strchr (IDENTIFIER_POINTER (name), ' '))
return;
if (TREE_CODE (decl) == NAMESPACE_DECL)
{
char *p = strchr (scope, '\0');
strcpy (p, IDENTIFIER_POINTER (name));
strcat (p, "::");
plugin_dump_ns (decl, scope);
*p = '\0';
return;
}
inform (UNKNOWN_LOCATION, "%s%D;", scope, name);
}
void
plugin_dump_binding (tree binding, char *scope)
{
tree value = NULL_TREE;
if (STAT_HACK_P (binding))
{
if (!STAT_TYPE_HIDDEN_P (binding)
&& STAT_TYPE (binding))
return plugin_dump_decl (STAT_TYPE (binding), scope);
else if (!STAT_DECL_HIDDEN_P (binding))
value = STAT_DECL (binding);
}
else
value = binding;
value = ovl_skip_hidden (value);
if (value)
{
value = OVL_FIRST (value);
return plugin_dump_decl (value, scope);
}
}
void
plugin_dump_ns (tree ns, char *scope)
{
using itert = hash_table<named_decl_hash>::iterator;
itert end (DECL_NAMESPACE_BINDINGS (ns)->end ());
for (itert iter (DECL_NAMESPACE_BINDINGS (ns)->begin ());
iter != end; ++iter)
{
tree b = *iter;
gcc_assert (TREE_CODE (b) != BINDING_VECTOR);
plugin_dump_binding (b, scope);
}
}
void
plugin_finish_unit (void *, void *)
{
char buf[4096];
strcpy (buf, "using std::");
plugin_dump_ns (std_node, buf);
}
int
plugin_init (struct plugin_name_args *plugin_info,
struct plugin_gcc_version *version)
{
const char *plugin_name = plugin_info->base_name;
register_callback (plugin_name, PLUGIN_FINISH_UNIT,
plugin_finish_unit, NULL);
return 0;
}
-------------- next part --------------
#include <bits/stdc++.h>
-------------- next part --------------
using std::auto_ptr;
using std::auto_ptr_ref;
using std::binary_function;
using std::binary_negate;
using std::bind1st;
using std::bind2nd;
using std::binder1st;
using std::binder2nd;
using std::chrono::ambiguous_local_time;
using std::chrono::choose;
using std::chrono::clock_cast;
using std::chrono::clock_time_conversion;
using std::chrono::current_zone;
using std::chrono::from_stream;
using std::chrono::get_leap_second_info;
using std::chrono::get_tzdb;
using std::chrono::get_tzdb_list;
using std::chrono::gps_clock;
using std::chrono::gps_seconds;
using std::chrono::gps_time;
using std::chrono::is_clock;
using std::chrono::is_clock_v;
using std::chrono::leap_second;
using std::chrono::leap_second_info;
using std::chrono::local_info;
using std::chrono::local_time_format;
using std::chrono::locate_zone;
using std::chrono::nonexistent_local_time;
using std::chrono::parse;
using std::chrono::reload_tzdb;
using std::chrono::remote_version;
using std::chrono::sys_info;
using std::chrono::tai_clock;
using std::chrono::tai_seconds;
using std::chrono::tai_time;
using std::chrono::time_zone;
using std::chrono::time_zone_link;
using std::chrono::tzdb;
using std::chrono::tzdb_list;
using std::chrono::utc_clock;
using std::chrono::utc_seconds;
using std::chrono::utc_time;
using std::chrono::zoned_seconds;
using std::chrono::zoned_time;
using std::chrono::zoned_traits;
using std::const_mem_fun1_ref_t;
using std::const_mem_fun1_t;
using std::const_mem_fun_ref_t;
using std::const_mem_fun_t;
using std::declare_no_pointers;
using std::declare_reachable;
using std::get_pointer_safety;
using std::get_temporary_buffer;
using std::get_unexpected;
using std::is_literal_type;
using std::is_literal_type_v;
using std::mem_fun;
using std::mem_fun1_ref_t;
using std::mem_fun1_t;
using std::mem_fun_ref;
using std::mem_fun_ref_t;
using std::mem_fun_t;
using std::not1;
using std::not2;
using std::operator""d;
using std::operator""h;
using std::operator""min;
using std::operator""ms;
using std::operator""ns;
using std::operator""sv;
using std::operator""us;
using std::operator""y;
using std::pointer_safety;
using std::pointer_to_binary_function;
using std::pointer_to_unary_function;
using std::ptr_fun;
using std::random_shuffle;
using std::ranges::iter_move;
using std::ranges::iter_swap;
using std::raw_storage_iterator;
using std::regex_constants::awk;
using std::regex_constants::basic;
using std::regex_constants::collate;
using std::regex_constants::ECMAScript;
using std::regex_constants::egrep;
using std::regex_constants::error_backref;
using std::regex_constants::error_badbrace;
using std::regex_constants::error_badrepeat;
using std::regex_constants::error_brace;
using std::regex_constants::error_brack;
using std::regex_constants::error_collate;
using std::regex_constants::error_complexity;
using std::regex_constants::error_ctype;
using std::regex_constants::error_escape;
using std::regex_constants::error_paren;
using std::regex_constants::error_range;
using std::regex_constants::error_space;
using std::regex_constants::error_stack;
using std::regex_constants::extended;
using std::regex_constants::format_default;
using std::regex_constants::format_first_only;
using std::regex_constants::format_no_copy;
using std::regex_constants::format_sed;
using std::regex_constants::grep;
using std::regex_constants::icase;
using std::regex_constants::match_any;
using std::regex_constants::match_continuous;
using std::regex_constants::match_default;
using std::regex_constants::match_not_bol;
using std::regex_constants::match_not_bow;
using std::regex_constants::match_not_eol;
using std::regex_constants::match_not_eow;
using std::regex_constants::match_not_null;
using std::regex_constants::match_prev_avail;
using std::regex_constants::multiline;
using std::regex_constants::nosubs;
using std::regex_constants::optimize;
using std::result_of;
using std::result_of_t;
using std::return_temporary_buffer;
using std::set_unexpected;
using std::unary_function;
using std::unary_negate;
using std::undeclare_no_pointers;
using std::undeclare_reachable;
using std::unexpected_handler;
-------------- next part --------------
using std::auto_ptr;
using std::auto_ptr_ref;
using std::binary_function;
using std::binary_negate;
using std::bind1st;
using std::bind2nd;
using std::binder1st;
using std::binder2nd;
using std::byteswap;
using std::chrono::ambiguous_local_time;
using std::chrono::choose;
using std::chrono::clock_cast;
using std::chrono::clock_time_conversion;
using std::chrono::current_zone;
using std::chrono::from_stream;
using std::chrono::get_leap_second_info;
using std::chrono::get_tzdb;
using std::chrono::get_tzdb_list;
using std::chrono::gps_clock;
using std::chrono::gps_seconds;
using std::chrono::gps_time;
using std::chrono::is_clock;
using std::chrono::is_clock_v;
using std::chrono::leap_second;
using std::chrono::leap_second_info;
using std::chrono::local_info;
using std::chrono::local_time_format;
using std::chrono::locate_zone;
using std::chrono::nonexistent_local_time;
using std::chrono::parse;
using std::chrono::reload_tzdb;
using std::chrono::remote_version;
using std::chrono::sys_info;
using std::chrono::tai_clock;
using std::chrono::tai_seconds;
using std::chrono::tai_time;
using std::chrono::time_zone;
using std::chrono::time_zone_link;
using std::chrono::tzdb;
using std::chrono::tzdb_list;
using std::chrono::utc_clock;
using std::chrono::utc_seconds;
using std::chrono::utc_time;
using std::chrono::zoned_seconds;
using std::chrono::zoned_time;
using std::chrono::zoned_traits;
using std::const_mem_fun1_ref_t;
using std::const_mem_fun1_t;
using std::const_mem_fun_ref_t;
using std::const_mem_fun_t;
using std::get_temporary_buffer;
using std::inout_ptr_t;
using std::is_literal_type;
using std::is_literal_type_v;
using std::is_scoped_enum;
using std::is_scoped_enum_v;
using std::mem_fun;
using std::mem_fun1_ref_t;
using std::mem_fun1_t;
using std::mem_fun_ref;
using std::mem_fun_ref_t;
using std::mem_fun_t;
using std::not1;
using std::not2;
using std::operator""d;
using std::operator""h;
using std::operator""min;
using std::operator""ms;
using std::operator""ns;
using std::operator""sv;
using std::operator""us;
using std::operator""y;
using std::out_ptr_t;
using std::pmr::generator;
using std::pointer_to_binary_function;
using std::pointer_to_unary_function;
using std::ptr_fun;
using std::random_shuffle;
using std::ranges::adjacent_transform_view;
using std::ranges::adjacent_view;
using std::ranges::as_const_view;
using std::ranges::as_rvalue_view;
using std::ranges::cartesian_product_view;
using std::ranges::chunk_by_view;
using std::ranges::chunk_view;
using std::ranges::constant_range;
using std::ranges::const_iterator_t;
using std::ranges::const_sentinel_t;
using std::ranges::contains;
using std::ranges::contains_subrange;
using std::ranges::elements_of;
using std::ranges::ends_with;
using std::ranges::enumerate_view;
using std::ranges::find_last;
using std::ranges::find_last_if;
using std::ranges::find_last_if_not;
using std::ranges::fold_left;
using std::ranges::fold_left_first;
using std::ranges::fold_left_first_with_iter;
using std::ranges::fold_left_first_with_iter_result;
using std::ranges::fold_left_with_iter;
using std::ranges::fold_left_with_iter_result;
using std::ranges::fold_right;
using std::ranges::fold_right_last;
using std::ranges::in_value_result;
using std::ranges::iota;
using std::ranges::iota_result;
using std::ranges::iter_move;
using std::ranges::iter_swap;
using std::ranges::join_with_view;
using std::ranges::out_value_result;
using std::ranges::range_adaptor_closure;
using std::ranges::range_const_reference_t;
using std::ranges::repeat_view;
using std::ranges::slide_view;
using std::ranges::starts_with;
using std::ranges::stride_view;
using std::ranges::to;
using std::ranges::views::adjacent;
using std::ranges::views::adjacent_transform;
using std::ranges::views::as_const;
using std::ranges::views::as_rvalue;
using std::ranges::views::cartesian_product;
using std::ranges::views::chunk;
using std::ranges::views::chunk_by;
using std::ranges::views::enumerate;
using std::ranges::views::join_with;
using std::ranges::views::pairwise;
using std::ranges::views::pairwise_transform;
using std::ranges::views::repeat;
using std::ranges::views::slide;
using std::ranges::views::stride;
using std::ranges::views::zip;
using std::ranges::views::zip_transform;
using std::ranges::zip_transform_view;
using std::ranges::zip_view;
using std::raw_storage_iterator;
using std::regex_constants::awk;
using std::regex_constants::basic;
using std::regex_constants::collate;
using std::regex_constants::ECMAScript;
using std::regex_constants::egrep;
using std::regex_constants::error_backref;
using std::regex_constants::error_badbrace;
using std::regex_constants::error_badrepeat;
using std::regex_constants::error_brace;
using std::regex_constants::error_brack;
using std::regex_constants::error_collate;
using std::regex_constants::error_complexity;
using std::regex_constants::error_ctype;
using std::regex_constants::error_escape;
using std::regex_constants::error_paren;
using std::regex_constants::error_range;
using std::regex_constants::error_space;
using std::regex_constants::error_stack;
using std::regex_constants::extended;
using std::regex_constants::format_default;
using std::regex_constants::format_first_only;
using std::regex_constants::format_no_copy;
using std::regex_constants::format_sed;
using std::regex_constants::grep;
using std::regex_constants::icase;
using std::regex_constants::match_any;
using std::regex_constants::match_continuous;
using std::regex_constants::match_default;
using std::regex_constants::match_not_bol;
using std::regex_constants::match_not_bow;
using std::regex_constants::match_not_eol;
using std::regex_constants::match_not_eow;
using std::regex_constants::match_not_null;
using std::regex_constants::match_prev_avail;
using std::regex_constants::multiline;
using std::regex_constants::nosubs;
using std::regex_constants::optimize;
using std::result_of;
using std::result_of_t;
using std::return_temporary_buffer;
using std::unary_function;
using std::unary_negate;
-------------- next part --------------
using std::auto_ptr;
using std::auto_ptr_ref;
using std::binary_function;
using std::binary_negate;
using std::bind1st;
using std::bind2nd;
using std::binder1st;
using std::binder2nd;
using std::byteswap;
using std::chrono::ambiguous_local_time;
using std::chrono::choose;
using std::chrono::clock_cast;
using std::chrono::clock_time_conversion;
using std::chrono::current_zone;
using std::chrono::from_stream;
using std::chrono::get_leap_second_info;
using std::chrono::get_tzdb;
using std::chrono::get_tzdb_list;
using std::chrono::gps_clock;
using std::chrono::gps_seconds;
using std::chrono::gps_time;
using std::chrono::is_clock;
using std::chrono::is_clock_v;
using std::chrono::leap_second;
using std::chrono::leap_second_info;
using std::chrono::local_info;
using std::chrono::local_time_format;
using std::chrono::locate_zone;
using std::chrono::nonexistent_local_time;
using std::chrono::parse;
using std::chrono::reload_tzdb;
using std::chrono::remote_version;
using std::chrono::sys_info;
using std::chrono::tai_clock;
using std::chrono::tai_seconds;
using std::chrono::tai_time;
using std::chrono::time_zone;
using std::chrono::time_zone_link;
using std::chrono::tzdb;
using std::chrono::tzdb_list;
using std::chrono::utc_clock;
using std::chrono::utc_seconds;
using std::chrono::utc_time;
using std::chrono::zoned_seconds;
using std::chrono::zoned_time;
using std::chrono::zoned_traits;
using std::const_mem_fun1_ref_t;
using std::const_mem_fun1_t;
using std::const_mem_fun_ref_t;
using std::const_mem_fun_t;
using std::get_temporary_buffer;
using std::inout_ptr_t;
using std::is_literal_type;
using std::is_literal_type_v;
using std::is_scoped_enum;
using std::is_scoped_enum_v;
using std::mem_fun;
using std::mem_fun1_ref_t;
using std::mem_fun1_t;
using std::mem_fun_ref;
using std::mem_fun_ref_t;
using std::mem_fun_t;
using std::not1;
using std::not2;
using std::operator""d;
using std::operator""h;
using std::operator""min;
using std::operator""ms;
using std::operator""ns;
using std::operator""sv;
using std::operator""us;
using std::operator""y;
using std::out_ptr_t;
using std::pmr::generator;
using std::pointer_to_binary_function;
using std::pointer_to_unary_function;
using std::projected_value_t;
using std::ptr_fun;
using std::random_shuffle;
using std::ranges::adjacent_transform_view;
using std::ranges::adjacent_view;
using std::ranges::as_const_view;
using std::ranges::as_rvalue_view;
using std::ranges::cache_latest_view;
using std::ranges::cartesian_product_view;
using std::ranges::chunk_by_view;
using std::ranges::chunk_view;
using std::ranges::concat_view;
using std::ranges::constant_range;
using std::ranges::const_iterator_t;
using std::ranges::const_sentinel_t;
using std::ranges::contains;
using std::ranges::contains_subrange;
using std::ranges::elements_of;
using std::ranges::ends_with;
using std::ranges::enumerate_view;
using std::ranges::find_last;
using std::ranges::find_last_if;
using std::ranges::find_last_if_not;
using std::ranges::fold_left;
using std::ranges::fold_left_first;
using std::ranges::fold_left_first_with_iter;
using std::ranges::fold_left_first_with_iter_result;
using std::ranges::fold_left_with_iter;
using std::ranges::fold_left_with_iter_result;
using std::ranges::fold_right;
using std::ranges::fold_right_last;
using std::ranges::in_value_result;
using std::ranges::iota;
using std::ranges::iota_result;
using std::ranges::iter_move;
using std::ranges::iter_swap;
using std::ranges::join_with_view;
using std::ranges::out_value_result;
using std::ranges::range_adaptor_closure;
using std::ranges::range_const_reference_t;
using std::ranges::repeat_view;
using std::ranges::slide_view;
using std::ranges::starts_with;
using std::ranges::stride_view;
using std::ranges::to;
using std::ranges::to_input_view;
using std::ranges::views::adjacent;
using std::ranges::views::adjacent_transform;
using std::ranges::views::as_const;
using std::ranges::views::as_rvalue;
using std::ranges::views::cache_latest;
using std::ranges::views::cartesian_product;
using std::ranges::views::chunk;
using std::ranges::views::chunk_by;
using std::ranges::views::concat;
using std::ranges::views::enumerate;
using std::ranges::views::join_with;
using std::ranges::views::pairwise;
using std::ranges::views::pairwise_transform;
using std::ranges::views::repeat;
using std::ranges::views::slide;
using std::ranges::views::stride;
using std::ranges::views::to_input;
using std::ranges::views::zip;
using std::ranges::views::zip_transform;
using std::ranges::zip_transform_view;
using std::ranges::zip_view;
using std::raw_storage_iterator;
using std::regex_constants::awk;
using std::regex_constants::basic;
using std::regex_constants::collate;
using std::regex_constants::ECMAScript;
using std::regex_constants::egrep;
using std::regex_constants::error_backref;
using std::regex_constants::error_badbrace;
using std::regex_constants::error_badrepeat;
using std::regex_constants::error_brace;
using std::regex_constants::error_brack;
using std::regex_constants::error_collate;
using std::regex_constants::error_complexity;
using std::regex_constants::error_ctype;
using std::regex_constants::error_escape;
using std::regex_constants::error_paren;
using std::regex_constants::error_range;
using std::regex_constants::error_space;
using std::regex_constants::error_stack;
using std::regex_constants::extended;
using std::regex_constants::format_default;
using std::regex_constants::format_first_only;
using std::regex_constants::format_no_copy;
using std::regex_constants::format_sed;
using std::regex_constants::grep;
using std::regex_constants::icase;
using std::regex_constants::match_any;
using std::regex_constants::match_continuous;
using std::regex_constants::match_default;
using std::regex_constants::match_not_bol;
using std::regex_constants::match_not_bow;
using std::regex_constants::match_not_eol;
using std::regex_constants::match_not_eow;
using std::regex_constants::match_not_null;
using std::regex_constants::match_prev_avail;
using std::regex_constants::multiline;
using std::regex_constants::nosubs;
using std::regex_constants::optimize;
using std::result_of;
using std::result_of_t;
using std::return_temporary_buffer;
using std::unary_function;
using std::unary_negate;
More information about the Libstdc++
mailing list