diff mbox series

C++ PATCH for c++/82053, ICE with default argument in lambda in template

Message ID CADzB+2kBJRp3JpWfPvK+xp=eZ0gHxjDn01Fc=XyBQn7aYYCxkA@mail.gmail.com
State New
Headers show
Series C++ PATCH for c++/82053, ICE with default argument in lambda in template | expand

Commit Message

Jason Merrill Sept. 7, 2017, 1:01 a.m. UTC
When we regenerate a lambda, the resulting op() doesn't have any
template information, so we can't delay instantiating default
arguments like we do for a normal template function.  I believe this
is also the direction of the core working group for default arguments
in local extern function declarations, so I don't think we need to
invent a mechanism to remember those template arguments for later use.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 17d672e6eaf10f96174b00207c60b5467693877f
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Aug 31 13:03:31 2017 -0400

            PR c++/82053 - ICE with default argument in lambda in template
    
            * pt.c (tsubst_arg_types): Substitute default arguments for lambdas
            in templates.
            (retrieve_specialization): Use lambda_fn_in_template_p.
            * cp-tree.h: Declare it.
diff mbox series

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 20fa039..a0e31d3 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6821,6 +6821,7 @@  extern tree current_nonlambda_function		(void);
 extern tree nonlambda_method_basetype		(void);
 extern tree current_nonlambda_scope		(void);
 extern bool generic_lambda_fn_p			(tree);
+extern bool lambda_fn_in_template_p		(tree);
 extern void maybe_add_lambda_conv_op            (tree);
 extern bool is_lambda_ignored_entity            (tree);
 extern bool lambda_static_thunk_p		(tree);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4a65e31..ec7bbc8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -1193,16 +1193,8 @@  retrieve_specialization (tree tmpl, tree args, hashval_t hash)
 
   /* Lambda functions in templates aren't instantiated normally, but through
      tsubst_lambda_expr.  */
-  if (LAMBDA_FUNCTION_P (tmpl))
-    {
-      bool generic = PRIMARY_TEMPLATE_P (tmpl);
-      if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)) > generic)
-	return NULL_TREE;
-
-      /* But generic lambda functions are instantiated normally, once their
-	 containing context is fully instantiated.  */
-      gcc_assert (generic);
-    }
+  if (lambda_fn_in_template_p (tmpl))
+    return NULL_TREE;
 
   if (optimize_specialization_lookup_p (tmpl))
     {
@@ -12579,7 +12571,7 @@  tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
 bool
 lambda_fn_in_template_p (tree fn)
 {
-  if (!LAMBDA_FUNCTION_P (fn))
+  if (!fn || !LAMBDA_FUNCTION_P (fn))
     return false;
   tree closure = DECL_CONTEXT (fn);
   return CLASSTYPE_TEMPLATE_INFO (closure) != NULL_TREE;
@@ -13248,6 +13240,13 @@  tsubst_arg_types (tree arg_types,
        done in build_over_call.  */
     default_arg = TREE_PURPOSE (arg_types);
 
+    /* Except that we do substitute default arguments under tsubst_lambda_expr,
+       since the new op() won't have any associated template arguments for us
+       to refer to later.  */
+    if (lambda_fn_in_template_p (in_decl))
+      default_arg = tsubst_copy_and_build (default_arg, args, complain, in_decl,
+					   false/*fn*/, false/*constexpr*/);
+
     if (default_arg && TREE_CODE (default_arg) == DEFAULT_ARG)
       {
         /* We've instantiated a template before its default arguments
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-defarg7.C b/gcc/testsuite/g++.dg/cpp1y/lambda-defarg7.C
new file mode 100644
index 0000000..f67dfee
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-defarg7.C
@@ -0,0 +1,13 @@ 
+// PR c++/82053
+// { dg-do compile { target c++14 } }
+
+template<class T>
+int fn() { return 42; }
+
+template<class T>
+auto lam = [](int = fn<T>()){};
+
+int main()
+{
+  lam<int>();
+}