diff mbox

Fix PR c++/60463, PR c++/60755 Incorrect discard of const qualifier

Message ID 536C9155.1090701@gmail.com
State New
Headers show

Commit Message

Momchil Velikov May 9, 2014, 8:27 a.m. UTC
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.velikov@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.velikov@gmail.com>

	PR c++/60463
	PR c++/60755
	* g++.dg/cpp0x/lambda/lambda-const-this.C: New testcase.

Comments

Jason Merrill May 9, 2014, 8:07 p.m. UTC | #1
Thanks for the patch, and for pinging me directly.

It looks like you don't have a copyright assignment on file; this and 
your other patch are small enough not to need one, but if you're going 
to continue working on GCC it would be good to get on file so that it 
doesn't hold up future patches.  See http://gcc.gnu.org/contribute.html 
for more information.

I'm going to apply this patch to trunk.

Jason
diff mbox

Patch

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\\(\\)'" }
+  }
+};