On Wed, Aug 9, 2017 at 3:20 PM, Jason Merrill wrote:
> In this testcase, when building up an extra version of N to refer to
> when instantiating the generic lambda, we were mistakenly replacing
> the 'auto' with a template argument for the generic lambda.
>
> Tested x86_64-pc-linux-gnu, applying to trunk and 7.
Recent testing found a bug in this patch, whereby we would mistakenly
clobber the TREE_VEC_LENGTH of a single-level argument set, or
increase the length rather than decreasing it. Fixed by using
strip_innermost_template_args and calculating how many levels we
actually want to remove. On the trunk I've also added an assert that
we shouldn't get into this situation anymore.
Tested x86_64-pc-linux-gnu, applying to trunk and 7.
commit 2e694fe9477fefb4d746943c6996785109f61aa6
Author: Jason Merrill
Date: Thu Sep 28 16:07:34 2017 -0400
PR c++/81525 - broken handling of auto in generic lambda.
* pt.c (tsubst_decl) [VAR_DECL]: Use strip_innermost_template_args.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f3ad6083190..38d7b45eb9b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12896,15 +12896,17 @@ tsubst_decl (tree t, tree args, tsubst_flags_t
complain)
&& VAR_HAD_UNKNOWN_BOUND (t)
&& type != error_mark_node)
type = strip_array_domain (type);
- tree auto_node = type_uses_auto (type);
- int len = TREE_VEC_LENGTH (args);
- if (auto_node)
- /* Mask off any template args past the variable's context so we
-don't replace the auto with an unrelated argument. */
- TREE_VEC_LENGTH (args) = TEMPLATE_TYPE_LEVEL (auto_node) - 1;
- type = tsubst (type, args, complain, in_decl);
- if (auto_node)
- TREE_VEC_LENGTH (args) = len;
+ tree sub_args = args;
+ if (tree auto_node = type_uses_auto (type))
+ {
+ /* Mask off any template args past the variable's context so we
+ don't replace the auto with an unrelated argument. */
+ int nouter = TEMPLATE_TYPE_LEVEL (auto_node) - 1;
+ int extra = TMPL_ARGS_DEPTH (args) - nouter;
+ if (extra > 0)
+ sub_args = strip_innermost_template_args (args, extra);
+ }
+ type = tsubst (type, sub_args, complain, in_decl);
}
if (VAR_P (r))
{
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C
b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C
new file mode 100644
index 000..b9e98c551c0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C
@@ -0,0 +1,19 @@
+// Related to c++/81525
+// { dg-do compile { target c++14 } }
+
+template
+struct A
+{
+ template
+ static void f()
+ {
+[](auto b) {
+ auto c = +b;
+}(42);
+ }
+};
+
+int main()
+{
+ A::f();
+}
commit c6c77e3c274bc8a1bdd33be58895e1ae08a453a7
Author: Jason Merrill
Date: Thu Sep 28 16:07:34 2017 -0400
PR c++/81525 - broken handling of auto in generic lambda.
* pt.c (tsubst_decl) [VAR_DECL]: Use strip_innermost_template_args.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index c29c779a147..36c8c106439 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13042,15 +13042,20 @@ tsubst_decl (tree t, tree args, tsubst_flags_t
complain)
&& VAR_HAD_UNKNOWN_BOUND (t)
&& type != error_mark_node)
type = strip_array_domain (type);
- tree auto_node = type_uses_auto (type);
- int len = TREE_VEC_LENGTH (args);
- if (auto_node)
- /* Mask off any template args past the variable's context so we
-don't replace the auto with an unrelated argument. */
- TREE_VEC_LENGTH (args) = TEMPLATE_TYPE_LEVEL (auto_node) - 1;
- type = tsubst (type, args, complain, in_decl);
- if (auto_node)
- TREE_VEC_LENGTH (args) = len;
+ tree sub_args = args;
+ if (tree auto_node = type_uses_auto (type))
+ {
+ /* Mask off any template args past the variable's context so we
+ don't replace the auto with an unrelated argument. */
+ int nouter = TEMPLATE_TYPE_LEVEL (auto_node) - 1;
+ int extra = TMPL_ARGS_DEPTH (args) - nouter;
+ if (extra > 0)
+ /* This should never happen with the new lambda instantiation
+model, but keep the handling just in case. */
+ gcc_assert (!CHECKING_P),
+ sub_args = strip_innermost_template_args (args, extra);
+ }
+ type = tsubst (type, sub_args, complain, in_decl);
}
if (VAR_P (r))
{
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C
b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C
new file mode 100644
index 000..b9e98c551c0
--- /dev/null
+++ b/g