Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
reasonable?

-- >8 --

It turns out that with modules we can call mangle_decl recursively,
which is a problem because the global mangling state isn't recursion
aware.  The recursion happens from write_closure_type_name, which calls
lambda function, which performs name lookup, which can trigger lazy
loading, which can call maybe_clone_body for a newly loaded function,
which can inspect DECL_ASSEMBLER_NAME, which enters mangling.  This was
observed when using fmtlib as a module with trunk, and leads to a bogus
"mangling conflicts with a previous mangle error" followed by an ICE
from cdtor_comdat_group due to a mangling mismatch.

I considered making our mangling state recursion-aware, but it seems
this lambda_function call is the only source of name lookup during
mangling, and in turn the only source of potential recursion with
modules so perhaps it's better to just address that.  To that end, this
patch adds a new field to LAMBDA_EXPR holding the op() of the closure
type, so that lambda_function can just inspect this field rather than
having to perform name lookup.  With this patch fmtlib can be
successfully imported as a module (with a few minor source tweaks).

In passing this patch adds streaming of LAMBDA_EXPR_REGEN_INFO which I
noticed is missing.

gcc/cp/ChangeLog:

        * cp-tree.h (LAMBDA_EXPR_FUNCTION): Define.
        (tree_lambda_expr::function): New member.
        * lambda.cc (lambda_function): Use LAMBDA_EXPR_FUNCTION instead
        of performing name lookup.
        * module.cc (trees_out::core_vals): Stream LAMBDA_EXPR_REGEN_INFO
        and LAMBDA_EXPR_FUNCTION.
        (trees_in::core_vals): Likewise.
        * parser.cc (cp_parser_lambda_declarator_opt): Set
        LAMBDA_EXPR_FUNCTION.
        * pt.cc (tsubst_lambda_expr): Likewise.
---
 gcc/cp/cp-tree.h |  5 +++++
 gcc/cp/lambda.cc | 20 +++++---------------
 gcc/cp/module.cc |  4 ++++
 gcc/cp/parser.cc |  1 +
 gcc/cp/pt.cc     |  1 +
 5 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 969c7239c97..3bef35fd90c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1543,6 +1543,10 @@ enum cp_lambda_default_capture_mode_type {
 #define LAMBDA_EXPR_CLOSURE(NODE) \
   (TREE_TYPE (LAMBDA_EXPR_CHECK (NODE)))
 
+/* The op() of the lambda closure type as would be found by name lookup.  */
+#define LAMBDA_EXPR_FUNCTION(NODE) \
+  (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->function)
+
 struct GTY (()) tree_lambda_expr
 {
   struct tree_typed typed;
@@ -1550,6 +1554,7 @@ struct GTY (()) tree_lambda_expr
   tree this_capture;
   tree extra_scope;
   tree regen_info;
+  tree function;
   vec<tree, va_gc> *pending_proxies;
   location_t locus;
   enum cp_lambda_default_capture_mode_type default_capture_mode : 2;
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 1d37e5a52b9..c3ec9381c19 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -165,22 +165,12 @@ begin_lambda_type (tree lambda)
 tree
 lambda_function (tree lambda)
 {
-  tree type;
-  if (TREE_CODE (lambda) == LAMBDA_EXPR)
-    type = LAMBDA_EXPR_CLOSURE (lambda);
-  else
-    type = lambda;
-  gcc_assert (LAMBDA_TYPE_P (type));
-  /* Don't let debug_tree cause instantiation.  */
-  if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)
-      && !COMPLETE_OR_OPEN_TYPE_P (type))
+  if (CLASS_TYPE_P (lambda))
+    lambda = CLASSTYPE_LAMBDA_EXPR (lambda);
+  tree callop = LAMBDA_EXPR_FUNCTION (lambda);
+  if (!callop)
     return NULL_TREE;
-  lambda = lookup_member (type, call_op_identifier,
-                         /*protect=*/0, /*want_type=*/false,
-                         tf_warning_or_error);
-  if (lambda)
-    lambda = STRIP_TEMPLATE (get_first_fn (lambda));
-  return lambda;
+  return STRIP_TEMPLATE (callop);
 }
 
 /* True if EXPR is an expression whose type can be used directly in lambda
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 3c2fef0e3f4..7ae965d38e4 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -6317,6 +6317,8 @@ trees_out::core_vals (tree t)
       WT (((lang_tree_node *)t)->lambda_expression.capture_list);
       WT (((lang_tree_node *)t)->lambda_expression.this_capture);
       WT (((lang_tree_node *)t)->lambda_expression.extra_scope);
+      WT (((lang_tree_node *)t)->lambda_expression.regen_info);
+      WT (((lang_tree_node *)t)->lambda_expression.function);
       /* pending_proxies is a parse-time thing.  */
       gcc_assert (!((lang_tree_node *)t)->lambda_expression.pending_proxies);
       if (state)
@@ -6818,6 +6820,8 @@ trees_in::core_vals (tree t)
       RT (((lang_tree_node *)t)->lambda_expression.capture_list);
       RT (((lang_tree_node *)t)->lambda_expression.this_capture);
       RT (((lang_tree_node *)t)->lambda_expression.extra_scope);
+      RT (((lang_tree_node *)t)->lambda_expression.regen_info);
+      RT (((lang_tree_node *)t)->lambda_expression.function);
       /* lambda_expression.pending_proxies is NULL  */
       ((lang_tree_node *)t)->lambda_expression.locus
        = state->read_location (*this);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index c4292c49ce2..3fe975cc213 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -12111,6 +12111,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, 
tree lambda_expr)
     else if (parser->fully_implicit_function_template_p)
       fco = finish_fully_implicit_template (parser, fco);
 
+    LAMBDA_EXPR_FUNCTION (lambda_expr) = fco;
     finish_member_declaration (fco);
     record_lambda_scope_sig_discriminator (lambda_expr, fco);
 
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index f9abb21a9a2..5743b105af3 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -19719,6 +19719,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
          r = error_mark_node;
          goto out;
        }
+      LAMBDA_EXPR_FUNCTION (r) = inst;
       finish_member_declaration (inst);
       record_lambda_scope_sig_discriminator (r, inst);
 
-- 
2.43.0.561.g235986be82

Reply via email to