aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog12
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/lambda.c61
-rw-r--r--gcc/cp/parser.c1
-rw-r--r--gcc/cp/pt.c45
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr61636-1.C31
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr61636-2.C72
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr61636-3.C25
9 files changed, 231 insertions, 25 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 1ea7b28..d24b2ae 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,15 @@
+2017-01-17 Nathan Sidwell <nathan@acm.org>
+
+ PR c++/61636
+ * cp-tree.h (maybe_generic_this_capture): Declare.
+ * lambda.c (resolvable_dummy_lambda): New, broken out of ...
+ (maybe_resolve_dummy): ... here. Call it.
+ (maybe_generic_this_capture): New.
+ * parser.c (cp_parser_postfix_expression): Speculatively capture
+ this in generic lambda in unresolved member function call.
+ * pt.c (tsubst_copy_and_build): Force hard error from failed
+ member function lookup in generic lambda.
+
2017-01-17 Aldy Hernandez <aldyh@redhat.com>
PR c++/70565
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 24de346..0c8f147 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6551,6 +6551,7 @@ extern bool is_capture_proxy (tree);
extern bool is_normal_capture_proxy (tree);
extern void register_capture_members (tree);
extern tree lambda_expr_this_capture (tree, bool);
+extern void maybe_generic_this_capture (tree, tree);
extern tree maybe_resolve_dummy (tree, bool);
extern tree current_nonlambda_function (void);
extern tree nonlambda_method_basetype (void);
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 98fdb74..4d22c3d 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -793,16 +793,14 @@ lambda_expr_this_capture (tree lambda, bool add_capture_p)
return result;
}
-/* We don't want to capture 'this' until we know we need it, i.e. after
- overload resolution has chosen a non-static member function. At that
- point we call this function to turn a dummy object into a use of the
- 'this' capture. */
+/* Return the current LAMBDA_EXPR, if this is a resolvable dummy
+ object. NULL otherwise.. */
-tree
-maybe_resolve_dummy (tree object, bool add_capture_p)
+static tree
+resolvable_dummy_lambda (tree object)
{
if (!is_dummy_object (object))
- return object;
+ return NULL_TREE;
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (object));
gcc_assert (!TYPE_PTR_P (type));
@@ -812,18 +810,55 @@ maybe_resolve_dummy (tree object, bool add_capture_p)
&& LAMBDA_TYPE_P (current_class_type)
&& lambda_function (current_class_type)
&& DERIVED_FROM_P (type, current_nonlambda_class_type ()))
- {
- /* In a lambda, need to go through 'this' capture. */
- tree lam = CLASSTYPE_LAMBDA_EXPR (current_class_type);
- tree cap = lambda_expr_this_capture (lam, add_capture_p);
- if (cap && cap != error_mark_node)
+ return CLASSTYPE_LAMBDA_EXPR (current_class_type);
+
+ return NULL_TREE;
+}
+
+/* We don't want to capture 'this' until we know we need it, i.e. after
+ overload resolution has chosen a non-static member function. At that
+ point we call this function to turn a dummy object into a use of the
+ 'this' capture. */
+
+tree
+maybe_resolve_dummy (tree object, bool add_capture_p)
+{
+ if (tree lam = resolvable_dummy_lambda (object))
+ if (tree cap = lambda_expr_this_capture (lam, add_capture_p))
+ if (cap != error_mark_node)
object = build_x_indirect_ref (EXPR_LOCATION (object), cap,
RO_NULL, tf_warning_or_error);
- }
return object;
}
+/* When parsing a generic lambda containing an argument-dependent
+ member function call we defer overload resolution to instantiation
+ time. But we have to know now whether to capture this or not.
+ Do that if FNS contains any non-static fns.
+ The std doesn't anticipate this case, but I expect this to be the
+ outcome of discussion. */
+
+void
+maybe_generic_this_capture (tree object, tree fns)
+{
+ if (tree lam = resolvable_dummy_lambda (object))
+ if (!LAMBDA_EXPR_THIS_CAPTURE (lam))
+ {
+ /* We've not yet captured, so look at the function set of
+ interest. */
+ if (BASELINK_P (fns))
+ fns = BASELINK_FUNCTIONS (fns);
+ for (; fns; fns = OVL_NEXT (fns))
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (OVL_CURRENT (fns)))
+ {
+ /* Found a non-static member. Capture this. */
+ lambda_expr_this_capture (lam, true);
+ break;
+ }
+ }
+}
+
/* Returns the innermost non-lambda function. */
tree
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 295c450..6d3b877 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -6971,6 +6971,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
|| type_dependent_expression_p (fn)
|| any_type_dependent_arguments_p (args)))
{
+ maybe_generic_this_capture (instance, fn);
postfix_expression
= build_nt_call_vec (postfix_expression, args);
release_tree_vector (args);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index dec7d39..022ffda 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -17142,19 +17142,34 @@ tsubst_copy_and_build (tree t,
if (unq != function)
{
- tree fn = unq;
- if (INDIRECT_REF_P (fn))
- fn = TREE_OPERAND (fn, 0);
- if (TREE_CODE (fn) == COMPONENT_REF)
- fn = TREE_OPERAND (fn, 1);
- if (is_overloaded_fn (fn))
- fn = get_first_fn (fn);
- if (permerror (EXPR_LOC_OR_LOC (t, input_location),
- "%qD was not declared in this scope, "
- "and no declarations were found by "
- "argument-dependent lookup at the point "
- "of instantiation", function))
+ /* In a lambda fn, we have to be careful to not
+ introduce new this captures. Legacy code can't
+ be using lambdas anyway, so it's ok to be
+ stricter. */
+ bool in_lambda = (current_class_type
+ && LAMBDA_TYPE_P (current_class_type));
+ char const *msg = "%qD was not declared in this scope, "
+ "and no declarations were found by "
+ "argument-dependent lookup at the point "
+ "of instantiation";
+
+ bool diag = true;
+ if (in_lambda)
+ error_at (EXPR_LOC_OR_LOC (t, input_location),
+ msg, function);
+ else
+ diag = permerror (EXPR_LOC_OR_LOC (t, input_location),
+ msg, function);
+ if (diag)
{
+ tree fn = unq;
+ if (INDIRECT_REF_P (fn))
+ fn = TREE_OPERAND (fn, 0);
+ if (TREE_CODE (fn) == COMPONENT_REF)
+ fn = TREE_OPERAND (fn, 1);
+ if (is_overloaded_fn (fn))
+ fn = get_first_fn (fn);
+
if (!DECL_P (fn))
/* Can't say anything more. */;
else if (DECL_CLASS_SCOPE_P (fn))
@@ -17177,7 +17192,13 @@ tsubst_copy_and_build (tree t,
inform (DECL_SOURCE_LOCATION (fn),
"%qD declared here, later in the "
"translation unit", fn);
+ if (in_lambda)
+ {
+ release_tree_vector (call_args);
+ RETURN (error_mark_node);
+ }
}
+
function = unq;
}
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1f6425a..8697c8a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2017-01-17 Nathan Sidwell <nathan@acm.org>
+
+ PR c++/61636
+ * g++.dg/cpp1y/pr61636-1.C: New.
+ * g++.dg/cpp1y/pr61636-2.C: New.
+ * g++.dg/cpp1y/pr61636-3.C: New.
+
2017-01-17 Martin Sebor <msebor@redhat.com>
PR testsuite/79115
@@ -214,6 +221,7 @@
PR target/79004
* gcc.target/powerpc/pr79004.c: New test.
+
2017-01-12 Martin Sebor <msebor@redhat.com>
* gcc.dg/pr78138.c: Adjust.
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr61636-1.C b/gcc/testsuite/g++.dg/cpp1y/pr61636-1.C
new file mode 100644
index 0000000..9426d5f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr61636-1.C
@@ -0,0 +1,31 @@
+// PR c++/61636
+// { dg-do compile { target c++14 } }
+
+// ICE because we figure this capture too late.
+
+struct Base
+{
+ void Bar (int);
+};
+
+struct A : Base {
+ void b ();
+ void Foo (int);
+ using Base::Bar;
+ template <typename T> void Baz (T);
+};
+
+void A::b() {
+
+ auto lam = [&](auto asdf) { Foo (asdf); };
+
+ lam (0);
+
+ auto lam1 = [&](auto asdf) { Bar (asdf); };
+
+ lam1 (0);
+
+ auto lam2 = [&](auto asdf) { Baz (asdf); };
+
+ lam2 (0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr61636-2.C b/gcc/testsuite/g++.dg/cpp1y/pr61636-2.C
new file mode 100644
index 0000000..a1bd597
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr61636-2.C
@@ -0,0 +1,72 @@
+// PR c++/61636
+// { dg-do run { target c++14 } }
+
+// Check we don't capture this (too) unnecessarily
+
+struct A {
+ int b ();
+ void f (int) {}
+ static void f (double) {}
+
+ static void g (int) {}
+ static void g (double) {}
+};
+
+struct O {
+ void x (int) {}
+ static void x (double) {}
+};
+
+namespace N {
+ void y (double) {}
+}
+
+int Check (bool expect, unsigned size)
+{
+ return (expect ? sizeof (void *) : 1) != size;
+}
+
+int A::b() {
+ int r = 0;
+
+ // one of the functions is non-static
+ auto l0 = [&](auto z) { f (z); };
+ r += Check (true, sizeof l0);
+ l0(0.0); // doesn't need this capture for A::f(double), but too late
+ l0 (0); // Needs this capture for A::f(int)
+
+ // no fn is non-static.
+ auto l00 = [&](auto z) { g (z); };
+ r += Check (false, sizeof l00);
+ l00(0.0);
+ l00 (0);
+
+ // sizeof isn't an evaluation context, so no this capture
+ auto l1 = [&](auto z) { sizeof (f (z), 1); };
+ r += Check (false, sizeof l1);
+ l1(0.0); l1 (0);
+
+ auto l2 = [&](auto) { f (2.4); };
+ auto l3 = [&](auto) { f (0); };
+ l2(0); l3(0); l2(0.0); l3 (0.0);
+ r += Check (false, sizeof l2);
+ r += Check (true, sizeof l3);
+
+ auto l4 = [&](auto) { O::x (2.4); };
+ auto l5 = [&](auto) { N::y (2.4); };
+ auto l6 = [&](auto) { };
+ l4(0); l5(0); l6(0);
+ l4(0.0); l5(0.0); l6(0.0);
+ r += Check (false, sizeof l4);
+ r += Check (false, sizeof l5);
+ r += Check (false, sizeof l6);
+
+ return r;
+}
+
+int main ()
+{
+ A a;
+
+ return a.b () ? 1 : 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr61636-3.C b/gcc/testsuite/g++.dg/cpp1y/pr61636-3.C
new file mode 100644
index 0000000..18f83fe
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr61636-3.C
@@ -0,0 +1,25 @@
+// PR c++/61636
+// { dg-do compile { target c++14 } }
+// permissiveness doesn't make this permitted
+// { dg-additional-options "-fpermissive" }
+
+// ICE because we attempt to use dependent Foo during error recovery
+// and die with an unexpected this capture need.
+
+template <typename T> struct Base
+{
+ void Foo (int);
+};
+
+template <typename T> struct A : Base<T> {
+ void b ();
+};
+
+template <typename T> void A<T>::b() {
+
+ auto lam = [&](auto asdf) { Foo (asdf); }; // { dg-error "not declared" }
+
+ lam (T(0));
+}
+
+template void A<int>::b ();