On 2/10/24 17:57, Nathaniel Shead wrote:
Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

Or should I re-introduce the tree checking and just add checks for the
new kinds of declarations that could be have keyed decls?

This way is fine.

-- >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 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.

OK with the comment adjustment below.

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.

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): Also handle keyed decls on decls other
        than VAR_DECL or FUNCTION_DECL.
        (trees_in::decl_value): Likewise.
        (trees_out::get_merge_kind): Likewise.
        (maybe_key_decl): Also handle lambdas attached to FIELD_DECLs
        and PARM_DECLS.
        (trees_out::key_mergeable): Likewise.
        (trees_in::key_mergeable): Support keyed decls in a TYPE_DECL
        container.

gcc/testsuite/ChangeLog:

        * g++.dg/modules/lambda-7_a.C: New test.
        * g++.dg/modules/lambda-7_b.C: New test.

Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
---
  gcc/cp/cp-tree.h                          | 23 ++++----
  gcc/cp/module.cc                          | 70 +++++++++++------------
  gcc/testsuite/g++.dg/modules/lambda-7_a.C | 20 +++++++
  gcc/testsuite/g++.dg/modules/lambda-7_b.C | 16 ++++++
  4 files changed, 81 insertions(+), 48 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/modules/lambda-7_a.C
  create mode 100644 gcc/testsuite/g++.dg/modules/lambda-7_b.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 334c11396c2..6ab82dc2d0f 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,19 @@ 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
       decls.  */

With your reformatting this comment now seems to apply to module_keyed_decls_p, which I don't think you mean. Maybe just adjust this comment to say "the following 4"?

-  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 560d8f3b614..9742bca922c 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:
@@ -7869,8 +7867,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 ())
      {
@@ -8170,8 +8167,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.  */
@@ -10482,8 +10478,7 @@ 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))
+               if (DECL_MODULE_KEYED_DECLS_P (scope))
                  {
                    mk = MK_keyed;
                    break;
@@ -10787,7 +10782,9 @@ 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);
            auto *root = keyed_table->get (scope);
            unsigned ix = root->length ();
            /* If we don't find it, we'll write a really big number
@@ -11065,6 +11062,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))
          {
@@ -11072,27 +11089,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
              {
@@ -18981,9 +18979,11 @@ 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,
+     or parm decls.  */
+  if (TREE_CODE (ctx) != VAR_DECL
+      && TREE_CODE (ctx) != FIELD_DECL
+      && TREE_CODE (ctx) != PARM_DECL)
      return;
if (!keyed_table)
diff --git a/gcc/testsuite/g++.dg/modules/lambda-7_a.C 
b/gcc/testsuite/g++.dg/modules/lambda-7_a.C
new file mode 100644
index 00000000000..289285cd926
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-7_a.C
@@ -0,0 +1,20 @@
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi foo }
+
+export module foo;
+
+export 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);
+  }
+};
+
+export inline int d(int x, int (*f)(int) = [](int x) { return x * 5; }) {
+  return f(x);
+}
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..a8762399ee1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-7_b.C
@@ -0,0 +1,16 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+import foo;
+
+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();
+}

Reply via email to