Created attachment 64365 [details] reflection flag patch Hi, I've been experimenting with GCC 16 testing its reflection implementation by compiling some code I had written targeting the pre standardization implementation for reflection (tested on the clang compiler available at the time). Unfortunately by enabling the reflection features (-std=c++26 - freflection), the compile times for my project plummet, it goes from compiling in 40 seconds to compiling in 17 minutes (with non parallel builds). These times were taken by building with GCC 16 packaged by Arch linux But I have the same slow build times even with other distributions of GCC 16. The project in question is https://github.com/edo9300/ygopro-core, it uses premake5 to compile (and the extra flags can be added by applying the attached patch). This is the build config of the GCC 16 shipped by Arch linux Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: /build/gcc/src/gcc/configure --enable-languages=ada,c,c++,d,fortran,go,lto,m2,objc,obj-c++,rust,cobol --enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://gitlab.archlinux.org/archlinux/packaging/packages/gcc/-/issues --with-build-config=bootstrap-lto --with-linker-hash-style=gnu --with-system-zlib --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-libstdcxx-backtrace --enable-link-serialization=1 --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-werror --disable-fixincludes Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 16.1.1 20260430 (GCC)
Please upload preprocessed source + g++ command line where it makes most significant compile time difference.
(In reply to Jakub Jelinek from comment #1) > Please upload preprocessed source + g++ command line where it makes most > significant compile time difference. All the files are heavily affected by this slowdown, but I'll attach one of bigger ones that itself goes from 1 second to 4 minutes compile time. The command lines for c++17 building is g++ -MD -MP -O0 -fPIC -g -fvisibility=hidden -Wall -Wextra -std=c++17 -fno-rtti -Wno-unused-parameter -o "./preprocessed.o" -c "./preprocessed.cpp" While for reflection is g++ -MD -MP -O0 -fPIC -g -fvisibility=hidden -Wall -Wextra -std=c++26 -freflection -fno-rtti -Wno-unused-parameter -o "./preprocessed.o" -c "./preprocessed.cpp"
Created attachment 64366 [details] preprocessed source compressed for size
perf record --call-graph=lbr shows: Children Self Command Shared Object Symbol + 97.33% 90.69% cc1plus cc1plus [.] consteval_only_type_r(tree_node**, int*, void*) ◆ + 94.71% 4.64% cc1plus cc1plus [.] walk_tree_1(tree_node**, tree_node* (*)(tree_node**, int*, void*), void*, hash_set<tree_node*, false, default_hash_traits<tree_node*> >*, tree_node* (*)(tr▒ + 19.94% 0.19% cc1plus cc1plus [.] walk_type_fields(tree_node*, tree_node* (*)(tree_node**, int*, void*), void*, hash_set<tree_node*, false, default_hash_traits<tree_node*> >*, tree_node* (*▒ + 8.37% 0.02% cc1plus cc1plus [.] consteval_only_p(tree_node*) ▒ + 7.72% 0.03% cc1plus cc1plus [.] check_out_of_consteval_use_r(tree_node**, int*, void*) ▒ + 1.91% 1.66% cc1plus cc1plus [.] hash_table<default_hash_traits<tree_node*>, false, xcallocator>::expand() ▒ + 0.83% 0.01% cc1plus cc1plus [.] cp_parser_statement(cp_parser*, tree_node*, bool, bool*, vec<tree_node*, va_heap, vl_ptr>*, unsigned long*) ▒ + 0.70% 0.00% cc1plus cc1plus [.] cp_parser_statement_seq_opt(cp_parser*, tree_node*) ▒ + 0.59% 0.01% cc1plus cc1plus [.] instantiate_class_template(tree_node*) ▒ So consteval_only_p is the culprit, like in PR124925
Testing a patch to memoize consteval_only_p via an auxiliary hash table.
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>: https://gcc.gnu.org/g:c8498d405a5abb276caa06f6a8952aa26637f1db commit r17-346-gc8498d405a5abb276caa06f6a8952aa26637f1db Author: Patrick Palka <ppalka@redhat.com> Date: Tue May 5 20:30:50 2026 -0400 c++/reflection: rewrite and memoize consteval_only_p [PR125179] The TU from this PR exhibits a 40x compile-time slowdown with -freflection vs without, all due to consteval_only_p which happens to be quite slow on large intertwined classes due to its recursive walking of TYPE_FIELDS. This patch firstly rewrites the predicate to use direct recursion instead of cp_walk_tree so that it's easier to reason about and more closely mirrors its standard definition at [basic.types.general]/12. This patch also makes the recursive part of the predicate tri-state, where the third 'unknown' state corresponds to seeing an incomplete class type whose consteval-only-ness we don't yet know. Finally this patch caches the result of the predicate for class types when the result is known. When the result is unknown (due to an incomplete constituent type) then we don't cache so that a subsequent call to the predicate can try again. With this patch compile time for said TU is now 1.1x with -freflection instead of 40x. PR c++/125179 gcc/cp/ChangeLog: * reflect.cc: (consteval_only_type_r): Remove this cp_walk_tree callback and replace with ... (consteval_only_walker): ... this recursive memoized implementation. (consteval_only_p): Define in terms of consteval_only_walker. Reviewed-by: Jakub Jelinek <jakub@redhat.com> Reviewed-by: Jason Merrill <jason@redhat.com>
Fixed on trunk so far.
The releases/gcc-16 branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>: https://gcc.gnu.org/g:64da98bd33730cb961f5543a9eed2cc160d0f387 commit r16-8877-g64da98bd33730cb961f5543a9eed2cc160d0f387 Author: Patrick Palka <ppalka@redhat.com> Date: Tue May 5 20:30:50 2026 -0400 c++/reflection: rewrite and memoize consteval_only_p [PR125179] The TU from this PR exhibits a 40x compile-time slowdown with -freflection vs without, all due to consteval_only_p which happens to be quite slow on large intertwined classes due to its recursive walking of TYPE_FIELDS. This patch firstly rewrites the predicate to use direct recursion instead of cp_walk_tree so that it's easier to reason about and more closely mirrors its standard definition at [basic.types.general]/12. This patch also makes the recursive part of the predicate tri-state, where the third 'unknown' state corresponds to seeing an incomplete class type whose consteval-only-ness we don't yet know. Finally this patch caches the result of the predicate for class types when the result is known. When the result is unknown (due to an incomplete constituent type) then we don't cache so that a subsequent call to the predicate can try again. With this patch compile time for said TU is now 1.1x with -freflection instead of 40x. PR c++/125179 gcc/cp/ChangeLog: * reflect.cc: (consteval_only_type_r): Remove this cp_walk_tree callback and replace with ... (consteval_only_walker): ... this recursive memoized implementation. (consteval_only_p): Define in terms of consteval_only_walker. Reviewed-by: Jakub Jelinek <jakub@redhat.com> Reviewed-by: Jason Merrill <jason@redhat.com> (cherry picked from commit c8498d405a5abb276caa06f6a8952aa26637f1db)
Fixed for GCC 16.2
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:54ddb5ff8b91bf518e69ed9221ed4530e7ad55af commit r17-522-g54ddb5ff8b91bf518e69ed9221ed4530e7ad55af Author: Jakub Jelinek <jakub@redhat.com> Date: Fri May 15 08:54:42 2026 +0200 testsuite: Add testcase for consteval-only type [PR125179] The following testcase tests that the consteval-only computation is not quadratic. With a loop of 50000 types, I believe this would be O(50000^2) in the earlier implementation and so would timeout. 2026-05-15 Jakub Jelinek <jakub@redhat.com> PR c++/125179 * g++.dg/reflect/pr125179.C: New test.