From patchwork Tue May 5 01:25:06 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 134451 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id A4C614B9DB7C for ; Tue, 5 May 2026 01:26:05 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A4C614B9DB7C Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=GC+1ALfI X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id ABE464B9DB64 for ; Tue, 5 May 2026 01:25:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org ABE464B9DB64 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org ABE464B9DB64 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777944314; cv=none; b=xYjbZjmlguHQHxte9fI0jrClNPfA3kYqB6c/8bv7N8BgwoqgG+4ib2BScR16peB237veuXBE2zNIVJjCzrdlkVYbgnthNRVVELh8LH6EYN1OTmQTAMdAQU3Mf6XmiCRakF59Qs8iPGq32Sam8gzr9754P/+PbAyfWOxHUXbKKCo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777944314; c=relaxed/simple; bh=avSuZD9WbJSwLIbCIuGukeCsl33uEdE7VjQ11ug2lgg=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=kyfIlzPkPV2uMkavzw5LvgSlb5KLE63EqfKfOxf0i75UwNc6lx2CEwFvZiZNybKbZRONOAVdmY8O4xrznIqBssXvZZh9jrgl9h0CrtAUVa3+BPctZ642IvlCRetWU5RzzaTKcFK5pCS8b3ussxmKp0qSuhxcs1kFMgTJO4QBFy8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org ABE464B9DB64 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777944314; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=xEpf7z2mH/txvoGqeGNBD2HGjbVpRjeBZx2KL0hTw6I=; b=GC+1ALfI5D0ZU9GKQZnYWoYTlCrP2F3UvgMZ4/g2m4nE4pvuXdoDPV28auXdbqdyE5m/Fo cHZxODr8nktxD8MRwTbgSfwAhZgdGdPl3mWyQfBNhlDHC4tZnivjZTce/vYBiKvtQGeRw4 jEWutnWeTDqlxEFIjiOPtfUa8aiEMyU= Received: from mail-qk1-f197.google.com (mail-qk1-f197.google.com [209.85.222.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-124-IKRFE9riN-OKllab10UeGA-1; Mon, 04 May 2026 21:25:12 -0400 X-MC-Unique: IKRFE9riN-OKllab10UeGA-1 X-Mimecast-MFC-AGG-ID: IKRFE9riN-OKllab10UeGA_1777944312 Received: by mail-qk1-f197.google.com with SMTP id af79cd13be357-8d59968444aso108233085a.3 for ; Mon, 04 May 2026 18:25:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777944312; x=1778549112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=xEpf7z2mH/txvoGqeGNBD2HGjbVpRjeBZx2KL0hTw6I=; b=LU/et6SfsZKJQ0t5ruJtq7kQ5Xt0kwGAg/g4eLSSvUAmZd6ROSA5WNIWOwpwt6TG2s I3hhFkmWgI/CVJ+gf+krWaNmz/cT6Ms03+/wrcRUm/JqPAmxn4x74zlMAQPp9R6lO6ch 5p7c7NfgLQF7LpgKD8IUK3Qkt3/tIn81u3iRLtz9Zzi1IAq+hz+AUnR0O8pDS5IceD4Q VNpGHRq7Qd5/ZJ7eAtnBqGCc8arCT8Z4E0gwOkQ1MmxypXXLxjD6l9+kTAFRm20No9Bm SMADbx/rh9yPqqLzXHaCEFFv0CbMAq55f5XVfJfTBwstID1+0AhJ4wU3Mb9na3rFuRWK NkWQ== X-Gm-Message-State: AOJu0Yw7zXC+C4p3HRLyrK9/tVZ26fSYjg6IKkoW7YHG3awWNE6cf3Vm ODVWEpKSSyxT1gmDZtjR2+bJmvAqlmSX33SfD99GHcNGoUV1NB9wW3ucjG1adh7SXofdg516eOr v5/DYKRPKebOvWLBMmSfe1vrUv8btduljYbOJNgoWTc8cLKEc0IV+Hl8vB0Ly/0NZOqWkS3qMxj g9CG1/7R+OVsWhmVyD5g96mRKwr2xzHhCl3ZbvYqrg X-Gm-Gg: AeBDieuVTLFCueTRY1nj7mqvVo8qHMUVolTeBz26J+lZjZr65y9BJGXM92fPiCzXDl7 wgE9fM/2cPh/I0jQQd8fJeOcBrv7/59wg4LlMl/NF2tOPhOm2r32A2NwyJiWVRv8v4FMyMN3sg1 WeUdcBiUF+rohkDMQZjtDspjerSyDxD9VkYI7LLW2bpIuEIDQBpO63KpfM4+1u0hwAM4lWkR9Cd jdJOgqf6RO5zerWXQL9ygxEL2EEbe8Dd3LbWISIpadqU7swgpgbXkrL3+Y7PzuMz+OairvfBQbL baZQEIiRlcxqWsXSJuzu+X6R5+CWNil7SBI/4rmfjeYJEsdBKd1wwp1AaKRQWWTMnTmvZXOL2w+ llHotXPxAoJqtz1kKC3rCTqo= X-Received: by 2002:a05:620a:f11:b0:8f0:10b0:9e34 with SMTP id af79cd13be357-8fd18e26004mr1241694885a.8.1777944311485; Mon, 04 May 2026 18:25:11 -0700 (PDT) X-Received: by 2002:a05:620a:f11:b0:8f0:10b0:9e34 with SMTP id af79cd13be357-8fd18e26004mr1241691685a.8.1777944310854; Mon, 04 May 2026 18:25:10 -0700 (PDT) Received: from idea ([2600:4040:aa66:bf00:9e8e:99ff:fed1:71f]) by smtp.gmail.com with ESMTPSA id af79cd13be357-8fc29a80069sm1352688485a.15.2026.05.04.18.25.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2026 18:25:10 -0700 (PDT) From: Patrick Palka To: gcc-patches@gcc.gnu.org Cc: jason@redhat.com, Patrick Palka Subject: [PATCH] c++/reflection: rewrite and memoize consteval_only_p [PR125179] Date: Mon, 4 May 2026 21:25:06 -0400 Message-ID: <20260505012506.748365-1-ppalka@redhat.com> X-Mailer: git-send-email 2.54.0.rc1.54.g60f07c4f5c MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: Dz8w0FdApvBIhCHw1djRKv88hm7tI5dU5qtcUe-vKz0_1777944312 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-13.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk/16? -- >8 -- The TU in 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 the standard definition ([basic.types.general]/2). This patch also makes the predicate partially tristate, where the unknown state tracks whether we've seen an incomplete class type and therefore don't know if it's consteval-only. Finally this patch caches the result of the predicate for class types when the result is known (and the class type is complete). When the result is unknown then we must not cache so that a subsequent call to the predicate can try again. We also need to be able to cope with a class input that's not been laid out yet. With this patch compile time for the TU is now 1.15x 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_class_cache, consteval_only_p_1): ... this recursive memoized implementation. (consteval_only_p): Define in terms of consteval_only_p_1. --- gcc/cp/reflect.cc | 122 +++++++++++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 44 deletions(-) diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc index b36c4be42736..10b5ed2b109f 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -8561,47 +8561,10 @@ splice (tree refl) return refl; } -/* A walker for consteval_only_p. It cannot be a lambda, because we - have to call this recursively, sigh. */ +static tristate consteval_only_p_1 (tree, hash_set&); -static tree -consteval_only_type_r (tree *tp, int *walk_subtrees, void *data) -{ - tree t = *tp; - /* Types can contain themselves recursively, hence this. */ - auto visited = static_cast *>(data); - - if (!TYPE_P (t)) - return NULL_TREE; - - if (REFLECTION_TYPE_P (t)) - return t; - - if (typedef_variant_p (t)) - /* Tell cp_walk_subtrees to look through typedefs. */ - *walk_subtrees = 2; - - if (RECORD_OR_UNION_TYPE_P (t)) - { - /* Don't walk template arguments; A::type isn't a consteval-only - type. */ - *walk_subtrees = 0; - /* So we have to walk the fields manually. */ - for (tree member = TYPE_FIELDS (t); - member; member = DECL_CHAIN (member)) - if (TREE_CODE (member) == FIELD_DECL) - if (tree r = cp_walk_tree (&TREE_TYPE (member), - consteval_only_type_r, visited, visited)) - return r; - } - - return NULL_TREE; -} - -/* True if T is a consteval-only type as per [basic.types.general]: - "A type is consteval-only if it is either std::meta::info or a type - compounded from a consteval-only type", or something that has - a consteval-only type. */ +/* True if T is a consteval-only type as per [basic.types.general], or + is a declaration with such a type, or a TREE_VEC thereof. */ bool consteval_only_p (tree t) @@ -8612,7 +8575,7 @@ consteval_only_p (tree t) if (!TYPE_P (t)) t = TREE_TYPE (t); - if (!t) + if (!t || t == error_mark_node) return false; if (TREE_CODE (t) == TREE_VEC) @@ -8634,9 +8597,80 @@ consteval_only_p (tree t) which could be consteval-only, depending on T. */ t = complete_type (t); - /* Classes with std::meta::info members are also consteval-only. */ - hash_set visited; - return !!cp_walk_tree (&t, consteval_only_type_r, &visited, &visited); + hash_set class_set; + return consteval_only_p_1 (t, class_set).is_true (); +} + +/* A cache of the boolean result of consteval_only_p_1 for class types, when + the result is known. */ + +static GTY((cache)) type_tree_cache_map *consteval_only_class_cache; + +/* Recursive workhorse of consteval_only_p. Returns true if T is definitely + consteval-only, false if it's definitely not, and unknown if we saw an + incomplete type and therefore don't know. CLASS_SET is the set of class types + we're recursively inside. */ + +static tristate +consteval_only_p_1 (tree t, hash_set& class_set) +{ + t = TYPE_MAIN_VARIANT (t); + + if (REFLECTION_TYPE_P (t)) + return true; + else if (INDIRECT_TYPE_P (t)) + return consteval_only_p_1 (TREE_TYPE (t), class_set); + else if (TREE_CODE (t) == ARRAY_TYPE) + return consteval_only_p_1 (TREE_TYPE (t), class_set); + else if (FUNC_OR_METHOD_TYPE_P (t)) + { + tristate r = consteval_only_p_1 (TREE_TYPE (t), class_set); + for (tree parm = TYPE_ARG_TYPES (t); + parm != NULL_TREE && parm != void_list_node; + parm = TREE_CHAIN (parm)) + { + r = r || consteval_only_p_1 (TREE_VALUE (parm), class_set); + if (r.is_true ()) + break; + } + return r; + } + else if (RECORD_OR_UNION_TYPE_P (t)) + { + if (tree *slot = hash_map_safe_get (consteval_only_class_cache, t)) + return *slot == boolean_true_node; + + if (class_set.add (t)) + /* Handle struct A { A* p; } etc. */ + return false; + + tristate r = COMPLETE_TYPE_P (t) ? false : tristate::unknown (); + for (tree member = TYPE_FIELDS (t); member; member = DECL_CHAIN (member)) + if (TREE_CODE (member) == FIELD_DECL) + { + r = r || consteval_only_p_1 (TREE_TYPE (member), class_set); + if (r.is_true ()) + break; + } + + if (COMPLETE_TYPE_P (t)) + { + if (r.is_true ()) + hash_map_safe_put (consteval_only_class_cache, + t, boolean_true_node); + else if (r.is_false ()) + hash_map_safe_put (consteval_only_class_cache, + t, boolean_false_node); + } + + class_set.remove (t); + return r; + } + else if (TYPE_PTRMEM_P (t)) + return (consteval_only_p_1 (TYPE_PTRMEM_CLASS_TYPE (t), class_set) + || consteval_only_p_1 (TYPE_PTRMEM_POINTED_TO_TYPE (t), class_set)); + else + return false; } /* A walker for check_out_of_consteval_use_r. It cannot be a lambda, because