aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/module.cc
diff options
context:
space:
mode:
authorNathaniel Shead <nathanieloshead@gmail.com>2024-02-16 15:52:48 +1100
committerNathaniel Shead <nathanieloshead@gmail.com>2024-02-29 16:04:03 +1100
commit3685fae23bb00898749dfc155212c9c5cd3a0980 (patch)
tree478deafad1636edbb6d681254219ab4e2df9359c /gcc/cp/module.cc
parentfd07a29e39f5347d6cef3e7042a32306f97a1719 (diff)
downloadgcc-3685fae23bb00898749dfc155212c9c5cd3a0980.zip
gcc-3685fae23bb00898749dfc155212c9c5cd3a0980.tar.gz
gcc-3685fae23bb00898749dfc155212c9c5cd3a0980.tar.bz2
c++: Support lambdas attached to more places in modules [PR111710]
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. Otherwise we can run into issues when deduplicating the lambda's TYPE_DECL, because when loading its context we load the containing field before we've deduplicated the keyed lambda, causing mismatches; by keying to the class instead we defer checking keyed declarations until deduplication has completed. 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 also 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 <nathanieloshead@gmail.com> Reviewed-by: Patrick Palka <ppalka@redhat.com> Reviewed-by: Jason Merrill <jason@redhat.com>
Diffstat (limited to 'gcc/cp/module.cc')
-rw-r--r--gcc/cp/module.cc101
1 files changed, 62 insertions, 39 deletions
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 106af7b..1b2ba2e 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));