https://gcc.gnu.org/g:4c01f40985eafccc3dd058441325b58009defd09

commit r15-7203-g4c01f40985eafccc3dd058441325b58009defd09
Author: Nathaniel Shead <nathanielosh...@gmail.com>
Date:   Sun Jan 5 23:45:05 2025 +1100

    c++/modules: Diagnose TU-local lambdas, give mangling scope to lambdas in 
concepts
    
    This fills in a hole left in r15-6378-g9016c5ac94c557 with regards to
    detection of TU-local lambdas.  Now that LAMBDA_EXPR_EXTRA_SCOPE is
    properly set for most lambdas we can use it to detect lambdas that are
    TU-local.
    
    CWG2988 suggests that lambdas in concept definitions should not be
    considered TU-local, since they are always unevaluated and should never
    be emitted. This patch gives these lambdas a mangling scope (though it
    will never be actually used in name mangling).
    
            PR c++/116568
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (finish_concept_definition): Adjust parameters.
            (start_concept_definition): Declare.
            * module.cc (depset::hash::is_tu_local_entity): Use
            LAMBDA_EXPR_EXTRA_SCOPE to detect TU-local lambdas.
            * parser.cc (cp_parser_concept_definition): Start a lambda scope
            for concept definitions.
            * pt.cc (tsubst_lambda_expr): Namespace-scope lambdas may now
            have extra scope.
            (finish_concept_definition): Split into...
            (start_concept_definition): ...this new function.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/modules/internal-4_b.C: Remove XFAIL, add lambda alias
            testcase.
            * g++.dg/modules/lambda-9.h: New test.
            * g++.dg/modules/lambda-9_a.H: New test.
            * g++.dg/modules/lambda-9_b.C: New test.
    
    Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
    Reviewed-by: Jason Merrill <ja...@redhat.com>

Diff:
---
 gcc/cp/cp-tree.h                            |  3 ++-
 gcc/cp/module.cc                            | 15 +++++++++------
 gcc/cp/parser.cc                            | 14 +++++++++++++-
 gcc/cp/pt.cc                                | 21 +++++++++++++++------
 gcc/testsuite/g++.dg/modules/internal-4_b.C |  5 +++--
 gcc/testsuite/g++.dg/modules/lambda-9.h     |  3 +++
 gcc/testsuite/g++.dg/modules/lambda-9_a.H   |  4 ++++
 gcc/testsuite/g++.dg/modules/lambda-9_b.C   |  6 ++++++
 8 files changed, 55 insertions(+), 16 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5d79cf927d92..4aa9f9f9aa91 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8689,7 +8689,8 @@ struct diagnosing_failed_constraint
 extern cp_expr finish_constraint_or_expr       (location_t, cp_expr, cp_expr);
 extern cp_expr finish_constraint_and_expr      (location_t, cp_expr, cp_expr);
 extern cp_expr finish_constraint_primary_expr  (cp_expr);
-extern tree finish_concept_definition          (cp_expr, tree, tree);
+extern tree start_concept_definition           (cp_expr);
+extern tree finish_concept_definition          (tree, tree, tree);
 extern tree combine_constraint_expressions      (tree, tree);
 extern tree append_constraint                  (tree, tree);
 extern tree get_constraints                     (const_tree);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 17215594fd3f..1c1eb2e37e2d 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -11329,7 +11329,8 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree 
decl, tree inner,
            gcc_checking_assert (TREE_CODE (scope) == VAR_DECL
                                 || TREE_CODE (scope) == FIELD_DECL
                                 || TREE_CODE (scope) == PARM_DECL
-                                || TREE_CODE (scope) == TYPE_DECL);
+                                || TREE_CODE (scope) == TYPE_DECL
+                                || TREE_CODE (scope) == CONCEPT_DECL);
            /* Lambdas attached to fields are keyed to the class.  */
            if (TREE_CODE (scope) == FIELD_DECL)
              scope = TYPE_NAME (DECL_CONTEXT (scope));
@@ -13435,9 +13436,10 @@ depset::hash::is_tu_local_entity (tree decl, bool 
explain/*=false*/)
       tree main_decl = TYPE_MAIN_DECL (type);
       if (!DECL_CLASS_SCOPE_P (main_decl)
          && !decl_function_context (main_decl)
-         /* FIXME: Lambdas defined outside initializers.  We'll need to more
-            thoroughly set LAMBDA_TYPE_EXTRA_SCOPE to check this.  */
-         && !LAMBDA_TYPE_P (type))
+         /* LAMBDA_EXPR_EXTRA_SCOPE will be set for lambdas defined in
+            contexts where they would not be TU-local.  */
+         && !(LAMBDA_TYPE_P (type)
+              && LAMBDA_TYPE_EXTRA_SCOPE (type)))
        {
          if (explain)
            inform (loc, "%qT has no name and is not defined within a class, "
@@ -20309,11 +20311,12 @@ maybe_key_decl (tree ctx, tree decl)
     return;
 
   /* We only need to deal with lambdas attached to var, field,
-     parm, or type decls.  */
+     parm, type, or concept decls.  */
   if (TREE_CODE (ctx) != VAR_DECL
       && TREE_CODE (ctx) != FIELD_DECL
       && TREE_CODE (ctx) != PARM_DECL
-      && TREE_CODE (ctx) != TYPE_DECL)
+      && TREE_CODE (ctx) != TYPE_DECL
+      && TREE_CODE (ctx) != CONCEPT_DECL)
     return;
 
   /* For fields, key it to the containing type to handle deduplication
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 2f88e5fcd914..7ddb7f119a4c 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -31830,8 +31830,20 @@ cp_parser_concept_definition (cp_parser *parser)
       return error_mark_node;
     }
 
+  tree decl = start_concept_definition (id);
+  if (decl == error_mark_node)
+    {
+      cp_parser_skip_to_end_of_statement (parser);
+      cp_parser_consume_semicolon_at_end_of_statement (parser);
+      return error_mark_node;
+    }
+
   processing_constraint_expression_sentinel parsing_constraint;
+
+  start_lambda_scope (decl);
   tree init = cp_parser_constraint_expression (parser);
+  finish_lambda_scope ();
+
   if (init == error_mark_node)
     cp_parser_skip_to_end_of_statement (parser);
 
@@ -31839,7 +31851,7 @@ cp_parser_concept_definition (cp_parser *parser)
      but continue as if it were.  */
   cp_parser_consume_semicolon_at_end_of_statement (parser);
 
-  return finish_concept_definition (id, init, attrs);
+  return finish_concept_definition (decl, init, attrs);
 }
 
 // -------------------------------------------------------------------------- 
