From patchwork Wed Feb 28 04:12:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathaniel Shead X-Patchwork-Id: 207661 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:a81b:b0:108:e6aa:91d0 with SMTP id bq27csp3126754dyb; Tue, 27 Feb 2024 20:13:02 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCXlbdCQxdNXpiOtHLsELCv2pszZaHeeOTdlzkxZzb6EjcneowXMyfM484mHUrlPBrppWmVT9Pb1dUiu5ziE7GBSRwtM5w== X-Google-Smtp-Source: AGHT+IHczWTOCdiUpOnh0Cd/fZBSax+35dZ+hUuSIzr0gJiBnIA4EO05C7+Gbod7Lj/bJXqfvPCj X-Received: by 2002:a05:6214:248e:b0:68e:fa3b:5bc1 with SMTP id gi14-20020a056214248e00b0068efa3b5bc1mr4360191qvb.31.1709093582035; Tue, 27 Feb 2024 20:13:02 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1709093582; cv=pass; d=google.com; s=arc-20160816; b=R7r6LquvIwNl+cQN7uT/k1+BKBthczHRnl/KkSk/UWVTxstYh8KHJfDA20JncNBhzo tZ8U00KdA+1aTOvzPuQRST+fc2jqlvQRI0WaQN/GCTb5Q2B7LsPifbnfkvLV1AhOfoO5 cZ5/rRuLLzOY+dqEZVCx1tq6bJ5ODMRbQaSZ+wvMO5dW6GD49Kzz19B/nisdjAZdSEEu pFYqU4iu9ReA4DEtOsSkKeG8Ej52LjWa72UIXNvCLD+Dly+h3pnyhKBckOwzu8DdtT2S lop6v8BuPEGD2y76H6jmYnraGtLyTZS3/angzKHjF2KyDPVi1b1/oGHpySw/z0nUciIc Yi5w== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:in-reply-to:content-disposition :mime-version:references:subject:cc:to:from:date:message-id :dkim-signature:arc-filter:dmarc-filter:delivered-to; bh=SkL5Fd97lmzlAbBFT32APyNUlagqRRfJnBlUMQvVoTc=; fh=/NebptFxf+NXcousPXB/bhnxvGU95QAU6mzjKHdmivE=; b=uoee3b+cXNx8annD6VR9PExhm75j895Pj/rzTGMHPdV5HdzVMNnbqtlU8IAZuRlfdE RxiMzQNwedxGZvy4SUWbS+0y2RhZZPzmcVOX5kM3pWQnH8jzZ7F7Tp24pM5GU8N+BB/Y Ors5cuodMzL30GNY9bL72I+WZiO6bSZ15faPfi8AY9kV+uqfHxKyIatm2QBc2pbiWqpw lxX15I2Y3bokPuq+zGCy+JsBTGVamjOs7lHmeshr4bllY6jJJK8GrxIiJ7Uj37ceenCY fLUgB31QGzWVPLFPVKW5ZUHbbwL40K+avtzaXI3IGMVnFmmCbGH5kXtR0tssgO9nQvyi LgYw==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=CNLOJnHC; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from server2.sourceware.org (server2.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id gi8-20020a056214248800b0069037956972si173080qvb.203.2024.02.27.20.13.01 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Feb 2024 20:13:02 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=CNLOJnHC; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B2481385840E for ; Wed, 28 Feb 2024 04:13:01 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-oi1-x22f.google.com (mail-oi1-x22f.google.com [IPv6:2607:f8b0:4864:20::22f]) by sourceware.org (Postfix) with ESMTPS id 1BDA23858C98 for ; Wed, 28 Feb 2024 04:12:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1BDA23858C98 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 1BDA23858C98 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::22f ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709093541; cv=none; b=juLG0k8yPAdgS0BbVETqj5BKzZmoJlNjO4WoYAKIST+0JNpTt3OjvSm2aOOKdxp7LyiHhP7NSlPb4IB9efqLxt9Fe1tKeDpS2NYWiUU0ujDBcTqyFn/tnbjNGbRhBZS4g3UUNcyd50kvJrZBR7MSAuC3rC4lqa2h6PWSs9V30sY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709093541; c=relaxed/simple; bh=v7LI7ffJoKZOxh1W6EmUssuNtFP/6SCDocpZpa6jprY=; h=DKIM-Signature:Message-ID:Date:From:To:Subject:MIME-Version; b=MNRBBY61Qol5lazHhlGPEaALpK1djOCbWAxwMl3AIWWmKlgxGdeBAOiJoeVRx5QbMAhP2ZEUPXk+VaeblSK/bFRItv9IjQ6134BLlhaRpNcMbyBRpX1ud380UIjrWMwbBbpZQz9m5hHaeCMqSXx28ixWaHUCC7RBCt4Z2UkVTPc= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-oi1-x22f.google.com with SMTP id 5614622812f47-3bbb4806f67so3810228b6e.3 for ; Tue, 27 Feb 2024 20:12:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1709093537; x=1709698337; darn=gcc.gnu.org; h=in-reply-to:content-disposition:mime-version:references:subject:cc :to:from:date:message-id:from:to:cc:subject:date:message-id:reply-to; bh=SkL5Fd97lmzlAbBFT32APyNUlagqRRfJnBlUMQvVoTc=; b=CNLOJnHCYR0mllh7rZlDMJWJZFvPHMRAPVy+b4r6miP4iihWYsVepQCFcqtzxMgbza BMy668r9WRMUQLGP4qlmn2/l2T6+dz+kGhxTFMu+UJQWsNos61+Xad8CEyTo0gPuwl+f T3IPV7zKZFpnMDiqiGVRo3Mf/QLROIxUT9NG64fbP+S8qC0l1WXhyqAtmoSt3wnrCmWa 8TcmljnItbVddrTeLXfeXJVgQq5nKcA5HQHn/CIM/+uqLplPUivKzq5cBv5k3RN92hkX zJF8DOAdNHZ6iE97XSILUBK2GsnENLX07vkZrmyDy6QRd2h96aQdPcttip5O8Agj8t1J PX4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1709093537; x=1709698337; h=in-reply-to:content-disposition:mime-version:references:subject:cc :to:from:date:message-id:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=SkL5Fd97lmzlAbBFT32APyNUlagqRRfJnBlUMQvVoTc=; b=HaEIYBul6+R7IcWkSvR+K5YKiWapAKfiKATGqBn2nxNNQQ2gsvyq7wamLw2oJw8NXU Md/m+0VgfH70hATAf1a/cy1l9MxfMGkEgWZ4/BMRQFoiPpz5H9iqI01NYXsshRWUTWFt lRRYspfq5hty8HXbAwmgTmCBU0WNccebKTT99aOtEWc2zC32RzqgFsERIeUSsZLmE/pl bZpNV3RJEOhD9J2HFdrkyqQgr9hxCEHaCi0jufzNuZyHYBYVDmN4Ct3bAbLyqpXYIWlT vxzcKcUm1oa5oY5vz0Uofqt5AFOyBTd7mGMF0PDO4iMxMbJSSdNAvBqrHqu63df+tgkr 59Nw== X-Forwarded-Encrypted: i=1; AJvYcCVklbqoSm3V2CW0fV8VSnWV76W7y50NAL6lvbjQ9wI/7qXxj/+yi3RMb7UNgHF7zlXbkdJmjGsfAFO2yVgqsFZAY8Dl3u8VOg== X-Gm-Message-State: AOJu0Ywz5dLPgDaM1EydBz+ZjulHqJ2tO29d/NybwIb3t1gzl+EsyJFN x+P/vChc/xzgYv7ZkKj7G1PFHUqu0wflgDtLfioN8oCLN308VVKU X-Received: by 2002:a05:6808:b07:b0:3c1:8498:239b with SMTP id s7-20020a0568080b0700b003c18498239bmr3584115oij.59.1709093537196; Tue, 27 Feb 2024 20:12:17 -0800 (PST) Received: from Thaum. (110-175-172-107.tpgi.com.au. [110.175.172.107]) by smtp.gmail.com with ESMTPSA id ls22-20020a056a00741600b006e533caee00sm4079108pfb.155.2024.02.27.20.12.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Feb 2024 20:12:16 -0800 (PST) Message-ID: <65deb2a0.050a0220.c8f98.2a88@mx.google.com> X-Google-Original-Message-ID: Date: Wed, 28 Feb 2024 15:12:12 +1100 From: Nathaniel Shead To: Patrick Palka Cc: Jason Merrill , gcc-patches@gcc.gnu.org, Nathan Sidwell Subject: [PATCH v3] c++/modules: Support lambdas attached to more places in modules [PR111710] References: <65c7ff51.170a0220.8dcc0.a404@mx.google.com> <65cf5356.620a0220.df9f9.aad0@mx.google.com> <30aadd67-ba0c-8714-7444-20ceff68ecea@idea> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <30aadd67-ba0c-8714-7444-20ceff68ecea@idea> X-Spam-Status: No, score=-11.2 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, URIBL_BLACK 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+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1791058137402958197 X-GMAIL-MSGID: 1792114512082616461 On Tue, Feb 27, 2024 at 11:59:46AM -0500, Patrick Palka wrote: > On Fri, 16 Feb 2024, Nathaniel Shead wrote: > > > On Tue, Feb 13, 2024 at 07:52:01PM -0500, Jason Merrill wrote: > > > On 2/10/24 17:57, Nathaniel Shead wrote: > > > > The fix for PR107398 weakened the restrictions that lambdas must belong > > > > to namespace scope. However this was not sufficient: we also need to > > > > allow lambdas keyed to FIELD_DECLs or PARM_DECLs. > > > > > > I wonder about keying such lambdas to the class and function, respectively, > > > rather than specifically to the field or parameter, but I suppose it doesn't > > > matter. > > > > I did some more testing and realised my testcase didn't properly > > exercise whether I'd properly deduplicated or not, and an improved > > testcase proved that actually keying to the field rather than the class > > did cause issues. (Parameter vs. function doesn't seem to have mattered > > however.) > > > > Here's an updated patch that fixes this, and includes the changes for > > lambdas in base classes that I'd had as a separate patch earlier. I've > > also added some concepts testcases just in case. > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk? > > > > -- >8 -- > > > > The fix for PR107398 weakened the restrictions that lambdas must belong > > to namespace scope. However this was not sufficient: we also need to > > allow lambdas attached to FIELD_DECLs, PARM_DECLs, and TYPE_DECLs. > > > > For field decls we key the lambda to its class rather than the field > > itself. This avoids some errors with deduplicating fields. > > > > Additionally, by [basic.link] p15.2 a lambda defined anywhere in a > > class-specifier should not be TU-local, which includes base-class > > declarations, so ensure that lambdas declared there are keyed > > appropriately as well. > > > > Because this now requires 'DECL_MODULE_KEYED_DECLS_P' to be checked on a > > fairly large number of different kinds of DECLs, and that in general > > it's safe to just get 'false' as a result of a check on an unexpected > > DECL type, this patch also removes the tree checking from the accessor. > > > > Finally, to handle deduplicating templated lambda fields, we need to > > ensure that we can determine that two lambdas from different field decls > > match. The modules code does not attempt to deduplicate expression > > nodes, which causes issues as the LAMBDA_EXPRs are then considered to be > > different. However, rather than checking the LAMBDA_EXPR directly we can > > instead check its type: the generated RECORD_TYPE for a LAMBDA_EXPR must > > also be unique, and /is/ deduplicated on import, so we can just check > > for that instead. > > We probably should be deduplicating LAMBDA_EXPR on stream-in, perhaps > something like > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc > index e8eabb1f6f9..1b2ba2e0fa8 100644 > --- a/gcc/cp/module.cc > +++ b/gcc/cp/module.cc > @@ -9183,6 +9183,13 @@ trees_in::tree_value () > return NULL_TREE; > } > > + if (TREE_CODE (t) == LAMBDA_EXPR > + && CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (t))) > + { > + existing = CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (t)); > + back_refs[~tag] = existing; > + } > + > dump (dumper::TREE) && dump ("Read tree:%d %C:%N", tag, TREE_CODE (t), t); > > if (TREE_CODE (existing) == INTEGER_CST && !TREE_OVERFLOW (existing)) > > would suffice? If not we probably need to take inspiration from the > TREE_BINFO streaming, and handle LAMBDA_EXPR similarly.. > Ah yup, right, that makes more sense. Your suggestion seems to work, thanks! Here's an updated patch. Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk? -- >8 -- The fix for PR107398 weakened the restrictions that lambdas must belong to namespace scope. However this was not sufficient: we also need to allow lambdas attached to FIELD_DECLs, PARM_DECLs, and TYPE_DECLs. For field decls we key the lambda to its class rather than the field itself. This avoids some errors with deduplicating fields. Additionally, by [basic.link] p15.2 a lambda defined anywhere in a class-specifier should not be TU-local, which includes base-class declarations, so ensure that lambdas declared there are keyed appropriately as well. Because this now requires 'DECL_MODULE_KEYED_DECLS_P' to be checked on a fairly large number of different kinds of DECLs, and that in general it's safe to just get 'false' as a result of a check on an unexpected DECL type, this patch also removes the tree checking from the accessor. Finally, to handle deduplicating templated lambda fields, we need to ensure that we can determine that two lambdas from different field decls match, so we ensure that we deduplicate LAMBDA_EXPRs on stream in. PR c++/111710 gcc/cp/ChangeLog: * cp-tree.h (DECL_MODULE_KEYED_DECLS_P): Remove tree checking. (struct lang_decl_base): Update comments and fix whitespace. * module.cc (trees_out::lang_decl_bools): Always write module_keyed_decls_p flag... (trees_in::lang_decl_bools): ...and always read it. (trees_out::decl_value): Handle all kinds of keyed decls. (trees_in::decl_value): Likewise. (trees_in::tree_value): Deduplicate LAMBDA_EXPRs. (maybe_key_decl): Also support lambdas attached to fields, parameters, and types. Key lambdas attached to fields to their class. (trees_out::get_merge_kind): Likewise. (trees_out::key_mergeable): Likewise. (trees_in::key_mergeable): Support keyed decls in a TYPE_DECL container. * parser.cc (cp_parser_class_head): Start a lambda scope when parsing base classes. gcc/testsuite/ChangeLog: * g++.dg/modules/lambda-7.h: New test. * g++.dg/modules/lambda-7_a.H: New test. * g++.dg/modules/lambda-7_b.C: New test. * g++.dg/modules/lambda-7_c.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Patrick Palka --- gcc/cp/cp-tree.h | 26 +++--- gcc/cp/module.cc | 101 +++++++++++++--------- gcc/cp/parser.cc | 10 ++- gcc/testsuite/g++.dg/modules/lambda-7.h | 42 +++++++++ gcc/testsuite/g++.dg/modules/lambda-7_a.H | 4 + gcc/testsuite/g++.dg/modules/lambda-7_b.C | 5 ++ gcc/testsuite/g++.dg/modules/lambda-7_c.C | 41 +++++++++ 7 files changed, 174 insertions(+), 55 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/lambda-7.h create mode 100644 gcc/testsuite/g++.dg/modules/lambda-7_a.H create mode 100644 gcc/testsuite/g++.dg/modules/lambda-7_b.C create mode 100644 gcc/testsuite/g++.dg/modules/lambda-7_c.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 334c11396c2..04c3aa6cd91 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1773,9 +1773,8 @@ check_constraint_info (tree t) (DECL_LANG_SPECIFIC (DECL_MODULE_CHECK (NODE))->u.base.module_entity_p) /* DECL that has attached decls for ODR-relatedness. */ -#define DECL_MODULE_KEYED_DECLS_P(NODE) \ - (DECL_LANG_SPECIFIC (TREE_CHECK2(NODE,FUNCTION_DECL,VAR_DECL))\ - ->u.base.module_keyed_decls_p) +#define DECL_MODULE_KEYED_DECLS_P(NODE) \ + (DECL_LANG_SPECIFIC (DECL_MODULE_CHECK (NODE))->u.base.module_keyed_decls_p) /* Whether this is an exported DECL. Held on any decl that can appear at namespace scope (function, var, type, template, const or @@ -2887,21 +2886,20 @@ struct GTY(()) lang_decl_base { unsigned friend_or_tls : 1; /* var, fn, type or template */ unsigned unknown_bound_p : 1; /* var */ unsigned odr_used : 1; /* var or fn */ - unsigned concept_p : 1; /* applies to vars and functions */ + unsigned concept_p : 1; /* applies to vars and functions */ unsigned var_declared_inline_p : 1; /* var */ unsigned dependent_init_p : 1; /* var */ - /* The following apply to VAR, FUNCTION, TYPE, CONCEPT, & NAMESPACE + /* The following four apply to VAR, FUNCTION, TYPE, CONCEPT, & NAMESPACE decls. */ - unsigned module_purview_p : 1; // in named-module purview - unsigned module_attach_p : 1; // attached to named module - unsigned module_import_p : 1; /* from an import */ - unsigned module_entity_p : 1; /* is in the entitity ary & - hash. */ - /* VAR_DECL or FUNCTION_DECL has keyed decls. */ - unsigned module_keyed_decls_p : 1; - - /* 12 spare bits. */ + unsigned module_purview_p : 1; /* in named-module purview */ + unsigned module_attach_p : 1; /* attached to named module */ + unsigned module_import_p : 1; /* from an import */ + unsigned module_entity_p : 1; /* is in the entitity ary & hash */ + + unsigned module_keyed_decls_p : 1; /* has keys, applies to all decls */ + + /* 11 spare bits. */ }; /* True for DECL codes which have template info and access. */ diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 106af7bdb3e..1b2ba2e0fa8 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -5664,8 +5664,7 @@ trees_out::lang_decl_bools (tree t) want to mark them as in module purview. */ WB (lang->u.base.module_purview_p && !header_module_p ()); WB (lang->u.base.module_attach_p); - if (VAR_OR_FUNCTION_DECL_P (t)) - WB (lang->u.base.module_keyed_decls_p); + WB (lang->u.base.module_keyed_decls_p); switch (lang->u.base.selector) { default: @@ -5738,8 +5737,7 @@ trees_in::lang_decl_bools (tree t) RB (lang->u.base.dependent_init_p); RB (lang->u.base.module_purview_p); RB (lang->u.base.module_attach_p); - if (VAR_OR_FUNCTION_DECL_P (t)) - RB (lang->u.base.module_keyed_decls_p); + RB (lang->u.base.module_keyed_decls_p); switch (lang->u.base.selector) { default: @@ -7871,8 +7869,7 @@ trees_out::decl_value (tree decl, depset *dep) install_entity (decl, dep); } - if (VAR_OR_FUNCTION_DECL_P (inner) - && DECL_LANG_SPECIFIC (inner) + if (DECL_LANG_SPECIFIC (inner) && DECL_MODULE_KEYED_DECLS_P (inner) && !is_key_order ()) { @@ -8172,8 +8169,7 @@ trees_in::decl_value () bool installed = install_entity (existing); bool is_new = existing == decl; - if (VAR_OR_FUNCTION_DECL_P (inner) - && DECL_LANG_SPECIFIC (inner) + if (DECL_LANG_SPECIFIC (inner) && DECL_MODULE_KEYED_DECLS_P (inner)) { /* Read and maybe install the attached entities. */ @@ -9187,6 +9183,13 @@ trees_in::tree_value () return NULL_TREE; } + if (TREE_CODE (t) == LAMBDA_EXPR + && CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (t))) + { + existing = CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (t)); + back_refs[~tag] = existing; + } + dump (dumper::TREE) && dump ("Read tree:%d %C:%N", tag, TREE_CODE (t), t); if (TREE_CODE (existing) == INTEGER_CST && !TREE_OVERFLOW (existing)) @@ -10484,12 +10487,17 @@ trees_out::get_merge_kind (tree decl, depset *dep) if (tree scope = LAMBDA_EXPR_EXTRA_SCOPE (CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (decl)))) - if (TREE_CODE (scope) == VAR_DECL - && DECL_MODULE_KEYED_DECLS_P (scope)) - { - mk = MK_keyed; - break; - } + { + /* Lambdas attached to fields are keyed to its class. */ + if (TREE_CODE (scope) == FIELD_DECL) + scope = TYPE_NAME (DECL_CONTEXT (scope)); + if (DECL_LANG_SPECIFIC (scope) + && DECL_MODULE_KEYED_DECLS_P (scope)) + { + mk = MK_keyed; + break; + } + } if (RECORD_OR_UNION_TYPE_P (ctx)) { @@ -10789,7 +10797,13 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, gcc_checking_assert (LAMBDA_TYPE_P (TREE_TYPE (inner))); tree scope = LAMBDA_EXPR_EXTRA_SCOPE (CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (inner))); - gcc_checking_assert (TREE_CODE (scope) == VAR_DECL); + gcc_checking_assert (TREE_CODE (scope) == VAR_DECL + || TREE_CODE (scope) == FIELD_DECL + || TREE_CODE (scope) == PARM_DECL + || TREE_CODE (scope) == TYPE_DECL); + /* Lambdas attached to fields are keyed to the class. */ + if (TREE_CODE (scope) == FIELD_DECL) + scope = TYPE_NAME (DECL_CONTEXT (scope)); auto *root = keyed_table->get (scope); unsigned ix = root->length (); /* If we don't find it, we'll write a really big number @@ -11067,6 +11081,26 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, } } } + else if (mk == MK_keyed + && DECL_LANG_SPECIFIC (name) + && DECL_MODULE_KEYED_DECLS_P (name)) + { + gcc_checking_assert (TREE_CODE (container) == NAMESPACE_DECL + || TREE_CODE (container) == TYPE_DECL); + if (auto *set = keyed_table->get (name)) + if (key.index < set->length ()) + { + existing = (*set)[key.index]; + if (existing) + { + gcc_checking_assert + (DECL_IMPLICIT_TYPEDEF_P (existing)); + if (inner != decl) + existing + = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (existing)); + } + } + } else switch (TREE_CODE (container)) { @@ -11074,27 +11108,8 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, gcc_unreachable (); case NAMESPACE_DECL: - if (mk == MK_keyed) - { - if (DECL_LANG_SPECIFIC (name) - && VAR_OR_FUNCTION_DECL_P (name) - && DECL_MODULE_KEYED_DECLS_P (name)) - if (auto *set = keyed_table->get (name)) - if (key.index < set->length ()) - { - existing = (*set)[key.index]; - if (existing) - { - gcc_checking_assert - (DECL_IMPLICIT_TYPEDEF_P (existing)); - if (inner != decl) - existing - = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (existing)); - } - } - } - else if (is_attached - && !(state->is_module () || state->is_partition ())) + if (is_attached + && !(state->is_module () || state->is_partition ())) kind = "unique"; else { @@ -18984,11 +18999,19 @@ maybe_key_decl (tree ctx, tree decl) if (!modules_p ()) return; - // FIXME: For now just deal with lambdas attached to var decls. - // This might be sufficient? - if (TREE_CODE (ctx) != VAR_DECL) + /* We only need to deal with lambdas attached to var, field, + parm, or type decls. */ + if (TREE_CODE (ctx) != VAR_DECL + && TREE_CODE (ctx) != FIELD_DECL + && TREE_CODE (ctx) != PARM_DECL + && TREE_CODE (ctx) != TYPE_DECL) return; + /* For fields, key it to the containing type to handle deduplication + correctly. */ + if (TREE_CODE (ctx) == FIELD_DECL) + ctx = TYPE_NAME (DECL_CONTEXT (ctx)); + if (!keyed_table) keyed_table = new keyed_map_t (EXPERIMENT (1, 400)); diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index b2ed2baa3a5..3ee9d49fb8e 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -27678,10 +27678,16 @@ cp_parser_class_head (cp_parser* parser, if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) { if (type) - pushclass (type); + { + pushclass (type); + start_lambda_scope (TYPE_NAME (type)); + } bases = cp_parser_base_clause (parser); if (type) - popclass (); + { + finish_lambda_scope (); + popclass (); + } } else bases = NULL_TREE; diff --git a/gcc/testsuite/g++.dg/modules/lambda-7.h b/gcc/testsuite/g++.dg/modules/lambda-7.h new file mode 100644 index 00000000000..6f6080c1324 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lambda-7.h @@ -0,0 +1,42 @@ +struct S { + int (*a)(int) = [](int x) { return x * 2; }; + + int b(int x, int (*f)(int) = [](int x) { return x * 3; }) { + return f(x); + } + + static int c(int x, int (*f)(int) = [](int x) { return x * 4; }) { + return f(x); + } +}; + +inline int d(int x, int (*f)(int) = [](int x) { return x * 5; }) { + return f(x); +} + +// unevaluated lambdas +#if __cplusplus >= 202002L +struct E : decltype([](int x) { return x * 6; }) { + decltype([](int x) { return x * 7; }) f; +}; + +template +struct G : decltype([](int x) { return x * 8; }) { + decltype([](int x) { return x * 9; }) h; +}; + +template <> +struct G : decltype([](int x) { return x * 10; }) { + decltype([](int x) { return x * 11; }) i; +}; +#endif + +// concepts +#if __cpp_concepts >= 201907L +template +concept J = requires { []{ T(); }; }; + +template +concept K = []{ return sizeof(T) == 1; }(); +#endif + diff --git a/gcc/testsuite/g++.dg/modules/lambda-7_a.H b/gcc/testsuite/g++.dg/modules/lambda-7_a.H new file mode 100644 index 00000000000..5197114f76c --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lambda-7_a.H @@ -0,0 +1,4 @@ +// { dg-additional-options "-fmodule-header -Wno-subobject-linkage" } +// { dg-module-cmi {} } + +#include "lambda-7.h" diff --git a/gcc/testsuite/g++.dg/modules/lambda-7_b.C b/gcc/testsuite/g++.dg/modules/lambda-7_b.C new file mode 100644 index 00000000000..2d781e93067 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lambda-7_b.C @@ -0,0 +1,5 @@ +// { dg-additional-options "-fmodules-ts -fno-module-lazy -Wno-subobject-linkage" } +// Test for ODR deduplication + +#include "lambda-7.h" +import "lambda-7_a.H"; diff --git a/gcc/testsuite/g++.dg/modules/lambda-7_c.C b/gcc/testsuite/g++.dg/modules/lambda-7_c.C new file mode 100644 index 00000000000..f283681fa96 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lambda-7_c.C @@ -0,0 +1,41 @@ +// { dg-module-do run } +// { dg-additional-options "-fmodules-ts -fno-module-lazy -Wno-subobject-linkage" } + +import "lambda-7_a.H"; + +int main() { + S s; + if (s.a(10) != 20) + __builtin_abort(); + if (s.b(10) != 30) + __builtin_abort(); + if (s.c(10) != 40) + __builtin_abort(); + if (d(10) != 50) + __builtin_abort(); + +#if __cplusplus >= 202002L + E e; + if (e(10) != 60) + __builtin_abort(); + if (e.f(10) != 70) + __builtin_abort(); + + G g1; + if (g1(10) != 80) + __builtin_abort(); + if (g1.h(10) != 90) + __builtin_abort(); + + G g2; + if (g2(10) != 100) + __builtin_abort(); + if (g2.i(10) != 110) + __builtin_abort(); +#endif + +#if __cpp_concepts >= 201907L + static_assert(J); + static_assert(K); +#endif +}