Ping
On 14.04.2014 23:53, Momchil Velikov wrote:
Hello,
During overload resolution of function calls in the body of a lambda it
is possible to use an implicit/dummy 'this', which differs in const-ness
from the actual 'this' that would be captured, resulting in choosing a
non-const member function even when the captured 'this' is const. This
patch makes sure that the captured 'this' is the same as the one used in
the overload resolution.
Bootstrapped/regtested for C/C++ on x86_64-unknown-linux-gnu against
xg++ (GCC) 4.10.0 20140508 (experimental) [master revision
ed50168:49aa3a5:e79f58c7b12f37014efb7425399c93814cddb4c4]
~chill
2014-05-08 Momchil Velikov <momchil.veli...@gmail.com>
PR c++/60463
PR c++/60755
* lambda.c (lambda_expr_this_capture): Add new parameter
add_capture_p controlling whether the functions will try to
capture 'this' via the default capture.
(maybe_resolve_dummy): Likewise.
* cp-tree.h: Adjust prototypes.
* call.c, semantics.c: Change callers of these functions.
* call.c (build_new_method_call_1): Use the actual 'this' that
would be potentially captured for the overload resolution, instead
of the dummy object.
2014-05-08 Momchil Velikov <momchil.veli...@gmail.com>
PR c++/60463
PR c++/60755
* g++.dg/cpp0x/lambda/lambda-const-this.C: New testcase.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 857df57..bfedfef 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7726,7 +7726,11 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
if (DECL_DESTRUCTOR_P (fn))
name = complete_dtor_identifier;
- first_mem_arg = instance;
+ /* For the overload resolution we need to find the actual `this`
+ that would be captured if the call turns out to be to a
+ non-static member function. Do not actually capture it at this
+ point. */
+ first_mem_arg = maybe_resolve_dummy (instance, false);
/* Get the high-water mark for the CONVERSION_OBSTACK. */
p = conversion_obstack_alloc (0);
@@ -7864,7 +7868,7 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
&& !DECL_CONSTRUCTOR_P (fn)
&& is_dummy_object (instance))
{
- instance = maybe_resolve_dummy (instance);
+ instance = maybe_resolve_dummy (instance, true);
if (instance == error_mark_node)
call = error_mark_node;
else if (!is_dummy_object (instance))
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 34d3d20..ed8d099 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5890,8 +5890,8 @@ extern void insert_pending_capture_proxies (void);
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);
-extern tree maybe_resolve_dummy (tree);
+extern tree lambda_expr_this_capture (tree, bool);
+extern tree maybe_resolve_dummy (tree, bool);
extern tree nonlambda_method_basetype (void);
extern void maybe_add_lambda_conv_op (tree);
extern bool is_lambda_ignored_entity (tree);
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 5ba6f14..3ce9ebb 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -624,11 +624,12 @@ add_default_capture (tree lambda_stack, tree id, tree initializer)
return var;
}
-/* Return the capture pertaining to a use of 'this' in LAMBDA, in the form of an
- INDIRECT_REF, possibly adding it through default capturing. */
+/* Return the capture pertaining to a use of 'this' in LAMBDA, in the
+ form of an INDIRECT_REF, possibly adding it through default
+ capturing, if ADD_CAPTURE_P is false. */
tree
-lambda_expr_this_capture (tree lambda)
+lambda_expr_this_capture (tree lambda, bool add_capture_p)
{
tree result;
@@ -648,7 +649,8 @@ lambda_expr_this_capture (tree lambda)
/* Try to default capture 'this' if we can. */
if (!this_capture
- && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) != CPLD_NONE)
+ && (!add_capture_p
+ || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) != CPLD_NONE))
{
tree lambda_stack = NULL_TREE;
tree init = NULL_TREE;
@@ -708,9 +710,14 @@ lambda_expr_this_capture (tree lambda)
}
if (init)
- this_capture = add_default_capture (lambda_stack,
- /*id=*/this_identifier,
- init);
+ {
+ if (add_capture_p)
+ this_capture = add_default_capture (lambda_stack,
+ /*id=*/this_identifier,
+ init);
+ else
+ this_capture = init;
+ }
}
if (!this_capture)
@@ -742,7 +749,7 @@ lambda_expr_this_capture (tree lambda)
'this' capture. */
tree
-maybe_resolve_dummy (tree object)
+maybe_resolve_dummy (tree object, bool add_capture_p)
{
if (!is_dummy_object (object))
return object;
@@ -758,7 +765,7 @@ maybe_resolve_dummy (tree object)
{
/* In a lambda, need to go through 'this' capture. */
tree lam = CLASSTYPE_LAMBDA_EXPR (current_class_type);
- tree cap = lambda_expr_this_capture (lam);
+ tree cap = lambda_expr_this_capture (lam, add_capture_p);
object = build_x_indirect_ref (EXPR_LOCATION (object), cap,
RO_NULL, tf_warning_or_error);
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 4afb821..d925f5c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1675,7 +1675,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
object = maybe_dummy_object (scope, NULL);
}
- object = maybe_resolve_dummy (object);
+ object = maybe_resolve_dummy (object, true);
if (object == error_mark_node)
return error_mark_node;
@@ -2434,7 +2434,7 @@ finish_this_expr (void)
/* In a lambda expression, 'this' refers to the captured 'this'. */
if (LAMBDA_TYPE_P (type))
- result = lambda_expr_this_capture (CLASSTYPE_LAMBDA_EXPR (type));
+ result = lambda_expr_this_capture (CLASSTYPE_LAMBDA_EXPR (type), true);
else
result = current_class_ptr;
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-this.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-this.C
new file mode 100644
index 0000000..2de00d3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-this.C
@@ -0,0 +1,9 @@
+// PR c++/60463
+// PR c++/60755
+// { dg-do compile { target c++11 } }
+struct S {
+ void f(); // { dg-message "no known conversion for implicit 'this' parameter from 'const S\\*' to 'S\\*'" }
+ void g() const {
+ [=] { f(); } (); // { dg-error "no matching function for call to 'S::f\\(\\)'" }
+ }
+};