Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk/15?
-- >8 --
A typedef to a template-id with a lambda targ must not be stripped by
strip_typedefs because it can cause the lambda to leak into a deeper
template context, which breaks substituting into the lambda later.
For example in the below testcases zero<inner> gets stripped to
zero<Type<[](auto) {}>>, and we end up substituting through this
lambda targ twice (with args {double} then {int}) even though the lambda
is from a depth-one template context.
This patch extends the existing lambda typedef handling in
dependent_opaque_alias_p (added by r15-3694 for decltype(lambda))
to also recognize such template-id typedefs. This should recognize
the vast majority of such constructs in practice (though the lambda
could also be a subexpression within a template argument which this
won't recognize).
PR c++/123700
gcc/cp/ChangeLog:
* pt.cc (dependent_opaque_alias_p): Return true for a
template-id typedef with a lambda targ.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/lambda-targ24.C: New test.
* g++.dg/cpp2a/lambda-targ24a.C: New test.
---
gcc/cp/pt.cc | 14 +++++++++++++-
gcc/testsuite/g++.dg/cpp2a/lambda-targ24.C | 12 ++++++++++++
gcc/testsuite/g++.dg/cpp2a/lambda-targ24a.C | 14 ++++++++++++++
3 files changed, 39 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ24.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ24a.C
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ddf492b34354..60afc6b99266 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -6872,6 +6872,14 @@ dependent_alias_template_spec_p (const_tree t, bool
transparent_typedefs)
bool
dependent_opaque_alias_p (const_tree t)
{
+ auto any_lambda_targ_p = [] (tree args)
+ {
+ for (tree arg : tree_vec_range (args))
+ if (TREE_CODE (arg) == LAMBDA_EXPR)
+ return true;
+ return false;
+ };
+
return (TYPE_P (t)
&& typedef_variant_p (t)
&& (any_dependent_type_attributes_p (DECL_ATTRIBUTES
@@ -6882,7 +6890,11 @@ dependent_opaque_alias_p (const_tree t)
alias would incorrectly yield a distinct lambda type. */
|| (TREE_CODE (t) == DECLTYPE_TYPE
&& TREE_CODE (DECLTYPE_TYPE_EXPR (t)) == LAMBDA_EXPR
- && !typedef_variant_p (DECL_ORIGINAL_TYPE (TYPE_NAME (t))))));
+ && !typedef_variant_p (DECL_ORIGINAL_TYPE (TYPE_NAME (t))))
+ || (TYPE_TEMPLATE_INFO (t)
+ && PRIMARY_TEMPLATE_P (TYPE_TI_TEMPLATE (t))
+ && any_lambda_targ_p (INNERMOST_TEMPLATE_ARGS
+ (TYPE_TI_ARGS (t))))));
}
/* Return the number of innermost template parameters in TMPL. */
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ24.C
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ24.C
new file mode 100644
index 000000000000..6b071ca2ada9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ24.C
@@ -0,0 +1,12 @@
+// PR c++/123700
+// { dg-do compile { target c++20 } }
+
+template<class> constexpr int zero = 0;
+template<auto> struct Type;
+
+int outer(auto) {
+ using inner = Type<[](auto) {}>;
+ return [](auto) { return zero<inner>; }(0);
+}
+
+int main() { outer(0.0); }
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ24a.C
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ24a.C
new file mode 100644
index 000000000000..83279356d4ec
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ24a.C
@@ -0,0 +1,14 @@
+// PR c++/123700
+// { dg-do compile { target c++20 } }
+// A version of lambda-targ24.C where zero is a class instead of
+// variable template
+
+template<class> struct zero { };
+template<auto> struct Type;
+
+auto outer(auto) {
+ using inner = Type<[](auto) {}>;
+ return [](auto) { return zero<inner>{}; }(0);
+}
+
+int main() { outer(0.0); }
--
2.53.0.582.gca1db8a0f7