Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2229918/?format=api
{ "id": 2229918, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2229918/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260428212111.1026503-1-polacek@redhat.com/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/1.1/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null }, "msgid": "<20260428212111.1026503-1-polacek@redhat.com>", "date": "2026-04-28T21:21:11", "name": "c++/reflection: remove cp_preserve_using_decl [PR124169]", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "0a31861a7d1b17c5a8262b2f61f37a3e4fa5f311", "submitter": { "id": 14370, "url": "http://patchwork.ozlabs.org/api/1.1/people/14370/?format=api", "name": "Marek Polacek", "email": "polacek@redhat.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260428212111.1026503-1-polacek@redhat.com/mbox/", "series": [ { "id": 501935, "url": "http://patchwork.ozlabs.org/api/1.1/series/501935/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=501935", "date": "2026-04-28T21:21:11", "name": "c++/reflection: remove cp_preserve_using_decl [PR124169]", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/501935/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2229918/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2229918/checks/", "tags": {}, "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=TrbL2hkq;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=TrbL2hkq", "sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com", "sourceware.org; spf=pass smtp.mailfrom=redhat.com", "server2.sourceware.org;\n arc=none smtp.remote-ip=170.10.133.124" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g4tft3pHHz1yK5\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 07:21:57 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 2E1864BA9010\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 21:21:55 +0000 (GMT)", "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by sourceware.org (Postfix) with ESMTP id 2875A4BA543C\n for <gcc-patches@gcc.gnu.org>; Tue, 28 Apr 2026 21:21:24 +0000 (GMT)", "from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-86-BZ5BpoiMPvOVnYvDT6CS5A-1; Tue,\n 28 Apr 2026 17:21:22 -0400", "from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 7A7B5195608B\n for <gcc-patches@gcc.gnu.org>; Tue, 28 Apr 2026 21:21:21 +0000 (UTC)", "from pdp-11.lan (unknown [10.22.89.17])\n by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id E0B3D195608E; Tue, 28 Apr 2026 21:21:20 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 2E1864BA9010", "OpenDKIM Filter v2.11.0 sourceware.org 2875A4BA543C" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 2875A4BA543C", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 2875A4BA543C", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777411284; cv=none;\n b=cCkadjOQAhCsaVdd6XsX37xWF8Wlcm7zKSXeTob/KyctaGE4PL70eqvj0Zk6WsIpHEi9RUf8pEW2dr38DljhZAmmSjepn2DOEgJikscjbHjrdm1rxLmyjctSHGQJJJrv66vOI35lnF+Bj7CbGKs97sgPqoC+SWxj/jxnpBf2wYo=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777411284; c=relaxed/simple;\n bh=E/N/55n2z6hiXt8KWPw++PicLk885QaH/anrjYWqToU=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=NHo8wSW9WHh2Jpt+Jnf++2URYUVR6Hb91+A8xIf3O6FiVqqBdktokyzjTlSqLu/9xeEqfGBkt0rTrusslKNekwflMoqRe1ujuUdLNNMJ92iAY1wZiQr/Z+tJ2cR31abIhlpFzMVIo3tN6O6mgtvU955+PfznkxYnDubWyM5gwHc=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1777411283;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding;\n bh=wKsHkbiqJLw89YY/d9fa+sMHbRfyY8luvegQ2iKFMWI=;\n b=TrbL2hkqZrN7LiQeCtkTv9bCKUNsQTexrnS6/MTvveCYbj0YAdQtZk0UI0u12mTjKKNo/g\n i7JEOaz+iFI4OpoG5w5rAcZWkfK/nRbSwNBfWcm3bXNb6/N/hf64ON8FCMj24W8gf+Aw+J\n gKl9yEOeYXsJAbWD8WovXQQ8YktS57Q=", "X-MC-Unique": "BZ5BpoiMPvOVnYvDT6CS5A-1", "X-Mimecast-MFC-AGG-ID": "BZ5BpoiMPvOVnYvDT6CS5A_1777411281", "From": "Marek Polacek <polacek@redhat.com>", "To": "GCC Patches <gcc-patches@gcc.gnu.org>,\n\tJason Merrill <jason@redhat.com>", "Subject": "[PATCH] c++/reflection: remove cp_preserve_using_decl [PR124169]", "Date": "Tue, 28 Apr 2026 17:21:11 -0400", "Message-ID": "<20260428212111.1026503-1-polacek@redhat.com>", "MIME-Version": "1.0", "X-Scanned-By": "MIMEDefang 3.0 on 10.30.177.17", "X-Mimecast-Spam-Score": "0", "X-Mimecast-MFC-PROC-ID": "wl7Sfbu2dkE77tg4395syhTMmTLjNguWBj1NqKPV_6A_1777411281", "X-Mimecast-Originator": "redhat.com", "Content-Transfer-Encoding": "8bit", "content-type": "text/plain; charset=\"US-ASCII\"; x-default=true", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "Frankly I'm not so sure this patch is such a great idea but I had to try.\n\nBootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?\n\n-- >8 --\ncp_preserve_using_decl is too broad so it would be good to have\na LOOK_want instead. This patch removes the global variable\nand instead adds LOOK_want::KEEP_USING. This has to be somehow\npropagated from cp_parser_lookup_name all the way down to\nstrip_using_decl. Unfortunately there are many paths by which\none can get to strip_using_decl, so this patch isn't as small\nas I had hoped.\n\n\tPR c++/124169\n\ngcc/cp/ChangeLog:\n\n\t* cp-tree.h: Remove cp_preserve_using_decl.\n\t(lookup_member): Adjust declaration.\n\t(strip_using_decl): Likewise.\n\t* name-lookup.cc (search_anon_aggr): Make static. New bool\n\tparameter. Pass it down to get_class_binding_direct.\n\t(name_lookup::process_binding): Adjust calls to strip_using_decl.\n\t(fields_linear_search): New bool parameter. Pass it down to\n\tsearch_anon_aggr. Adjust the call to strip_using_decl.\n\t(name_independent_linear_search): Likewise.\n\t(get_class_binding_direct): New bool parameter. Pass it down to\n\tname_independent_linear_search and fields_linear_search.\n\t(get_class_binding): New bool parameter. Pass it down to\n\tget_class_binding_direct.\n\t(strip_using_decl): New bool parameter. If it's true, don't\n\tstrip USING_DECLs. Don't check cp_preserve_using_decl.\n\t(lookup_class_binding): Adjust the call to fields_linear_search.\n\t(lookup_qualified_name): Check want instead of\n\tcp_preserve_using_decl. Adjust the call to lookup_member.\n\t* name-lookup.h (LOOK_want): Add KEEP_USING.\n\t(search_anon_aggr): Remove declaration.\n\t(get_class_binding_direct): Adjust declaration.\n\t(get_class_binding): Likewise.\n\t* parser.cc: Remove cp_preserve_using_decl.\n\t(cp_parser_reflection_name): Don't override\n\tcp_preserve_using_decl. Call cp_parser_lookup_name instead of\n\tcp_parser_lookup_name_simple.\n\t(cp_parser_lookup_name): New bool parameter. Use it. Adjust\n\tcalls to lookup_qualified_name, lookup_member, and lookup_name.\n\t* search.cc (struct lookup_field_info): Add keep_using.\n\t(lookup_field_r): Pass lfi->keep_using to get_class_binding.\n\t(lookup_member): New bool parameter. Use it to set\n\tlfi.keep_using. Pass it to strip_using_decl.\n\ngcc/testsuite/ChangeLog:\n\n\t* g++.dg/reflect/expr17.C: New test.\n---\n gcc/cp/cp-tree.h | 7 ++-\n gcc/cp/name-lookup.cc | 69 ++++++++++++++++-----------\n gcc/cp/name-lookup.h | 8 ++--\n gcc/cp/parser.cc | 51 ++++++++++++--------\n gcc/cp/search.cc | 13 +++--\n gcc/testsuite/g++.dg/reflect/expr17.C | 13 +++++\n 6 files changed, 102 insertions(+), 59 deletions(-)\n create mode 100644 gcc/testsuite/g++.dg/reflect/expr17.C\n\n\nbase-commit: c1977d101524d87642790422134fe170ce00b545", "diff": "diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h\nindex 70132b586d8..3c8d68f5b34 100644\n--- a/gcc/cp/cp-tree.h\n+++ b/gcc/cp/cp-tree.h\n@@ -6253,8 +6253,6 @@ extern bool comparing_contracts;\n \n /* In parser.cc. */\n \n-extern bool cp_preserve_using_decl;\n-\n /* Nonzero if we are parsing an unevaluated operand: an operand to\n sizeof, typeof, or alignof. This is a count since operands to\n sizeof can be nested. */\n@@ -8338,7 +8336,8 @@ extern tree lookup_field\t\t\t(tree, tree, int, bool);\n extern tree lookup_fnfields\t\t\t(tree, tree, int, tsubst_flags_t);\n extern tree lookup_member\t\t\t(tree, tree, int, bool,\n \t\t\t\t\t\t tsubst_flags_t,\n-\t\t\t\t\t\t access_failure_info *afi = NULL);\n+\t\t\t\t\t\t access_failure_info * = nullptr,\n+\t\t\t\t\t\t bool = false);\n extern tree lookup_member_fuzzy\t\t\t(tree, tree, bool);\n extern tree locate_field_accessor\t\t(tree, tree, bool);\n extern int look_for_overrides\t\t\t(tree, tree);\n@@ -9182,7 +9181,7 @@ extern void process_and_check_pending_immediate_escalating_fns ();\n extern bool is_invisiref_parm \t\t\t(const_tree);\n \n /* in name-lookup.cc */\n-extern tree strip_using_decl (tree);\n+extern tree strip_using_decl (tree, bool = false);\n extern void diagnose_name_conflict\t\t(tree, tree);\n extern bool dependent_local_decl_p\t\t(tree);\n \ndiff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc\nindex ef844088381..e7e88882703 100644\n--- a/gcc/cp/name-lookup.cc\n+++ b/gcc/cp/name-lookup.cc\n@@ -44,6 +44,7 @@ static name_hint maybe_suggest_missing_std_header (location_t location,\n \t\t\t\t\t\t tree name);\n static name_hint suggest_alternatives_for_1 (location_t location, tree name,\n \t\t\t\t\t bool suggest_misspellings);\n+static tree search_anon_aggr (tree, tree, bool, bool);\n \n /* Slots in BINDING_VECTOR. */\n enum binding_slots\n@@ -754,8 +755,8 @@ name_lookup::process_binding (tree new_val, tree new_type)\n && (want & LOOK_want::TYPE_NAMESPACE) == LOOK_want::NAMESPACE)\n new_type = NULL_TREE;\n \n- new_val = strip_using_decl (new_val);\n- new_type = strip_using_decl (new_type);\n+ new_val = strip_using_decl (new_val, bool (want & LOOK_want::KEEP_USING));\n+ new_type = strip_using_decl (new_type, bool (want & LOOK_want::KEEP_USING));\n \n /* Do we really see a value? */\n if (new_val)\n@@ -1843,10 +1844,11 @@ member_vec_linear_search (vec<tree, va_gc> *member_vec, tree name)\n return NULL_TREE;\n }\n \n-/* Linear search of (partially ordered) fields of KLASS for NAME. */\n+/* Linear search of (partially ordered) fields of KLASS for NAME. KEEP_USING\n+ is true if we shouldn't strip USING_DECLs. */\n \n static tree\n-fields_linear_search (tree klass, tree name, bool want_type)\n+fields_linear_search (tree klass, tree name, bool want_type, bool keep_using)\n {\n for (tree fields = TYPE_FIELDS (klass); fields; fields = DECL_CHAIN (fields))\n {\n@@ -1855,7 +1857,8 @@ fields_linear_search (tree klass, tree name, bool want_type)\n if (TREE_CODE (decl) == FIELD_DECL\n \t && ANON_AGGR_TYPE_P (TREE_TYPE (decl)))\n \t{\n-\t if (tree temp = search_anon_aggr (TREE_TYPE (decl), name, want_type))\n+\t if (tree temp = search_anon_aggr (TREE_TYPE (decl), name, want_type,\n+\t\t\t\t\t keep_using))\n \t return temp;\n \t}\n \n@@ -1864,7 +1867,7 @@ fields_linear_search (tree klass, tree name, bool want_type)\n \n if (TREE_CODE (decl) == USING_DECL)\n \t{\n-\t decl = strip_using_decl (decl);\n+\t decl = strip_using_decl (decl, keep_using);\n \t if (is_overloaded_fn (decl))\n \t continue;\n \t}\n@@ -1887,10 +1890,11 @@ fields_linear_search (tree klass, tree name, bool want_type)\n \n /* Like fields_linear_search, but specific for \"_\" name. There can be multiple\n name-independent non-static data members and in that case a TREE_LIST with the\n- ambiguous decls should be returned. */\n+ ambiguous decls should be returned. KEEP_USING is true if we shouldn't strip\n+ USING_DECLs. */\n \n static tree\n-name_independent_linear_search (tree val, tree klass, tree name)\n+name_independent_linear_search (tree val, tree klass, tree name, bool keep_using)\n {\n for (tree fields = TYPE_FIELDS (klass); fields; fields = DECL_CHAIN (fields))\n {\n@@ -1899,7 +1903,8 @@ name_independent_linear_search (tree val, tree klass, tree name)\n if (TREE_CODE (decl) == FIELD_DECL\n \t && ANON_AGGR_TYPE_P (TREE_TYPE (decl)))\n \t{\n-\t if (tree temp = search_anon_aggr (TREE_TYPE (decl), name, false))\n+\t if (tree temp = search_anon_aggr (TREE_TYPE (decl), name,\n+\t\t\t\t\t /*want_type=*/false, keep_using))\n \t {\n \t decl = temp;\n \t goto add;\n@@ -1911,7 +1916,7 @@ name_independent_linear_search (tree val, tree klass, tree name)\n \n if (TREE_CODE (decl) == USING_DECL)\n \t{\n-\t decl = strip_using_decl (decl);\n+\t decl = strip_using_decl (decl, keep_using);\n \t if (is_overloaded_fn (decl))\n \t continue;\n \t}\n@@ -1953,25 +1958,26 @@ name_independent_linear_search (tree val, tree klass, tree name)\n /* Look for NAME member inside of anonymous aggregate ANON. Although\n such things should only contain FIELD_DECLs, we check that too\n late, and would give very confusing errors if we weren't\n- permissive here. */\n+ permissive here. If KEEP_USING is true, name lookup will preserve\n+ USING_DECLs. */\n \n-tree\n-search_anon_aggr (tree anon, tree name, bool want_type)\n+static tree\n+search_anon_aggr (tree anon, tree name, bool want_type, bool keep_using)\n {\n gcc_assert (COMPLETE_TYPE_P (anon));\n- tree ret = get_class_binding_direct (anon, name, want_type);\n+ tree ret = get_class_binding_direct (anon, name, want_type, keep_using);\n return ret;\n }\n \n /* Look for NAME as an immediate member of KLASS (including\n- anon-members or unscoped enum member). TYPE_OR_FNS is zero for\n- regular search. >0 to get a type binding (if there is one) and <0\n- if you want (just) the member function binding.\n+ anon-members or unscoped enum member). If KEEP_USING is true,\n+ name lookup will preserve USING_DECLs.\n \n Use this if you do not want lazy member creation. */\n \n tree\n-get_class_binding_direct (tree klass, tree name, bool want_type)\n+get_class_binding_direct (tree klass, tree name, bool want_type/*=false*/,\n+\t\t\t bool keep_using/*=false*/)\n {\n gcc_checking_assert (RECORD_OR_UNION_TYPE_P (klass));\n \n@@ -2042,11 +2048,12 @@ get_class_binding_direct (tree klass, tree name, bool want_type)\n \tval = member_vec_linear_search (member_vec, lookup);\n \n if (id_equal (lookup, \"_\") && !want_type)\n-\tval = name_independent_linear_search (val, klass, lookup);\n+\tval = name_independent_linear_search (val, klass, lookup, keep_using);\n else if (!val || (TREE_CODE (val) == OVERLOAD && OVL_DEDUP_P (val)))\n \t/* Dependent using declarations are a 'field', make sure we\n \t return that even if we saw an overload already. */\n-\tif (tree field_val = fields_linear_search (klass, lookup, want_type))\n+\tif (tree field_val = fields_linear_search (klass, lookup, want_type,\n+\t\t\t\t\t\t keep_using))\n \t {\n \t if (!val)\n \t val = field_val;\n@@ -2108,14 +2115,15 @@ maybe_lazily_declare (tree klass, tree name)\n special function creation as necessary. */\n \n tree\n-get_class_binding (tree klass, tree name, bool want_type /*=false*/)\n+get_class_binding (tree klass, tree name, bool want_type/*=false*/,\n+\t\t bool keep_using/*=false*/)\n {\n klass = complete_type (klass);\n \n if (COMPLETE_TYPE_P (klass))\n maybe_lazily_declare (klass, name);\n \n- return get_class_binding_direct (klass, name, want_type);\n+ return get_class_binding_direct (klass, name, want_type, keep_using);\n }\n \n /* Find the slot containing overloads called 'NAME'. If there is no\n@@ -2766,18 +2774,19 @@ pop_bindings_and_leave_scope (void)\n leave_scope ();\n }\n \n-/* Strip non dependent using declarations. If DECL is dependent,\n- surreptitiously create a typename_type and return it. */\n+/* Strip non dependent using declarations. If DECL is dependent,\n+ surreptitiously create a typename_type and return it. If\n+ KEEP_USING is true, don't actually strip USING_DECLs. */\n \n tree\n-strip_using_decl (tree decl)\n+strip_using_decl (tree decl, bool keep_using/*=false*/)\n {\n if (decl == NULL_TREE)\n return NULL_TREE;\n \n while (TREE_CODE (decl) == USING_DECL\n \t && !DECL_DEPENDENT_P (decl)\n-\t && (LIKELY (!cp_preserve_using_decl)\n+\t && (LIKELY (!keep_using)\n \t || TREE_CODE (USING_DECL_DECLS (decl)) == NAMESPACE_DECL))\n decl = USING_DECL_DECLS (decl);\n \n@@ -4326,7 +4335,8 @@ lookup_class_binding (tree klass, tree name)\n {\n gcc_checking_assert (IS_FAKE_BASE_TYPE (klass)\n \t\t\t || TYPE_PTRMEMFUNC_P (klass));\n- found = fields_linear_search (klass, name, false);\n+ found = fields_linear_search (klass, name, /*want_type=*/false,\n+\t\t\t\t /*keep_using=*/false);\n }\n \n return found;\n@@ -7714,7 +7724,7 @@ lookup_qualified_name (tree scope, tree name, LOOK_want want, bool complain)\n \t for using decls. */\n \t if (TREE_CODE (t) == OVERLOAD\n \t && TREE_TYPE (t) != unknown_type_node\n-\t && LIKELY (!cp_preserve_using_decl))\n+\t && LIKELY (!bool (want & LOOK_want::KEEP_USING)))\n \t t = OVL_FUNCTION (t);\n \t}\n }\n@@ -7722,7 +7732,8 @@ lookup_qualified_name (tree scope, tree name, LOOK_want want, bool complain)\n t = lookup_enumerator (scope, name);\n else if (is_class_type (scope, complain))\n t = lookup_member (scope, name, 2, bool (want & LOOK_want::TYPE),\n-\t\t tf_warning_or_error);\n+\t\t tf_warning_or_error, /*access_failure_info=*/nullptr,\n+\t\t bool (want & LOOK_want::KEEP_USING));\n \n if (!t)\n return error_mark_node;\ndiff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h\nindex cd0799a80de..e2dc0f1aa0f 100644\n--- a/gcc/cp/name-lookup.h\n+++ b/gcc/cp/name-lookup.h\n@@ -431,6 +431,7 @@ enum class LOOK_want\n \n ANY_REACHABLE = 1 << 5, /* Include reachable module declarations not\n \t\t\t normally visible to name lookup. */\n+ KEEP_USING = 1 << 6,\t /* Don't strip USING_DECLs. */\n \n TYPE_NAMESPACE = TYPE | NAMESPACE, /* Either NAMESPACE or TYPE. */\n };\n@@ -489,9 +490,10 @@ extern void do_namespace_alias (location_t, tree, tree);\n extern tree do_class_using_decl (tree, tree);\n extern tree lookup_arg_dependent (tree, tree, vec<tree, va_gc> *,\n \t\t\t\t bool tentative = false);\n-extern tree search_anon_aggr (tree, tree, bool = false);\n-extern tree get_class_binding_direct (tree, tree, bool want_type = false);\n-extern tree get_class_binding (tree, tree, bool want_type = false);\n+extern tree get_class_binding_direct (tree, tree, bool want_type = false,\n+\t\t\t\t bool keep_using = false);\n+extern tree get_class_binding (tree, tree, bool want_type = false,\n+\t\t\t bool keep_using = false);\n extern tree *find_member_slot (tree klass, tree name);\n extern tree *add_member_slot (tree klass, tree name);\n extern void resort_type_member_vec (void *, void *,\ndiff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc\nindex dc67cfd9f7c..6f2c5eccad3 100644\n--- a/gcc/cp/parser.cc\n+++ b/gcc/cp/parser.cc\n@@ -295,10 +295,6 @@ static FILE *cp_lexer_debug_stream;\n sizeof, typeof, or alignof. */\n int cp_unevaluated_operand;\n \n-/* Nonzero if we are parsing a reflect-expression and shouldn't strip\n- using-declarations. */\n-bool cp_preserve_using_decl;\n-\n #if ENABLE_ANALYZER\n \n namespace ana {\n@@ -3066,7 +3062,8 @@ static tree cp_parser_objc_struct_declaration\n /* Utility Routines */\n \n static cp_expr cp_parser_lookup_name\n- (cp_parser *, tree, enum tag_types, int, bool, bool, tree *, location_t);\n+ (cp_parser *, tree, enum tag_types, int, bool, bool, tree *, location_t,\n+ bool = false);\n static tree cp_parser_lookup_name_simple\n (cp_parser *, tree, location_t);\n static tree cp_parser_maybe_treat_template_as_class\n@@ -10059,11 +10056,15 @@ cp_parser_reflection_name (cp_parser *parser)\n cp_parser_error (parser, \"%<template%> must follow a nested-name-\"\n \t\t \"specifier\");\n \n- auto s = make_temp_override (cp_preserve_using_decl, true);\n /* Look for the identifier. */\n location_t loc = cp_lexer_peek_token (parser->lexer)->location;\n tree name = cp_parser_identifier (parser);\n- tree decl = cp_parser_lookup_name_simple (parser, name, loc);\n+ tree decl = cp_parser_lookup_name (parser, name, none_type,\n+\t\t\t\t /*is_template=*/false,\n+\t\t\t\t /*is_namespace=*/false,\n+\t\t\t\t /*check_dependency=*/true,\n+\t\t\t\t /*ambiguous_decls=*/nullptr,\n+\t\t\t\t loc, /*keep_using=*/true);\n if (name != error_mark_node && decl == error_mark_node)\n cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, loc);\n \n@@ -35255,7 +35256,9 @@ prefer_type_arg (tag_types tag_type)\n \n If AMBIGUOUS_DECLS is non-NULL, *AMBIGUOUS_DECLS is set to a\n TREE_LIST of candidates if name-lookup results in an ambiguity, and\n- NULL_TREE otherwise. */\n+ NULL_TREE otherwise.\n+\n+ If KEEP_USING is true, name lookup will preserve USING_DECLs. */\n \n static cp_expr\n cp_parser_lookup_name (cp_parser *parser, tree name,\n@@ -35264,10 +35267,21 @@ cp_parser_lookup_name (cp_parser *parser, tree name,\n \t\t bool is_namespace,\n \t\t bool check_dependency,\n \t\t tree *ambiguous_decls,\n-\t\t location_t name_location)\n+\t\t location_t name_location,\n+\t\t bool keep_using/*=false*/)\n {\n tree decl;\n tree object_type = parser->context->object_type;\n+ /* Prepare the want flags. */\n+ const auto want = (keep_using\n+\t\t ? prefer_type_arg (tag_type) | LOOK_want::KEEP_USING\n+\t\t : prefer_type_arg (tag_type));\n+ const auto want_ns = (keep_using\n+\t\t\t? LOOK_want::NAMESPACE | LOOK_want::KEEP_USING\n+\t\t\t: LOOK_want::NAMESPACE);\n+ const auto want_type = (keep_using\n+\t\t\t ? LOOK_want::TYPE | LOOK_want::KEEP_USING\n+\t\t\t : LOOK_want::TYPE);\n \n /* Assume that the lookup will be unambiguous. */\n if (ambiguous_decls)\n@@ -35365,8 +35379,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,\n \t may be instantiated during name lookup. In that case,\n \t errors may be issued. Even if we rollback the current\n \t tentative parse, those errors are valid. */\n-\t decl = lookup_qualified_name (parser->scope, name,\n-\t\t\t\t\tprefer_type_arg (tag_type),\n+\t decl = lookup_qualified_name (parser->scope, name, want,\n \t\t\t\t\t/*complain=*/true);\n \n \t /* 3.4.3.1: In a lookup in which the constructor is an acceptable\n@@ -35387,8 +35400,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,\n \t && DECL_SELF_REFERENCE_P (decl)\n \t && same_type_p (DECL_CONTEXT (decl), parser->scope))\n \t decl = lookup_qualified_name (parser->scope, ctor_identifier,\n-\t\t\t\t\t prefer_type_arg (tag_type),\n-\t\t\t\t\t /*complain=*/true);\n+\t\t\t\t\t want, /*complain=*/true);\n \n \t if (pushed_scope)\n \t pop_scope (pushed_scope);\n@@ -35443,7 +35455,9 @@ cp_parser_lookup_name (cp_parser *parser, tree name,\n \t\t\t name,\n \t\t\t /*protect=*/2,\n \t\t\t /*prefer_type=*/tag_type != none_type,\n-\t\t\t tf_warning_or_error);\n+\t\t\t tf_warning_or_error,\n+\t\t\t /*access_failure_info=*/nullptr,\n+\t\t\t keep_using);\n else\n \tdecl = NULL_TREE;\n \n@@ -35457,13 +35471,13 @@ cp_parser_lookup_name (cp_parser *parser, tree name,\n else if (!decl)\n \t/* Look it up in the enclosing context. DR 141: When looking for a\n \t template-name after -> or ., only consider class templates. */\n-\tdecl = lookup_name (name, is_namespace ? LOOK_want::NAMESPACE\n+\tdecl = lookup_name (name, is_namespace ? want_ns\n \t\t\t /* DR 141: When looking in the\n \t\t\t current enclosing context for a\n \t\t\t template-name after -> or ., only\n \t\t\t consider class templates. */\n-\t\t\t : is_template ? LOOK_want::TYPE\n-\t\t\t : prefer_type_arg (tag_type));\n+\t\t\t : is_template ? want_type\n+\t\t\t : want);\n \n /* If we did unqualified lookup of a dependent member-qualified name and\n \t found something, do we want to use it? P1787 clarified that we need\n@@ -35494,8 +35508,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,\n }\n else\n {\n- decl = lookup_name (name, is_namespace ? LOOK_want::NAMESPACE\n-\t\t\t : prefer_type_arg (tag_type));\n+ decl = lookup_name (name, is_namespace ? want_ns : want);\n parser->qualifying_scope = NULL_TREE;\n parser->object_scope = NULL_TREE;\n }\ndiff --git a/gcc/cp/search.cc b/gcc/cp/search.cc\nindex e098362fed7..b55bf042901 100644\n--- a/gcc/cp/search.cc\n+++ b/gcc/cp/search.cc\n@@ -995,6 +995,8 @@ struct lookup_field_info {\n tree ambiguous;\n /* If nonzero, we are looking for types, not data members. */\n int want_type;\n+ /* If true, we don't strip USING_DECLs. */\n+ bool keep_using;\n };\n \n /* True for a class member means that it is shared between all objects\n@@ -1072,7 +1074,7 @@ lookup_field_r (tree binfo, void *data)\n && !BINFO_VIRTUAL_P (binfo))\n return dfs_skip_bases;\n \n- nval = get_class_binding (type, lfi->name, lfi->want_type);\n+ nval = get_class_binding (type, lfi->name, lfi->want_type, lfi->keep_using);\n \n /* If there is no declaration with the indicated name in this type,\n then there's nothing to do. */\n@@ -1166,7 +1168,8 @@ build_baselink (tree binfo, tree access_binfo, tree functions, tree optype)\n ambiguous lookup, we return NULL. If PROTECT is 1, we issue error\n messages about inaccessible or ambiguous lookup. If PROTECT is 2,\n we return a TREE_LIST whose TREE_TYPE is error_mark_node and whose\n- TREE_VALUEs are the list of ambiguous candidates.\n+ TREE_VALUEs are the list of ambiguous candidates. If KEEP_USING is\n+ true, name lookup will preserve USING_DECLs.\n \n WANT_TYPE is 1 when we should only return TYPE_DECLs.\n \n@@ -1176,7 +1179,8 @@ build_baselink (tree binfo, tree access_binfo, tree functions, tree optype)\n \n tree\n lookup_member (tree xbasetype, tree name, int protect, bool want_type,\n-\t tsubst_flags_t complain, access_failure_info *afi /* = NULL */)\n+\t tsubst_flags_t complain, access_failure_info *afi/*=nullptr*/,\n+\t bool keep_using/*=false*/)\n {\n tree rval, rval_binfo = NULL_TREE;\n tree type = NULL_TREE, basetype_path = NULL_TREE;\n@@ -1227,6 +1231,7 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type,\n lfi.type = type;\n lfi.name = name;\n lfi.want_type = want_type;\n+ lfi.keep_using = keep_using;\n dfs_walk_all (basetype_path, &lookup_field_r, NULL, &lfi);\n rval = lfi.rval;\n rval_binfo = lfi.rval_binfo;\n@@ -1276,7 +1281,7 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type,\n if (protect == 1 && !really_overloaded_fn (rval))\n {\n tree decl = is_overloaded_fn (rval) ? get_first_fn (rval) : rval;\n- decl = strip_using_decl (decl);\n+ decl = strip_using_decl (decl, keep_using);\n /* A dependent USING_DECL will be checked after tsubsting. */\n if (TREE_CODE (decl) != USING_DECL\n \t && !DECL_IOBJ_MEMBER_FUNCTION_P (decl)\ndiff --git a/gcc/testsuite/g++.dg/reflect/expr17.C b/gcc/testsuite/g++.dg/reflect/expr17.C\nnew file mode 100644\nindex 00000000000..c56f45c3912\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/reflect/expr17.C\n@@ -0,0 +1,13 @@\n+// PR c++/124169\n+// { dg-do compile { target c++26 } }\n+// { dg-additional-options \"-freflection\" }\n+\n+enum class Jazz { BOP };\n+using Jazz::BOP;\n+constexpr auto r = ^^BOP; // { dg-error \"cannot be applied to a using-declaration\" }\n+\n+struct A { enum Mode { Phrygian }; };\n+struct B : A { using A::Phrygian; };\n+struct C : A { using A::Mode; };\n+constexpr auto r2 = ^^B::Phrygian; // { dg-error \"cannot be applied to a using-declaration\" }\n+constexpr auto r3 = ^^C::Mode;\t // { dg-error \"cannot be applied to a using-declaration\" }\n", "prefixes": [] }