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 0291d456ff5..af99df2b79c 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -5662,8 +5662,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:
@@ -5736,8 +5735,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:
@@ -7867,8 +7865,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 ())
     {
@@ -8168,8 +8165,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.  */
@@ -10480,12 +10476,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))
 	      {
@@ -10785,7 +10786,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
@@ -11063,6 +11070,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))
 	  {
@@ -11070,27 +11097,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
 	      {
@@ -18980,11 +18988,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 9d0914435fb..95d59973b6d 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -27671,10 +27671,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/cp/tree.cc b/gcc/cp/tree.cc
index ad312710f68..ca598859b97 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -4239,8 +4239,8 @@ cp_tree_equal (tree t1, tree t2)
 				     DEFERRED_NOEXCEPT_ARGS (t2)));
 
     case LAMBDA_EXPR:
-      /* Two lambda-expressions are never considered equivalent.  */
-      return false;
+      /* Two lambda-expressions are only equivalent if their type is.  */
+      return TREE_TYPE (t1) == TREE_TYPE (t2);
 
     case TYPE_ARGUMENT_PACK:
     case NONTYPE_ARGUMENT_PACK:
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 <typename T>
+struct G : decltype([](int x) { return x * 8; }) {
+  decltype([](int x) { return x * 9; }) h;
+};
+
+template <>
+struct G<double> : decltype([](int x) { return x * 10; }) {
+  decltype([](int x) { return x * 11; }) i;
+};
+#endif
+
+// concepts
+#if __cpp_concepts >= 201907L
+template <typename T>
+concept J = requires { []{ T(); }; };
+
+template <typename T>
+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<int> g1;
+  if (g1(10) != 80)
+    __builtin_abort();
+  if (g1.h(10) != 90)
+    __builtin_abort();
+
+  G<double> g2;
+  if (g2(10) != 100)
+    __builtin_abort();
+  if (g2.i(10) != 110)
+    __builtin_abort();
+#endif
+
+#if __cpp_concepts >= 201907L
+  static_assert(J<char>);
+  static_assert(K<char>);
+#endif
+}
