PR c++/89241 - ICE with lambda in template parameter list.
authorJason Merrill <jason@redhat.com>
Wed, 27 Mar 2019 18:39:20 +0000 (14:39 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 27 Mar 2019 18:39:20 +0000 (14:39 -0400)
We were getting confused by a lambda in template definition context that
isn't actually in the scope of any templated entity.  Fixed by telling
type_dependent_expression_p that such a lambda is type-dependent even if we
can't tell that from its closure type.  I've also restored the error for
defining a non-lambda class in a default template argument, and for a lambda
befor C++20.

* parser.c (cp_parser_lambda_expression): Also reject a lambda in a
template parameter list before C++20.
* pt.c (type_dependent_expression_p): True for LAMBDA_EXPR.
* semantics.c (begin_class_definition): Restore error about defining
non-lambda class in template parm list.

From-SVN: r269972

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/testsuite/g++.dg/cpp2a/lambda-uneval10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/complit16.C [new file with mode: 0644]

index bce9b108723d1f591aadf4e51c95446edb8278b4..48071948f4e1319a70ac324e01403615f1171ffe 100644 (file)
@@ -1,3 +1,12 @@
+2019-03-27  Jason Merrill  <jason@redhat.com>
+
+       PR c++/89241 - ICE with lambda in template parameter list.
+       * parser.c (cp_parser_lambda_expression): Also reject a lambda in a
+       template parameter list before C++20.
+       * pt.c (type_dependent_expression_p): True for LAMBDA_EXPR.
+       * semantics.c (begin_class_definition): Restore error about defining
+       non-lambda class in template parm list.
+
 2019-03-26  Jason Merrill  <jason@redhat.com>
 
        PR c++/86932 - missed SFINAE with empty pack.
index 4119d2a32659980937a32f203fb4f3da2fec7139..348e4acf2d10356f31c0e9940c063778d0acaad0 100644 (file)
@@ -10397,7 +10397,7 @@ cp_parser_lambda_expression (cp_parser* parser)
        }
       ok = false;
     }
-  else if (parser->in_template_argument_list_p)
+  else if (parser->in_template_argument_list_p || processing_template_parmlist)
     {
       if (!token->error_reported)
        {
index dc982f3ed55a7babf04066d0bcccc40eb1a3395e..229b34a197e4ca9be4290ddfba89c1ec488ea746 100644 (file)
@@ -25692,6 +25692,12 @@ type_dependent_expression_p (tree expression)
       || TREE_CODE (expression) == WILDCARD_DECL)
     return true;
 
+  /* A lambda-expression in template context is dependent.  dependent_type_p is
+     true for a lambda in the scope of a class or function template, but that
+     doesn't cover all template contexts, like a default template argument.  */
+  if (TREE_CODE (expression) == LAMBDA_EXPR)
+    return true;
+
   /* A fold expression is type-dependent. */
   if (TREE_CODE (expression) == UNARY_LEFT_FOLD_EXPR
       || TREE_CODE (expression) == UNARY_RIGHT_FOLD_EXPR
index d7e97e0510db399924b996982e8518586df5e6d1..fea269657f9a20f3dc4d5f1921f365bdc3d4ace6 100644 (file)
@@ -3043,6 +3043,12 @@ begin_class_definition (tree t)
   if (error_operand_p (t) || error_operand_p (TYPE_MAIN_DECL (t)))
     return error_mark_node;
 
+  if (processing_template_parmlist && !LAMBDA_TYPE_P (t))
+    {
+      error ("definition of %q#T inside template parameter list", t);
+      return error_mark_node;
+    }
+
   /* According to the C++ ABI, decimal classes defined in ISO/IEC TR 24733
      are passed the same as decimal scalar types.  */
   if (TREE_CODE (t) == RECORD_TYPE
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval10.C b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval10.C
new file mode 100644 (file)
index 0000000..86065eb
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/89421
+
+template <int I = []{return 1;}()> // { dg-message "lambda" "" { target c++17_down } }
+struct B
+{
+  static const int i = I;
+};
+
+#if __cplusplus > 201703L
+B<> b;
+static_assert (b.i == 1);
+#endif
diff --git a/gcc/testsuite/g++.dg/ext/complit16.C b/gcc/testsuite/g++.dg/ext/complit16.C
new file mode 100644 (file)
index 0000000..5625ced
--- /dev/null
@@ -0,0 +1,5 @@
+// { dg-options "" }
+
+template <int = (struct A{int i;}){42}.i> struct B{}; // { dg-error "" }
+
+B<0> b;