aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/cp-tree.h7
-rw-r--r--gcc/cp/lambda.cc148
-rw-r--r--gcc/cp/mangle.cc8
-rw-r--r--gcc/cp/module.cc2
-rw-r--r--gcc/cp/parser.cc1
-rw-r--r--gcc/cp/pt.cc1
-rw-r--r--gcc/testsuite/g++.dg/abi/lambda-sig1-18.C34
-rw-r--r--gcc/testsuite/g++.dg/abi/lambda-sig1-18vs17.C40
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1-18.C26
-rw-r--r--libcc1/libcp1plugin.cc1
10 files changed, 265 insertions, 3 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 4c0bacb..d13bb3d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1501,9 +1501,12 @@ enum cp_lambda_default_capture_mode_type {
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->extra_scope)
/* Lambdas in the same extra scope might need a discriminating count.
- This is a single per-scope count. */
+ For ABI 17, we have single per-scope count, for ABI 18, we have
+ per-scope, per-signature numbering. */
#define LAMBDA_EXPR_SCOPE_ONLY_DISCRIMINATOR(NODE) \
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->discriminator_scope)
+#define LAMBDA_EXPR_SCOPE_SIG_DISCRIMINATOR(NODE) \
+ (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->discriminator_sig)
/* During parsing of the lambda, a vector of capture proxies which need
to be pushed once we're done processing a nested lambda. */
@@ -1533,6 +1536,7 @@ struct GTY (()) tree_lambda_expr
location_t locus;
enum cp_lambda_default_capture_mode_type default_capture_mode : 2;
unsigned discriminator_scope : 15; // Per-scope discriminator
+ unsigned discriminator_sig : 15; // Per-scope, per-signature discriminator
};
/* Non-zero if this template specialization has access violations that
@@ -7783,6 +7787,7 @@ extern void start_lambda_scope (tree decl);
extern void finish_lambda_scope (void);
extern void record_lambda_scope (tree lambda);
extern void record_lambda_scope_discriminator (tree lambda);
+extern void record_lambda_scope_sig_discriminator (tree lambda, tree fn);
extern tree start_lambda_function (tree fn, tree lambda_expr);
extern void finish_lambda_function (tree body);
extern bool regenerated_lambda_fn_p (tree);
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index d2673e2..c7a9268 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -1447,13 +1447,21 @@ is_lambda_ignored_entity (tree val)
/* Lambdas that appear in variable initializer or default argument
scope get that in their mangling, so we need to record it. Also,
multiple lambdas in the same scope may need a mangling
- discriminator. Record in the same data structure. */
+ discriminator. In ABI <= 17, there is a single per-scope sequence
+ number. In ABI >= 18, there are per-scope per-signature sequence
+ numbers. */
+struct GTY(()) lambda_sig_count
+{
+ tree fn; // The lambda fn whose sig this is.
+ unsigned count;
+};
struct GTY(()) lambda_discriminator
{
tree scope;
unsigned nesting; // Inside a function, VAR_DECLs get the function
// as scope. This counts that nesting.
unsigned count; // The per-scope counter.
+ vec<lambda_sig_count, va_gc> *discriminators; // Per-signature counters
};
// The current scope.
static GTY(()) lambda_discriminator lambda_scope;
@@ -1475,6 +1483,7 @@ start_lambda_scope (tree decl)
lambda_scope.scope = decl;
lambda_scope.nesting = 0;
lambda_scope.count = 0;
+ lambda_scope.discriminators = nullptr;
}
}
@@ -1504,6 +1513,116 @@ record_lambda_scope (tree lambda)
}
}
+// Compare lambda template heads TMPL_A and TMPL_B, used for both
+// templated lambdas, and template template parameters of said lambda.
+
+static bool
+compare_lambda_template_head (tree tmpl_a, tree tmpl_b)
+{
+ // We only need one level of template parms
+ tree inner_a = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl_a));
+ tree inner_b = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl_b));
+
+ // We only compare explicit template parms, ignoring trailing
+ // synthetic ones.
+ int len_a = TREE_VEC_LENGTH (inner_a);
+ int len_b = TREE_VEC_LENGTH (inner_b);
+
+ for (int ix = 0, len = MAX (len_a, len_b); ix != len; ix++)
+ {
+ tree parm_a = NULL_TREE;
+ if (ix < len_a)
+ {
+ parm_a = TREE_VEC_ELT (inner_a, ix);
+ if (parm_a == error_mark_node)
+ return false;
+ parm_a = TREE_VALUE (parm_a);
+ if (DECL_VIRTUAL_P (parm_a))
+ parm_a = NULL_TREE;
+ }
+
+ tree parm_b = NULL_TREE;
+ if (ix < len_b)
+ {
+ parm_b = TREE_VEC_ELT (inner_b, ix);
+ if (parm_b == error_mark_node)
+ return false;
+ parm_b = TREE_VALUE (parm_b);
+ if (DECL_VIRTUAL_P (parm_b))
+ parm_b = NULL_TREE;
+ }
+
+ if (!parm_a && !parm_b)
+ // we're done
+ break;
+
+ if (!(parm_a && parm_b))
+ return false;
+
+ if (TREE_CODE (parm_a) != TREE_CODE (parm_b))
+ return false;
+
+ if (TREE_CODE (parm_a) == PARM_DECL)
+ {
+ if (TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm_a))
+ != TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm_b)))
+ return false;
+
+ if (!same_type_p (TREE_TYPE (parm_a), TREE_TYPE (parm_b)))
+ return false;
+ }
+ else
+ {
+ if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm_a))
+ != TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm_b)))
+ return false;
+
+ if (TREE_CODE (parm_a) != TEMPLATE_DECL)
+ gcc_checking_assert (TREE_CODE (parm_a) == TYPE_DECL);
+ else if (!compare_lambda_template_head (parm_a, parm_b))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Compare lambda signatures FN_A and FN_B, they may be TEMPLATE_DECLs too.
+
+static bool
+compare_lambda_sig (tree fn_a, tree fn_b)
+{
+ if (TREE_CODE (fn_a) == TEMPLATE_DECL
+ && TREE_CODE (fn_b) == TEMPLATE_DECL)
+ {
+ if (!compare_lambda_template_head (fn_a, fn_b))
+ return false;
+ fn_a = DECL_TEMPLATE_RESULT (fn_a);
+ fn_b = DECL_TEMPLATE_RESULT (fn_b);
+ }
+ else if (TREE_CODE (fn_a) == TEMPLATE_DECL
+ || TREE_CODE (fn_b) == TEMPLATE_DECL)
+ return false;
+
+ if (fn_a == error_mark_node
+ || fn_b == error_mark_node)
+ return false;
+
+ for (tree args_a = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn_a))),
+ args_b = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn_b)));
+ args_a || args_b;
+ args_a = TREE_CHAIN (args_a), args_b = TREE_CHAIN (args_b))
+ {
+ if (!args_a || !args_b)
+ return false;
+ // This check also deals with differing varadicness
+ if (!same_type_p (TREE_VALUE (args_a), TREE_VALUE (args_b)))
+ return false;
+ }
+
+ return true;
+}
+
// Record the per-scope discriminator of LAMBDA. If the extra scope
// is empty, we must use the empty scope counter, which might not be
// the live one.
@@ -1517,6 +1636,33 @@ record_lambda_scope_discriminator (tree lambda)
LAMBDA_EXPR_SCOPE_ONLY_DISCRIMINATOR (lambda) = slot->count++;
}
+// Record the per-scope per-signature discriminator of LAMBDA. If the
+// extra scope is empty, we must use the empty scope counter, which
+// might not be the live one.
+
+void
+record_lambda_scope_sig_discriminator (tree lambda, tree fn)
+{
+ auto *slot = (vec_safe_is_empty (lambda_scope_stack)
+ || LAMBDA_EXPR_EXTRA_SCOPE (lambda)
+ ? &lambda_scope : lambda_scope_stack->begin ());
+ gcc_checking_assert (LAMBDA_EXPR_EXTRA_SCOPE (lambda) == slot->scope);
+
+ // A linear search, we're not expecting this to be a big list, and
+ // this avoids needing a signature hash function.
+ lambda_sig_count *sig;
+ if (unsigned ix = vec_safe_length (slot->discriminators))
+ for (sig = slot->discriminators->begin (); ix--; sig++)
+ if (compare_lambda_sig (fn, sig->fn))
+ goto found;
+ {
+ lambda_sig_count init = {fn, 0};
+ sig = vec_safe_push (slot->discriminators, init);
+ }
+ found:
+ LAMBDA_EXPR_SCOPE_SIG_DISCRIMINATOR (lambda) = sig->count++;
+}
+
tree
start_lambda_function (tree fco, tree lambda_expr)
{
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index a62c975..e97428e 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -1810,7 +1810,13 @@ write_closure_type_name (const tree type)
write_method_parms (parms, /*method_p=*/1, fn);
write_char ('E');
- write_compact_number (LAMBDA_EXPR_SCOPE_ONLY_DISCRIMINATOR (lambda));
+ if ((LAMBDA_EXPR_SCOPE_SIG_DISCRIMINATOR (lambda)
+ != LAMBDA_EXPR_SCOPE_ONLY_DISCRIMINATOR (lambda))
+ && abi_warn_or_compat_version_crosses (18))
+ G.need_abi_warning = true;
+ write_compact_number (abi_version_at_least (18)
+ ? LAMBDA_EXPR_SCOPE_SIG_DISCRIMINATOR (lambda)
+ : LAMBDA_EXPR_SCOPE_ONLY_DISCRIMINATOR (lambda));
}
/* Convert NUMBER to ascii using base BASE and generating at least
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index df05b52..0e9af31 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -6328,6 +6328,7 @@ trees_out::core_vals (tree t)
{
WU (((lang_tree_node *)t)->lambda_expression.default_capture_mode);
WU (((lang_tree_node *)t)->lambda_expression.discriminator_scope);
+ WU (((lang_tree_node *)t)->lambda_expression.discriminator_sig);
}
break;
@@ -6820,6 +6821,7 @@ trees_in::core_vals (tree t)
RUC (cp_lambda_default_capture_mode_type,
((lang_tree_node *)t)->lambda_expression.default_capture_mode);
RU (((lang_tree_node *)t)->lambda_expression.discriminator_scope);
+ RU (((lang_tree_node *)t)->lambda_expression.discriminator_sig);
break;
case OVERLOAD:
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index e0e3cf3..fd59de4 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -11712,6 +11712,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
fco = finish_fully_implicit_template (parser, fco);
finish_member_declaration (fco);
+ record_lambda_scope_sig_discriminator (lambda_expr, fco);
obstack_free (&declarator_obstack, p);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index fc6279c..c3fc56a 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -19912,6 +19912,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
goto out;
}
finish_member_declaration (inst);
+ record_lambda_scope_sig_discriminator (r, inst);
tree fn = oldtmpl ? DECL_TEMPLATE_RESULT (inst) : inst;
diff --git a/gcc/testsuite/g++.dg/abi/lambda-sig1-18.C b/gcc/testsuite/g++.dg/abi/lambda-sig1-18.C
new file mode 100644
index 0000000..88692ed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/lambda-sig1-18.C
@@ -0,0 +1,34 @@
+// { dg-do compile { target c++20 } }
+// { dg-options -fabi-version=18 }
+
+#include "lambda-sig1.h"
+
+// { dg-final { scan-assembler {_ZZN1XIfLj0EE2FnEvENKUlfE_clEf:} } }
+// { dg-final { scan-assembler {_ZZN1XIfLj0EE2FnEvENKUlfE0_clEf:} } }
+
+// { dg-final { scan-assembler {_ZZN1XIfLj0EE2FnEvENKUlTyfT_E_clIiEEDafS1_:} } }
+// { dg-final { scan-assembler {_ZZN1XIfLj0EE2FnEvENKUlTyfT_E0_clIiEEDafS1_:} } }
+
+// { dg-final { scan-assembler {_ZZN1XIfLj0EE2FnEvENKUlTyT_E_clIiEEDaS1_:} } }
+// { dg-final { scan-assembler {_ZZN1XIfLj0EE2FnEvENKUlTyT_E0_clIiEEDaS1_:} } }
+
+// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlfE_clEf:} } }
+// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlfE0_clEf:} } }
+// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlfE1_clEf:} } }
+
+// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlTyfT_E_clIiEEDafS1_:} } }
+// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlTyfT_E0_clIiEEDafS1_:} } }
+// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlTyfT_E1_clIiEEDafS1_:} } }
+
+// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlTyT_E_clIiEEDaS1_:} } }
+// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlTyT_E0_clIiEEDaS1_:} } }
+// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlTyT_E1_clIiEEDaS1_:} } }
+
+// { dg-final { scan-assembler {_ZZN1XIiLj0EE2FnEvENKUliE_clEi:} } }
+// { dg-final { scan-assembler {_ZZN1XIiLj0EE2FnEvENKUliE0_clEi:} } }
+
+// { dg-final { scan-assembler {_ZZN1XIiLj0EE2FnEvENKUlTyiT_E_clIiEEDaiS1_:} } }
+// { dg-final { scan-assembler {_ZZN1XIiLj0EE2FnEvENKUlTyiT_E0_clIiEEDaiS1_:} } }
+
+// { dg-final { scan-assembler {_ZZN1XIiLj0EE2FnEvENKUlTyT_E_clIiEEDaS1_:} } }
+// { dg-final { scan-assembler {_ZZN1XIiLj0EE2FnEvENKUlTyT_E0_clIiEEDaS1_:} } }
diff --git a/gcc/testsuite/g++.dg/abi/lambda-sig1-18vs17.C b/gcc/testsuite/g++.dg/abi/lambda-sig1-18vs17.C
new file mode 100644
index 0000000..b191fb3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/lambda-sig1-18vs17.C
@@ -0,0 +1,40 @@
+// { dg-do compile { target c++20 } }
+// { dg-options {-fabi-version=18 -Wabi=17} }
+
+#include "lambda-sig1.h"
+
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENKUlfT_E7_clIiEEDafS1_'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENKUlTyfT_E1_clIiEEDafS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENKUlT_E5_clIiEEDaS1_'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENKUlTyT_E1_clIiEEDaS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENKUlfE6_cvPFvfEEv'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENKUlfE1_cvPFvfEEv'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENUlfE6_4_FUNEf'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENUlfE1_4_FUNEf'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENKUlfE6_clEf'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENKUlfE1_clEf'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENKUlfT_E4_clIiEEDafS1_'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENKUlTyfT_E0_clIiEEDafS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENKUlT_E2_clIiEEDaS1_'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENKUlTyT_E0_clIiEEDaS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENKUlfE3_cvPFvfEEv'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENKUlfE0_cvPFvfEEv'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENUlfE3_4_FUNEf'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENUlfE0_4_FUNEf'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENKUlfE3_clEf'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENKUlfE0_clEf'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENKUlfT_E1_clIiEEDafS1_'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENKUlTyfT_E_clIiEEDafS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENKUlT_E_clIiEEDaS1_'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENKUlTyT_E_clIiEEDaS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENKUlfE0_cvPFvfEEv'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENKUlfE_cvPFvfEEv'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENUlfE0_4_FUNEf'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENUlfE_4_FUNEf'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj1EE2FnEvENKUlfE0_clEf'\) and '-fabi-version=18' \('_ZZN1XIfLj1EE2FnEvENKUlfE_clEf'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj0EE2FnEvENKUlfT_E4_clIiEEDafS1_'\) and '-fabi-version=18' \('_ZZN1XIfLj0EE2FnEvENKUlTyfT_E0_clIiEEDafS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj0EE2FnEvENKUlT_E2_clIiEEDaS1_'\) and '-fabi-version=18' \('_ZZN1XIfLj0EE2FnEvENKUlTyT_E0_clIiEEDaS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj0EE2FnEvENKUlfE3_cvPFvfEEv'\) and '-fabi-version=18' \('_ZZN1XIfLj0EE2FnEvENKUlfE0_cvPFvfEEv'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj0EE2FnEvENUlfE3_4_FUNEf'\) and '-fabi-version=18' \('_ZZN1XIfLj0EE2FnEvENUlfE0_4_FUNEf'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj0EE2FnEvENKUlfE3_clEf'\) and '-fabi-version=18' \('_ZZN1XIfLj0EE2FnEvENKUlfE0_clEf'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj0EE2FnEvENKUlfT_E1_clIiEEDafS1_'\) and '-fabi-version=18' \('_ZZN1XIfLj0EE2FnEvENKUlTyfT_E_clIiEEDafS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj0EE2FnEvENKUlT_E_clIiEEDaS1_'\) and '-fabi-version=18' \('_ZZN1XIfLj0EE2FnEvENKUlTyT_E_clIiEEDaS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj0EE2FnEvENKUlfE0_cvPFvfEEv'\) and '-fabi-version=18' \('_ZZN1XIfLj0EE2FnEvENKUlfE_cvPFvfEEv'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj0EE2FnEvENUlfE0_4_FUNEf'\) and '-fabi-version=18' \('_ZZN1XIfLj0EE2FnEvENUlfE_4_FUNEf'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIfLj0EE2FnEvENKUlfE0_clEf'\) and '-fabi-version=18' \('_ZZN1XIfLj0EE2FnEvENKUlfE_clEf'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIiLj0EE2FnEvENKUliT_E4_clIiEEDaiS1_'\) and '-fabi-version=18' \('_ZZN1XIiLj0EE2FnEvENKUlTyiT_E0_clIiEEDaiS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIiLj0EE2FnEvENKUlT_E2_clIiEEDaS1_'\) and '-fabi-version=18' \('_ZZN1XIiLj0EE2FnEvENKUlTyT_E0_clIiEEDaS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIiLj0EE2FnEvENKUliE3_cvPFviEEv'\) and '-fabi-version=18' \('_ZZN1XIiLj0EE2FnEvENKUliE0_cvPFviEEv'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIiLj0EE2FnEvENUliE3_4_FUNEi'\) and '-fabi-version=18' \('_ZZN1XIiLj0EE2FnEvENUliE0_4_FUNEi'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIiLj0EE2FnEvENKUliE3_clEi'\) and '-fabi-version=18' \('_ZZN1XIiLj0EE2FnEvENKUliE0_clEi'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIiLj0EE2FnEvENKUliT_E1_clIiEEDaiS1_'\) and '-fabi-version=18' \('_ZZN1XIiLj0EE2FnEvENKUlTyiT_E_clIiEEDaiS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIiLj0EE2FnEvENKUlT_E_clIiEEDaS1_'\) and '-fabi-version=18' \('_ZZN1XIiLj0EE2FnEvENKUlTyT_E_clIiEEDaS1_'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIiLj0EE2FnEvENKUliE0_cvPFviEEv'\) and '-fabi-version=18' \('_ZZN1XIiLj0EE2FnEvENKUliE_cvPFviEEv'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIiLj0EE2FnEvENUliE0_4_FUNEi'\) and '-fabi-version=18' \('_ZZN1XIiLj0EE2FnEvENUliE_4_FUNEi'\) [^\n]*\n} }
+// { dg-regexp {[^\n]*lambda-sig1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZN1XIiLj0EE2FnEvENKUliE0_clEi'\) and '-fabi-version=18' \('_ZZN1XIiLj0EE2FnEvENKUliE_clEi'\) [^\n]*\n} }
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1-18.C b/gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1-18.C
new file mode 100644
index 0000000..22ad15e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1-18.C
@@ -0,0 +1,26 @@
+// { dg-do compile { target c++14 } }
+// { dg-additional-options -fabi-version=18 }
+
+// PRs 78621
+
+#include "lambda-mangle-1.h"
+
+// We erroneously mangled lambda auto parms as-if template parameters (T<n>_),
+// rather than auto (Da). Fixed in abi version 11
+
+// ABI 18 uses per-scope per-signature lambda discriminator
+
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRT_E_EOS0_S1_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRiRT_E_EOS1_S2_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRT_R1XIiEE_EOS0_S1_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlPA5_T_E_EOS0_RS0_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRT_E_EvS1_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRiRT_E_EvS2_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRT_R1XIiEE_EvS1_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlPA5_T_E_EvRS0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPfS1_E_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPT_PT0_E_EvRS1_RS3_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlPT_PT0_E_Z3FoovEUlS1_S3_E0_EvRS0_RS2_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPfS3_E_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPT_PT0_E_EvRS3_RS5_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsDpPT_E_EvRT_RT0_:" } }
diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc
index b0f0cb9..e232aac 100644
--- a/libcc1/libcp1plugin.cc
+++ b/libcc1/libcp1plugin.cc
@@ -1656,6 +1656,7 @@ plugin_start_closure_class_type (cc1_plugin::connection *self,
/* Instead of calling record_lambda_scope, do this: */
LAMBDA_EXPR_EXTRA_SCOPE (lambda_expr) = extra_scope;
LAMBDA_EXPR_SCOPE_ONLY_DISCRIMINATOR (lambda_expr) = discriminator;
+ LAMBDA_EXPR_SCOPE_SIG_DISCRIMINATOR (lambda_expr) = discriminator;
tree decl = TYPE_NAME (type);
determine_visibility (decl);