re PR c++/60463 (Lambda function can call a non-const member function with const...
authorMomchil Velikov <momchil.velikov@gmail.com>
Fri, 9 May 2014 20:07:45 +0000 (20:07 +0000)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 9 May 2014 20:07:45 +0000 (16:07 -0400)
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.

From-SVN: r210292

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/lambda.c
gcc/cp/semantics.c
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const-this.C [new file with mode: 0644]

index ea813a98d2ea34b078097b46516af844c886588a..5ddf555923da1ee278ffac661bdeb6d42ab151b4 100644 (file)
@@ -1,3 +1,17 @@
+2014-05-09  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-09  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * pt.c (convert_nontype_argument_function): Add tsubst_flags_t
index 9e83c4a8b73ae8b0cbe8f657e2901cb5cc6e911e..254b43a24279699afe510cece0e50a7228eea104 100644 (file)
@@ -7760,7 +7760,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);
@@ -7898,7 +7902,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))
index 34d3d2033362ab1ea44aa77b377c0a7d73f70bf9..ed8d099bda88b21c4f8416be37e3c5deab5d86c6 100644 (file)
@@ -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);
index 5ba6f141b72dd601ba68fbd5ad4dac9b5d3a5eb7..3ce9ebb7f1f463ef5dd561888559cf731d05210f 100644 (file)
@@ -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);
     }
index 4afb821de06ebfd78b61b3a68e795a47ed9bfa20..d925f5ced40e034b95142918d2678e6c0658aaad 100644 (file)
@@ -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 (file)
index 0000000..2de00d3
--- /dev/null
@@ -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\\(\\)'" }
+  }
+};