2016-12-07 Nathan Sidwell <nathan@acm.org>
gcc/
PR c++/78621
* doc/invoke.texi (-fabi-version): Document generic lambda
mangling for version 11.
gcc/cp/
PR c++/78621
* cp-tree.h (make_auto_for_mangle): Declare.
* mangle.c (write_closure_type_name): Handle generic lambdas
correctly.
* pt.c (tsubst): Add {TYPE,EXPR}_PACK_EXPANSION handling.
(make_auto_raw): Break out of ...
(make_auto_1): ... here. Call it.
(make_auto_for_mangle): New.
gcc/testsuite/
PR c++/78621
* g++.dg/cpp1y/lambda-mangle-1.C: New.
* g++.dg/cpp1y/lambda-mangle-2.C: New.
* g++.dg/cpp1y/lambda-mangle-3.C: New.
libiberty/
PR c++/78621
* testsuite/demangle-expected: Add fixed-ABI generic lambda tests.
===================================================================
@@ -6108,6 +6108,7 @@
extern void check_template_variable (tree);
extern tree make_auto (void);
extern tree make_decltype_auto (void);
+extern tree make_auto_for_mangle (tree, tree);
extern tree make_template_placeholder (tree);
extern tree do_auto_deduction (tree, tree, tree);
extern tree do_auto_deduction (tree, tree, tree,
===================================================================
@@ -1640,6 +1640,19 @@
tree lambda = CLASSTYPE_LAMBDA_EXPR (type);
tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ if (generic_lambda_fn_p (fn))
+ {
+ /* A generic lambda's auto parms are represented as distinct
+ TEMPLATE_TYPE_PARMs, which are both distinct and not is_auto.
+ But we must mangle (& squangle) them as (the same) 'auto'.
+ So do some substitution to arrange that. */
+ if (abi_warn_or_compat_version_crosses (11))
+ G.need_abi_warning = 1;
+
+ if (abi_version_at_least (11))
+ parms = make_auto_for_mangle (fn, parms);
+ }
+
MANGLE_TRACE_TREE ("closure-type-name", type);
write_string ("Ul");
===================================================================
@@ -13813,6 +13813,42 @@
return r;
}
+ case TYPE_PACK_EXPANSION:
+ case EXPR_PACK_EXPANSION:
+ {
+ tree r;
+
+ if (code == EXPR_PACK_EXPANSION)
+ {
+ r = make_node (code);
+ TREE_TYPE (r) = type;
+ TREE_CONSTANT (r) = TREE_CONSTANT (t);
+ PACK_EXPANSION_SIZEOF_P (r) = PACK_EXPANSION_SIZEOF_P (t);
+ }
+ else
+ {
+ r = cxx_make_type (code);
+ SET_TYPE_STRUCTURAL_EQUALITY (r);
+ }
+
+ WILDCARD_PACK_P (r) = WILDCARD_PACK_P (t);
+ PACK_EXPANSION_LOCAL_P (r) = PACK_EXPANSION_LOCAL_P (t);
+
+ tree pattern = PACK_EXPANSION_PATTERN (t);
+ pattern = tsubst (pattern, args, complain, in_decl);
+ SET_PACK_EXPANSION_PATTERN (r, pattern);
+
+ tree packs = PACK_EXPANSION_PARAMETER_PACKS (t);
+ packs = tsubst (packs, args, complain, in_decl);
+ PACK_EXPANSION_PARAMETER_PACKS (r) = packs;
+
+ tree extra = PACK_EXPANSION_EXTRA_ARGS (t);
+ extra = tsubst (extra, args, complain, in_decl);
+ PACK_EXPANSION_EXTRA_ARGS (r) = extra;
+
+ return r;
+ }
+
case VOID_CST:
case INTEGER_CST:
case REAL_CST:
@@ -24278,20 +24314,19 @@
}
}
-/* Returns a type which represents 'auto' or 'decltype(auto)'. We use a
- TEMPLATE_TYPE_PARM with a level one deeper than the actual template
- parms. If set_canonical is true, we set TYPE_CANONICAL on it. */
+/* Returns a template type parm to represent 'auto' or
+ 'decltype(auto)'. If SET_CANONICAL is true, we set TYPE_CANONICAL
+ on it. set the parm's LEVEL and ORIG_LEVEL as specified. */
static tree
-make_auto_1 (tree name, bool set_canonical)
+make_auto_raw (tree name, bool set_canonical, int level, int orig_level)
{
tree au = cxx_make_type (TEMPLATE_TYPE_PARM);
TYPE_NAME (au) = build_decl (input_location,
TYPE_DECL, name, au);
TYPE_STUB_DECL (au) = TYPE_NAME (au);
TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
- (0, processing_template_decl + 1, processing_template_decl + 1,
- TYPE_NAME (au), NULL_TREE);
+ (0, level, orig_level, TYPE_NAME (au), NULL_TREE);
if (set_canonical)
TYPE_CANONICAL (au) = canonical_type_parameter (au);
DECL_ARTIFICIAL (TYPE_NAME (au)) = 1;
@@ -24300,6 +24335,18 @@
return au;
}
+/* Returns a type to represent 'auto' or 'decltype(auto)'. We use a
+ TEMPLATE_TYPE_PARM with a level one deeper than the actual template
+ parms. If set_canonical is true, we set TYPE_CANONICAL on it. */
+
+static tree
+make_auto_1 (tree name, bool set_canonical)
+{
+ return make_auto_raw (name, set_canonical,
+ processing_template_decl + 1,
+ processing_template_decl + 1);
+}
+
tree
make_decltype_auto (void)
{
@@ -24352,6 +24399,25 @@
return decl;
}
+/* FN a generic lambda function and PARMS is its parameters. Perform
+ appropriate substitution turning the distinct template type parms
+ into a regular auto template type parm suitable for mangler
+ use. */
+
+tree
+make_auto_for_mangle (tree fn, tree parms)
+{
+ tree ti_args = TI_ARGS (DECL_TEMPLATE_INFO (fn));
+ unsigned ix = NUM_TMPL_ARGS (INNERMOST_TEMPLATE_ARGS (ti_args));
+ tree args = make_tree_vec (ix);
+ tree auto_parm = make_auto_raw (auto_identifier, true,
+ 1, TMPL_ARGS_DEPTH (ti_args));
+ while (ix--)
+ TREE_VEC_ELT (args, ix) = auto_parm;
+
+ return tsubst (parms, args, tf_none, NULL_TREE);
+}
+
/* Given type ARG, return std::initializer_list<ARG>. */
static tree
===================================================================
@@ -2250,7 +2250,7 @@
attributes (e.g. @samp{stdcall}).
Version 11, which first appeared in G++ 7, corrects the mangling of
-sizeof... expressions. It also implies
+sizeof... expressions and generic lambdas. It also implies
@option{-fnew-inheriting-ctors}.
See also @option{-Wabi}.
===================================================================
@@ -0,0 +1,81 @@
+// { dg-do compile { target c++14 } }
+// { dg-additional-options "-fabi-version=10" }
+
+// PRs 78252, 78621
+
+// We erroneously mangle lambda auto parms as-if template parameters (T<n>_),
+// rather than auto (Da). While that's unfortunate, it'd be best if
+// we didn't accidentally change that.
+
+template<typename T> class X;
+
+template<typename T>
+T &&forward (T &v)
+{
+ return static_cast<T &&> (v);
+}
+
+template<typename T>
+void eat (T &v)
+{
+}
+
+template<typename S, typename T>
+ void eat (S &, T &v)
+{
+}
+
+void Foo ()
+{
+ auto lam = [](auto &) { };
+ auto lam_1 = [](int &, auto &) { };
+ auto lam_2 = [](auto &, X<int> &) { };
+ auto lam_3 = [](auto (*)[5]) { };
+
+ forward (lam);
+ forward (lam_1);
+ forward (lam_2);
+ forward (lam_3);
+
+ eat (lam);
+ eat (lam_1);
+ eat (lam_2);
+ eat (lam_3);
+
+ auto lambda_1 = [](float *, float *) { };
+ auto lambda_2 = [](auto *, auto *) { };
+
+ int *i;
+
+ eat (i, lambda_1);
+ eat (i, lambda_2);
+}
+
+template<typename X> void Bar ()
+{
+ auto lambda_1 = [](X *, float *, float *) { };
+ auto lambda_2 = [](X *, auto *, auto *) { };
+
+ int *i;
+
+ eat (i, lambda_1);
+ eat (i, lambda_2);
+}
+
+void Baz ()
+{
+ Bar<short> ();
+}
+
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRT_E_EOS0_S1_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRiRT_E0_EOS1_S2_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRT_R1XIiEE1_EOS0_S1_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlPA5_T_E2_EOS0_RS0_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRT_E_EvS1_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRiRT_E0_EvS2_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRT_R1XIiEE1_EvS1_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlPA5_T_E2_EvRS0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPfS1_E3_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPT_PT0_E4_EvRS1_RS3_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPfS3_E_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPT_PT0_E0_EvRS3_RS5_:" } }
===================================================================
@@ -0,0 +1,88 @@
+// { dg-do compile { target c++14 } }
+
+// PRs 78621
+
+// We erroneously mangled lambda auto parms as-if template parameters (T<n>_),
+// rather than auto (Da). Fixed in abi version 11
+
+template<typename T> class X;
+
+template<typename T>
+T &&forward (T &v)
+{
+ return static_cast<T &&> (v);
+}
+
+template<typename T>
+void eat (T &v)
+{
+}
+
+template<typename S, typename T>
+ void eat (S &, T &v)
+{
+}
+
+void Foo ()
+{
+ auto lam = [](auto &) { };
+ auto lam_1 = [](int &, auto &) { };
+ auto lam_2 = [](auto &, X<int> &) { };
+ auto lam_3 = [](auto (*)[5]) { };
+
+ forward (lam);
+ forward (lam_1);
+ forward (lam_2);
+ forward (lam_3);
+
+ eat (lam);
+ eat (lam_1);
+ eat (lam_2);
+ eat (lam_3);
+
+ // The auto lambda should mangle similarly to the non-auto one
+ auto lambda_1 = [](float *, float *) { };
+ auto lambda_2 = [](auto *, auto *) { };
+ auto lambda_3 = [](auto *, auto *) { };
+
+ int *i;
+
+ eat (i, lambda_1);
+ eat (i, lambda_2);
+
+ // The autos should squangle to the first one.
+ eat (lambda_2, lambda_3);
+}
+
+template<typename X> void Bar ()
+{
+ auto lambda_1 = [](X *, float *, float *) { };
+ auto lambda_2 = [](X *, auto *, auto *) { };
+ auto lambda_3 = [](X *, auto *...) {};
+
+ int *i;
+
+ eat (i, lambda_1);
+ eat (i, lambda_2);
+ eat (i, lambda_3);
+}
+
+void Baz ()
+{
+ Bar<short> ();
+}
+
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRDaE_EOT_RS2_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRiRDaE0_EOT_RS3_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRDaR1XIiEE1_EOT_RS5_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlPA5_DaE2_EOT_RS3_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRDaE_EvRT_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRiRDaE0_EvRT_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRDaR1XIiEE1_EvRT_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlPA5_DaE2_EvRT_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPfS1_E3_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPDaS1_E4_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlPDaS0_E4_Z3FoovEUlS0_S0_E5_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPfS3_E_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPDaS3_E0_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPDazE1_EvRT_RT0_:" } }
===================================================================
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++14 } }
+// { dg-additional-options "-Wabi=10" }
+
+// PRs 78621
+
+// check we warn about changed mangling of generic lambdas.
+
+template<typename T>
+void eat (T &v) // { dg-warning "mangled name" }
+{
+}
+
+void Foo ()
+{
+ auto lam = [](auto &) { };
+
+ eat (lam);
+}
===================================================================
@@ -4634,3 +4634,11 @@
# ?: expression with missing third component could crash.
AquT_quT_4mxautouT_4mxxx
AquT_quT_4mxautouT_4mxxx
+
+# pr78621 We were incorrectly mangling generic lambdas. Check the fix
+# for that demangles as expected
+_Z3eatIPiZ3FoovEUlPDaS1_E4_EvRT_RT0_
+void eat<int*, Foo()::{lambda(auto*, auto*)#6}>(int*&, Foo()::{lambda(auto*, auto*)#6}&)
+
+_Z3eatIPiZ3BarIsEvvEUlPsPDaS3_E0_EvRT_RT0_
+void eat<int*, void Bar<short>()::{lambda(short*, auto*, auto*)#2}>(int*&, void Bar<short>()::{lambda(short*, auto*, auto*)#2}&)