Bug 125179 - extremely slow build times with -freflection flag
Summary: extremely slow build times with -freflection flag
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 16.1.1
: P3 normal
Target Milestone: 16.2
Assignee: Patrick Palka
URL:
Keywords: compile-time-hog
Depends on:
Blocks: c++-reflection
  Show dependency tree / graph
 
Reported: 2026-05-04 13:23 UTC by Edoardo Lolletti
Modified: 2026-05-15 06:56 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2026-05-04 00:00:00


Attachments
reflection flag patch (251 bytes, patch)
2026-05-04 13:23 UTC, Edoardo Lolletti
Details | Diff
preprocessed source (322.43 KB, application/gzip)
2026-05-04 13:47 UTC, Edoardo Lolletti
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Edoardo Lolletti 2026-05-04 13:23:27 UTC
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)
Comment 1 Jakub Jelinek 2026-05-04 13:31:43 UTC
Please upload preprocessed source + g++ command line where it makes most significant compile time difference.
Comment 2 Edoardo Lolletti 2026-05-04 13:46:10 UTC
(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"
Comment 3 Edoardo Lolletti 2026-05-04 13:47:51 UTC
Created attachment 64366 [details]
preprocessed source

compressed for size
Comment 4 Patrick Palka 2026-05-04 13:52:08 UTC
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
Comment 5 Patrick Palka 2026-05-04 14:29:11 UTC
Testing a patch to memoize consteval_only_p via an auxiliary hash table.
Comment 6 GCC Commits 2026-05-06 00:31:12 UTC
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>
Comment 7 Patrick Palka 2026-05-06 00:31:50 UTC
Fixed on trunk so far.
Comment 8 GCC Commits 2026-05-06 22:29:23 UTC
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)
Comment 9 Patrick Palka 2026-05-06 22:30:00 UTC
Fixed for GCC 16.2
Comment 10 GCC Commits 2026-05-15 06:56:04 UTC
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.