From patchwork Sun Jun 16 02:29:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathaniel Shead X-Patchwork-Id: 1948249 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=ggOG2Dff; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1xq41xt5z20Wb for ; Sun, 16 Jun 2024 12:31:44 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6D2FF3858C39 for ; Sun, 16 Jun 2024 02:31:42 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pj1-x1035.google.com (mail-pj1-x1035.google.com [IPv6:2607:f8b0:4864:20::1035]) by sourceware.org (Postfix) with ESMTPS id 28B3F3858C50 for ; Sun, 16 Jun 2024 02:29:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 28B3F3858C50 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 28B3F3858C50 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::1035 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1718504984; cv=none; b=pp+cg+BDf5J1hdL/hpMfhQkxeIJ5ihKMFyGtm9+v6UekiTfq2FCGc4IoGNSK5Pwj4Sv3vFz6Hii+eQtljm4/5jUfdis7LhqrWI1qhIu8qRIcMhl9qBTx2p575Kif/0Esi6uoKj5n7+xGvUnqa0ZokrF4MUERYBgWFg969sXeW5E= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1718504984; c=relaxed/simple; bh=ipf+228JLLAeBYFR57n8qXas8um8r8jVUkJKvENsDO4=; h=DKIM-Signature:Message-ID:Date:From:To:Subject:MIME-Version; b=ekxaorbvmrqA/xfiaiFkdR/h5QJul4mxKCB22BNUmkuoxLXAxrSckniOk8B8hg6heh8vKlEh8eEVBa4xDTdp545AFZbcblZ6Cn8OkogpG+P6OBTBcngf+ivZxFDKC3tbTMyMcdr75XA5kBOWFzY4ewr76Jf423YumRt+Uj0iWis= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pj1-x1035.google.com with SMTP id 98e67ed59e1d1-2c2ef6617bfso2914853a91.3 for ; Sat, 15 Jun 2024 19:29:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718504968; x=1719109768; darn=gcc.gnu.org; h=content-disposition:mime-version:subject:cc:to:from:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=EQFur61GnPXmWNe1z070qQJoPeEooLGTEC82oQu+AhE=; b=ggOG2DffmLZKPI45N8UEz4jgDSUFlgbMWbuKNjgastnB1WMim04MBSKxLyyKVyPhcu PX5JslRI3eHow33UiLkZcQKe1DoBEvpJ/MGNlmiONoK4s37+HIeWLk/S20+MFO9I2+1X YSGaQiMamu5dW6+7+Ht3loKER6aNgbsQq4NcQxbL/eIMCmsl2JvJxW7Gywd9rngb8mrx CJ5PgygizC8t+XfVfrRqG3QFSyt2ViBjl+XK3Hg0BMbMToe10MIEzgrk6/c3db0WxCWZ jk28oztNlZZf8SwVv8AV8JeTPf4sKN0b/XV9ruiDb+yOyPwCvfE2M4H/JxBIkUFEGliz +8wg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718504968; x=1719109768; h=content-disposition:mime-version:subject:cc:to:from:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=EQFur61GnPXmWNe1z070qQJoPeEooLGTEC82oQu+AhE=; b=BZ0pbMGmYn5XXe+2SdX6+JR5apbwW5uzEtjl6Gk5Zp8ZUmcYYd0W7Tn4ABQiATNs8g 34z1eCZ+TyxhgwyEsj07xLsCLY+jH57UW4Ef7CJ6iCxok/pOU0BfGUX8SKDVXRucGR8s 0Cw7vsrPBer/w2ms24rzdN38eBmhQhHv368UdMnhZIYm0c/NgaZ4DbzJfnJjboeIPpig dlj1t7VwU9Xz+Prp0sMU4HcGkcqgi4t/Uzfwyvy5JznCsLJo29ASYRh06ewSMavg9tB7 y0k4L7jLZR7ldNitSUyQFwaPPNWOdQ88gpcJI7JbYpQtTd4+cLi4hclrEnIdtVatpK6R xmXw== X-Gm-Message-State: AOJu0YzbcV6aJSLXDVVAxXicHYPottBZMPjshr78PLASiFNwN0iHQ0PY +FzvMua40QK3h9D2uG6JMWNDiZXl24PBmpo/T+NoCGJZPEFwOlTojxhktA== X-Google-Smtp-Source: AGHT+IGjXB+k4udsYkodFgYnrchAGhpIQXhrAk1tlAD1Y4IXAqQTK5kYGsjlEh4jfHY635BIu+rKQg== X-Received: by 2002:a17:902:7246:b0:1f6:8014:5e29 with SMTP id d9443c01a7336-1f8627d64dcmr69700765ad.40.1718504968122; Sat, 15 Jun 2024 19:29:28 -0700 (PDT) Received: from Thaum. (14-200-72-253.tpgi.com.au. [14.200.72.253]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1f855f07e6bsm56270975ad.207.2024.06.15.19.29.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 19:29:27 -0700 (PDT) Message-ID: <666e4e07.170a0220.f594a.008f@mx.google.com> X-Google-Original-Message-ID: Date: Sun, 16 Jun 2024 12:29:23 +1000 From: Nathaniel Shead To: gcc-patches@gcc.gnu.org Cc: Jason Merrill , Nathan Sidwell Subject: [PATCH] c++/modules: Ensure deduction guides are always reachable [PR115231] MIME-Version: 1.0 Content-Disposition: inline X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.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+incoming=patchwork.ozlabs.org@gcc.gnu.org Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk? This probably isn't the most efficient approach, since we need to do name lookup to find deduction guides for a type which will also potentially do a bunch of pointless lazy loading from imported modules, but I wasn't able to work out a better approach without completely reworking how deduction guides are stored and represented. This way at least is correct (I believe), and we can maybe revisit this in the future. -- >8 -- Deduction guides are represented as 'normal' functions currently, and have no special handling in modules. However, this causes some issues; by [temp.deduct.guide] a deduction guide is not found by normal name lookup and instead all reachable deduction guides for a class template should be considered, but this does not happen currently. To solve this, this patch ensures that all deduction guides are considered exported to ensure that they are always visible to importers if they are reachable. Another alternative here would be to add a new kind of "all reachable" flag to name lookup, but that is complicated by some difficulties in handling GM entities; this may be a better way to go if more kinds of entities end up needing this handling, however. Another issue here is that because deduction guides are "unrelated" functions, they will usually get discarded from the GMF, so this patch ensures that when finding dependencies, GMF deduction guides will also have bindings created. We do this in find_dependencies so that we don't unnecessarily create bindings for GMF deduction guides that are never reached; for consistency we do this for *all* deduction guides, not just GM ones. Finally, when merging deduction guides from multiple modules, the name lookup code may now return two-dimensional overload sets, so update callers to match. As a small drive-by improvement this patch also updates the error pretty printing code to add a space before the '->' when printing a deduction guide, so we get 'S(int) -> S' instead of 'S(int)-> S'. PR c++/115231 gcc/cp/ChangeLog: * error.cc (dump_function_decl): Add a space before '->' when printing deduction guides. * module.cc (depset::hash::add_binding_entity): Skip deduction guides here. (depset::hash::add_deduction_guides): New. (depset::hash::find_dependencies): Add deduction guide dependencies for a class template. (module_state::write_cluster): Always consider deduction guides as exported. * pt.cc (deduction_guides_for): Use 'lkp_iterator' instead of 'ovl_iterator'. gcc/testsuite/ChangeLog: * g++.dg/modules/dguide-1_a.C: New test. * g++.dg/modules/dguide-1_b.C: New test. * g++.dg/modules/dguide-2_a.C: New test. * g++.dg/modules/dguide-2_b.C: New test. * g++.dg/modules/dguide-3_a.C: New test. * g++.dg/modules/dguide-3_b.C: New test. * g++.dg/modules/dguide-3_c.C: New test. Signed-off-by: Nathaniel Shead --- gcc/cp/error.cc | 1 + gcc/cp/module.cc | 60 +++++++++++++++++++++++ gcc/cp/pt.cc | 2 +- gcc/testsuite/g++.dg/modules/dguide-1_a.C | 44 +++++++++++++++++ gcc/testsuite/g++.dg/modules/dguide-1_b.C | 20 ++++++++ gcc/testsuite/g++.dg/modules/dguide-2_a.C | 24 +++++++++ gcc/testsuite/g++.dg/modules/dguide-2_b.C | 19 +++++++ gcc/testsuite/g++.dg/modules/dguide-3_a.C | 10 ++++ gcc/testsuite/g++.dg/modules/dguide-3_b.C | 10 ++++ gcc/testsuite/g++.dg/modules/dguide-3_c.C | 22 +++++++++ 10 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/modules/dguide-1_a.C create mode 100644 gcc/testsuite/g++.dg/modules/dguide-1_b.C create mode 100644 gcc/testsuite/g++.dg/modules/dguide-2_a.C create mode 100644 gcc/testsuite/g++.dg/modules/dguide-2_b.C create mode 100644 gcc/testsuite/g++.dg/modules/dguide-3_a.C create mode 100644 gcc/testsuite/g++.dg/modules/dguide-3_b.C create mode 100644 gcc/testsuite/g++.dg/modules/dguide-3_c.C diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index 171a352c85f..2fb5084320e 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -1866,6 +1866,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) dump_type_suffix (pp, ret, flags); else if (deduction_guide_p (t)) { + pp->set_padding (pp_before); pp_cxx_ws_string (pp, "->"); dump_type (pp, TREE_TYPE (TREE_TYPE (t)), flags); } diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 6d6044af199..a2c9e151fd5 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -2589,6 +2589,9 @@ public: void add_partial_entities (vec *); void add_class_entities (vec *); + private: + void add_deduction_guides (tree decl); + public: void find_dependencies (module_state *); bool finalize_dependencies (); @@ -13127,6 +13130,11 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) { tree inner = decl; + if (deduction_guide_p (inner)) + /* Ignore deduction guides here, they'll be handled within + find_dependencies for a class template. */ + return false; + if (TREE_CODE (inner) == CONST_DECL && TREE_CODE (DECL_CONTEXT (inner)) == ENUMERAL_TYPE) inner = TYPE_NAME (DECL_CONTEXT (inner)); @@ -13590,6 +13598,50 @@ find_pending_key (tree decl, tree *decl_p = nullptr) return ns; } +/* Creates bindings and dependencies for all deduction guides of + the given class template DECL as needed. */ + +void +depset::hash::add_deduction_guides (tree decl) +{ + /* Alias templates never have deduction guides. */ + if (DECL_ALIAS_TEMPLATE_P (decl)) + return; + + /* We don't need to do anything for class-scope deduction guides, + as they will be added as members anyway. */ + if (!DECL_NAMESPACE_SCOPE_P (decl)) + return; + + tree ns = CP_DECL_CONTEXT (decl); + tree name = dguide_name (decl); + + /* We always add all deduction guides with a given name at once, + so if there's already a binding there's nothing to do. */ + if (find_binding (ns, name)) + return; + + tree guides = lookup_qualified_name (ns, name, LOOK_want::NORMAL, + /*complain=*/false); + if (guides == error_mark_node) + return; + + /* We have bindings to add. */ + depset *binding = make_binding (ns, name); + add_namespace_context (binding, ns); + + depset **slot = binding_slot (ns, name, /*insert=*/true); + *slot = binding; + + for (lkp_iterator it (guides); it; ++it) + { + gcc_checking_assert (!TREE_VISITED (*it)); + depset *dep = make_dependency (*it, EK_FOR_BINDING); + binding->deps.safe_push (dep); + dep->deps.safe_push (binding); + } +} + /* Iteratively find dependencies. During the walk we may find more entries on the same binding that need walking. */ @@ -13649,6 +13701,10 @@ depset::hash::find_dependencies (module_state *module) } walker.end (); + if (!walker.is_key_order () + && DECL_CLASS_TEMPLATE_P (decl)) + add_deduction_guides (decl); + if (!walker.is_key_order () && TREE_CODE (decl) == TEMPLATE_DECL && !DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)) @@ -15145,6 +15201,10 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size, flags |= cbf_hidden; else if (DECL_MODULE_EXPORT_P (STRIP_TEMPLATE (bound))) flags |= cbf_export; + else if (deduction_guide_p (bound)) + /* Deduction guides are always exported so that they are + reachable whenever their class template is. */ + flags |= cbf_export; } gcc_checking_assert (DECL_P (bound)); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 607753ae6b7..8e007a571a5 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -30784,7 +30784,7 @@ deduction_guides_for (tree tmpl, bool &any_dguides_p, tsubst_flags_t complain) else { cands = ctor_deduction_guides_for (tmpl, complain); - for (ovl_iterator it (guides); it; ++it) + for (lkp_iterator it (guides); it; ++it) cands = lookup_add (*it, cands); } diff --git a/gcc/testsuite/g++.dg/modules/dguide-1_a.C b/gcc/testsuite/g++.dg/modules/dguide-1_a.C new file mode 100644 index 00000000000..834e033eae3 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/dguide-1_a.C @@ -0,0 +1,44 @@ +// PR c++/115231 +// { dg-additional-options "-fmodules-ts -Wno-global-module" } +// { dg-module-cmi M } + +module; + +template +struct A { + template A(U); +}; + +template A(T) -> A; + +export module M; + +// Exporting a GMF entity should make the deduction guides reachable. +export using ::A; + + +export template +struct B { + template B(U); +}; + +// Not exported, but should still be reachable by [temp.deduct.guide] p1. +B(int) -> B; + + +// Class-scope deduction guides should be reachable as well, even if +// the class body was not exported. +export template struct C; + +template +struct C { + template + struct I { + template I(V); + }; + + I(int) -> I; + + template + I(const P*) -> I