//
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 0f739d89b35c..6442ae947c32 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -20231,7 +20231,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 
   if (LAMBDA_EXPR_EXTRA_SCOPE (t))
     record_lambda_scope (r);
-  else if (TYPE_NAMESPACE_SCOPE_P (TREE_TYPE (t)))
+  if (TYPE_NAMESPACE_SCOPE_P (TREE_TYPE (t)))
     /* If we're pushed into another scope (PR105652), fix it.  */
     TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_NAME (type))
       = TYPE_CONTEXT (TREE_TYPE (t));
@@ -30027,12 +30027,10 @@ placeholder_type_constraint_dependent_p (tree t)
   return false;
 }
 
-/* Build and return a concept definition. Like other templates, the
-   CONCEPT_DECL node is wrapped by a TEMPLATE_DECL.  This returns the
-   the TEMPLATE_DECL. */
+/* Prepare and return a concept definition.  */
 
 tree
-finish_concept_definition (cp_expr id, tree init, tree attrs)
+start_concept_definition (cp_expr id)
 {
   gcc_assert (identifier_p (id));
   gcc_assert (processing_template_decl);
@@ -30064,9 +30062,20 @@ finish_concept_definition (cp_expr id, tree init, tree 
attrs)
   /* Initially build the concept declaration; its type is bool.  */
   tree decl = build_lang_decl_loc (loc, CONCEPT_DECL, *id, boolean_type_node);
   DECL_CONTEXT (decl) = current_scope ();
-  DECL_INITIAL (decl) = init;
   TREE_PUBLIC (decl) = true;
 
+  return decl;
+}
+
+/* Finish building a concept definition. Like other templates, the
+   CONCEPT_DECL node is wrapped by a TEMPLATE_DECL.  This returns the
+   the TEMPLATE_DECL. */
+
+tree
+finish_concept_definition (tree decl, tree init, tree attrs)
+{
+  DECL_INITIAL (decl) = init;
+
   if (attrs)
     cplus_decl_attributes (&decl, attrs, 0);
 
diff --git a/gcc/testsuite/g++.dg/modules/internal-4_b.C 
b/gcc/testsuite/g++.dg/modules/internal-4_b.C
index 86bec294fc83..81fc65a69bdd 100644
--- a/gcc/testsuite/g++.dg/modules/internal-4_b.C
+++ b/gcc/testsuite/g++.dg/modules/internal-4_b.C
@@ -80,13 +80,14 @@ void in_function_body() { struct {} x; }  // OK
 auto in_initializer = []{};  // OK
 
 #if __cplusplus >= 202002L
-decltype([]{}) d_lambda;  // { dg-error "exposes TU-local entity" "" { xfail 
*-*-* } }
+decltype([]{}) d_lambda;  // { dg-error "exposes TU-local entity" "" { target 
c++20 } }
+using alias_lambda = decltype([]{});  // { dg-error "exposes TU-local entity" 
"" { target c++20 } }
 
 template <typename T>
 concept in_constraint_expression = requires {
   // Strictly by the standard this is currently ill-formed
   // (this is a constraint-expression not an initializer)
-  // but I don't think that is intended.
+  // but I don't think that is intended; see CWG2988.
   []{};  // { dg-bogus "exposes TU-local entity" }
 };
 #endif
diff --git a/gcc/testsuite/g++.dg/modules/lambda-9.h 
b/gcc/testsuite/g++.dg/modules/lambda-9.h
new file mode 100644
index 000000000000..fccd36da6d13
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-9.h
@@ -0,0 +1,3 @@
+// CWG2988
+template <typename T>
+concept C = requires { []{}; };
diff --git a/gcc/testsuite/g++.dg/modules/lambda-9_a.H 
b/gcc/testsuite/g++.dg/modules/lambda-9_a.H
new file mode 100644
index 000000000000..da0fa3b31f2d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-9_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodule-header -std=c++20" }
+// { dg-module-cmi {} }
+
+#include "lambda-9.h"
diff --git a/gcc/testsuite/g++.dg/modules/lambda-9_b.C 
b/gcc/testsuite/g++.dg/modules/lambda-9_b.C
new file mode 100644
index 000000000000..6f2186421f7d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-9_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules -std=c++20 -fno-module-lazy" }
+
+#include "lambda-9.h"
+import "lambda-9_a.H";
+
+static_assert(C<int>);

Reply via email to