Hi,

again, a simple core issue, an ICE on invalid, with some rather more interesting side issues. The core is that we are not enforcing that an incomplete type cannot be captured by value. Thus the add_capture check. Then: 1- I'm also adding the early error_mark_node check because otherwise in some cases we ICE during error recovery when COMPLETE_TYPE_P gets an error_mark_node. I added the second function g() in the testcase to cover that. 2- I wish I could just do type = error_mark_node, for the by value capture error, like we do above for the VLA-related error, instead of returning error_mark_node, but that would result in a suboptimal diagnostic for the existing lambda-ice7.C. For it, we used to produce:

lambda-ice7.C: In function ‘void foo(A&)’:
lambda-ice7.C:8:3: error: invalid use of incomplete type ‘struct A’
[=](){a;};
^
lambda-ice7.C:4:8: error: forward declaration of ‘struct A’
struct A;
^
lambda-ice7.C:8:3: error: invalid use of incomplete type ‘struct A’
[=](){a;};
^
lambda-ice7.C:4:8: error: forward declaration of ‘struct A’
struct A;
^

and, after the patch:

lambda-ice7.C: In lambda function:
lambda-ice7.C:8:9: error: cannot capture by value ‘a’ of incomplete type ‘A’
[=](){a;};
^
lambda-ice7.C:4:8: note: forward declaration of ‘struct A’
struct A;
^

which I think is nearly optimal. With type = error_mark_node we would only add an additional error to the former.

3- The cxx_incomplete_type_inform check is because in some cases TYPE_MAIN_DECL can indeed be null (traditionally we used + which means location_of, which handles that). This happens for example for f() in the new testcase, and we don't emit any inform for it (at variance with lambda-ice7.C, for example). I think it's fine.

4- Finally, something I noticed while working on add_capture: right above the new check there is:

type = lambda_capture_field_type (initializer, explicit_init_p);
if (by_reference_p)
{
type = build_reference_type (type);
if (!real_lvalue_p (initializer))
error ("cannot capture %qE by reference", initializer);
}

now, interestingly, nothing in the testsuite exercises this error. And, so far, I failed to create a testcase for it. The Standard too doesn't seem to me so clear about that. Ideas?!?

Thanks!
Paolo.

/////////////////////////////

/cp
2014-05-22  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/61088
        * lambda.c (add_capture): Enforce that capture by value requires
        complete type.
        * typeck2.c (cxx_incomplete_type_inform): Early return if
        TYPE_MAIN_DECL is null.

/testsuite
2014-05-22  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/61088
        * g++.dg/cpp0x/lambda/lambda-ice13.C: New.
        * g++.dg/cpp0x/lambda/lambda-ice7.C: Adjust.
Index: cp/lambda.c
===================================================================
--- cp/lambda.c (revision 210682)
+++ cp/lambda.c (working copy)
@@ -456,6 +456,9 @@ add_capture (tree lambda, tree id, tree orig_init,
     initializer = build_x_compound_expr_from_list (initializer, ELK_INIT,
                                                   tf_warning_or_error);
   type = TREE_TYPE (initializer);
+  if (type == error_mark_node)
+    return error_mark_node;
+
   if (array_of_runtime_bound_p (type))
     {
       vla = true;
@@ -492,8 +495,17 @@ add_capture (tree lambda, tree id, tree orig_init,
            error ("cannot capture %qE by reference", initializer);
        }
       else
-       /* Capture by copy requires a complete type.  */
-       type = complete_type (type);
+       {
+         /* Capture by copy requires a complete type.  */
+         type = complete_type (type);
+         if (!dependent_type_p (type) && !COMPLETE_TYPE_P (type))
+           {
+             error ("cannot capture by value %qE of incomplete "
+                    "type %qT", initializer, type);
+             cxx_incomplete_type_inform (type);
+             return error_mark_node;
+           }
+       }
     }
 
   /* Add __ to the beginning of the field name so that user code
Index: cp/typeck2.c
===================================================================
--- cp/typeck2.c        (revision 210682)
+++ cp/typeck2.c        (working copy)
@@ -434,6 +434,9 @@ abstract_virtuals_error (abstract_class_use use, t
 void
 cxx_incomplete_type_inform (const_tree type)
 {
+  if (!TYPE_MAIN_DECL (type))
+    return;
+
   location_t loc = DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type));
   tree ptype = strip_top_quals (CONST_CAST_TREE (type));
 
Index: testsuite/g++.dg/cpp0x/lambda/lambda-ice13.C
===================================================================
--- testsuite/g++.dg/cpp0x/lambda/lambda-ice13.C        (revision 0)
+++ testsuite/g++.dg/cpp0x/lambda/lambda-ice13.C        (working copy)
@@ -0,0 +1,14 @@
+// PR c++/61088
+// { dg-do compile { target c++11 } }
+
+void f()
+{
+  typedef void (*X) ();
+  X x[] = { [x](){} };  // { dg-error "incomplete type" }
+}
+
+void g()
+{
+  typedef void (X) ();
+  X x[] = { [x](){} };  // { dg-error "array of functions|not declared" }
+}
Index: testsuite/g++.dg/cpp0x/lambda/lambda-ice7.C
===================================================================
--- testsuite/g++.dg/cpp0x/lambda/lambda-ice7.C (revision 210682)
+++ testsuite/g++.dg/cpp0x/lambda/lambda-ice7.C (working copy)
@@ -5,5 +5,5 @@ struct A;         // { dg-message "forward declara
 
 void foo(A& a)
 {
-  [=](){a;};      // { dg-error "invalid use of incomplete type" }
+  [=](){a;};      // { dg-error "incomplete type" }
 }

Reply via email to