; +}; diff --git a/gcc/testsuite/g++.dg/modules/dguide-1_b.C b/gcc/testsuite/g++.dg/modules/dguide-1_b.C new file mode 100644 index 00000000000..97266986d8f --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/dguide-1_b.C @@ -0,0 +1,20 @@ +// PR c++/115231 +// { dg-additional-options "-fmodules-ts" } + +import M; + +int main() { + // Check that deduction guides are reachable, + // and that they declared the right type. + A a(1); + A a2 = a; + + B b(2); + B b2 = b; + + C::I x(10); + C::I x2 = x; + + C::I y("xyz"); + C::I y2 = y; +} diff --git a/gcc/testsuite/g++.dg/modules/dguide-2_a.C b/gcc/testsuite/g++.dg/modules/dguide-2_a.C new file mode 100644 index 00000000000..fcd6c579813 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/dguide-2_a.C @@ -0,0 +1,24 @@ +// PR c++/115231 +// { dg-additional-options "-fmodules-ts -Wno-global-module" } +// { dg-module-cmi M } + +module; + +template +struct A { + template A(U); +}; +template A(T) -> A; + +export module M; + +template +struct B { + template B(U); +}; +B(int) -> B; + +// Accessing deduction guides should be possible, +// even if we can't name the type directly. +export A f(); +export B g(); diff --git a/gcc/testsuite/g++.dg/modules/dguide-2_b.C b/gcc/testsuite/g++.dg/modules/dguide-2_b.C new file mode 100644 index 00000000000..ca31306aea3 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/dguide-2_b.C @@ -0,0 +1,19 @@ +// PR c++/115231 +// { dg-additional-options "-fmodules-ts" } + +import M; + +template +struct U; + +template