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
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))))
+ /* Also treat an alias to A<lambda> as opaque so that it doesn't
+ "leak" into a deeper template context which would cause us to
+ over substitute into the lambda. */
+ /* FIXME These lambda checks don't recognize deeply nested lambda
+ subexpressions, and we can't use walk_tree here because it's
+ slow. Maybe a tree flag indicating typedef opaqueness? */
+ || (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. */
--- /dev/null
+// 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); }
--- /dev/null
+// 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); }