This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Fix PR c++/60463, PR c++/60755 Incorrect discard of const qualifier


On 14.04.2014 23:53, Momchil Velikov wrote:

Ping

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 and regtested again with xgcc (GCC) 4.10.0 20140430 (experimental)
[master revision b069c2a:edc7cc5:af379dd3ed2b932a506437bca77ea4f4c320dbb4]
with no regressions on x86_64-unknown-linux-gnu.

~chill

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index b201825..bb89e8f 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,17 @@
+2014-04-30  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-04-29  Jason Merrill  <jason@redhat.com>
 
 	DR 1351
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 8c55c32..a3aaebb 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7727,7 +7727,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);
@@ -7865,7 +7869,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 55ecc4e..4a45cc1 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5889,8 +5889,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 0b8b46a..3de1f15 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -620,11 +620,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;
 
@@ -644,7 +645,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;
@@ -704,9 +706,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)
@@ -738,7 +745,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;
@@ -754,7 +761,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 3f8ca44..2632fd6 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/ChangeLog b/gcc/testsuite/ChangeLog
index de10503..df792c8 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2014-04-30  Momchil Velikov  <momchil.velikov@gmail.com>
+
+	PR c++/60463
+	PR c++/60755
+	* g++.dg/cpp0x/lambda/lambda-const-this.C: New testcase.
+
 2014-04-30  Marek Polacek  <polacek@redhat.com>
 
 	PR c/60139
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\\(\\)'" }
+  }
+};

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]