re PR c++/51494 (Legal program rejection - capturing "this" when using static method...
authorJason Merrill <jason@redhat.com>
Fri, 8 Mar 2013 16:03:48 +0000 (11:03 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 8 Mar 2013 16:03:48 +0000 (11:03 -0500)
PR c++/51494
PR c++/51884
PR c++/56222
* tree.c (maybe_dummy_object): Don't capture 'this'.
* semantics.c (maybe_resolve_dummy): New.
(finish_non_static_data_member): Use it.
(finish_qualified_id_expr): Don't test is_dummy_object.
* cp-tree.h: Declare maybe_resolve_dummy.
* call.c (build_new_method_call_1): Use it.

From-SVN: r196549

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

index 14647610e4f19e7b6340116a5bb6da9b62bed5ff..f9731a5538e234ce79d8103126a9e34f0e2f0dc3 100644 (file)
@@ -1,5 +1,15 @@
 2013-03-08  Jason Merrill  <jason@redhat.com>
 
+       PR c++/51494
+       PR c++/51884
+       PR c++/56222
+       * tree.c (maybe_dummy_object): Don't capture 'this'.
+       * semantics.c (maybe_resolve_dummy): New.
+       (finish_non_static_data_member): Use it.
+       (finish_qualified_id_expr): Don't test is_dummy_object.
+       * cp-tree.h: Declare maybe_resolve_dummy.
+       * call.c (build_new_method_call_1): Use it.
+
        PR c++/56567
        * semantics.c (apply_deduced_return_type): Don't allow returning
        std::initializer_list.
index 4eb38ec73e9f8c4e337e74f3230e325f9a085608..530835b87c83823939087849eccbdbd8a877bdd3 100644 (file)
@@ -7627,6 +7627,7 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
       else
        {
          fn = cand->fn;
+         call = NULL_TREE;
 
          if (!(flags & LOOKUP_NONVIRTUAL)
              && DECL_PURE_VIRTUAL_P (fn)
@@ -7644,12 +7645,26 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
          if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
              && is_dummy_object (instance_ptr))
            {
-             if (complain & tf_error)
-               error ("cannot call member function %qD without object",
-                      fn);
-             call = error_mark_node;
+             instance = maybe_resolve_dummy (instance);
+             if (instance == error_mark_node)
+               call = error_mark_node;
+             else if (!is_dummy_object (instance))
+               {
+                 /* We captured 'this' in the current lambda now that
+                    we know we really need it.  */
+                 instance_ptr = build_this (instance);
+                 cand->first_arg = instance_ptr;
+               }
+             else
+               {
+                 if (complain & tf_error)
+                   error ("cannot call member function %qD without object",
+                          fn);
+                 call = error_mark_node;
+               }
            }
-         else
+
+         if (call != error_mark_node)
            {
              /* Optimize away vtable lookup if we know that this
                 function can't be overridden.  We need to check if
index 4a597d8b3a64c74b060e88363d7307b5bd859106..c3b2aecf3b1cd1eb8b8948436a954e5dffc4a304 100644 (file)
@@ -5722,6 +5722,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);
+extern tree maybe_resolve_dummy                        (tree);
 extern tree nonlambda_method_basetype          (void);
 extern void maybe_add_lambda_conv_op            (tree);
 extern bool is_lambda_ignored_entity            (tree);
index d605de9631f87ed42c5ed6aff0055a96bbbe73fb..d11a4e4b2180c539588ec8cb5b97c4bec84e7c31 100644 (file)
@@ -1544,6 +1544,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
       object = maybe_dummy_object (scope, NULL);
     }
 
+  object = maybe_resolve_dummy (object);
   if (object == error_mark_node)
     return error_mark_node;
 
@@ -1778,15 +1779,14 @@ finish_qualified_id_expr (tree qualifying_class,
     }
   else if (BASELINK_P (expr) && !processing_template_decl)
     {
-      tree ob;
-
       /* See if any of the functions are non-static members.  */
       /* If so, the expression may be relative to 'this'.  */
       if (!shared_member_p (expr)
-         && (ob = maybe_dummy_object (qualifying_class, NULL),
-             !is_dummy_object (ob)))
+         && current_class_ptr
+         && DERIVED_FROM_P (qualifying_class,
+                            current_nonlambda_class_type ()))
        expr = (build_class_member_access_expr
-               (ob,
+               (maybe_dummy_object (qualifying_class, NULL),
                 expr,
                 BASELINK_ACCESS_BINFO (expr),
                 /*preserve_reference=*/false,
@@ -9534,6 +9534,34 @@ lambda_expr_this_capture (tree lambda)
   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.  */
+
+tree
+maybe_resolve_dummy (tree object)
+{
+  if (!is_dummy_object (object))
+    return object;
+
+  tree type = TYPE_MAIN_VARIANT (TREE_TYPE (object));
+  gcc_assert (TREE_CODE (type) != POINTER_TYPE);
+
+  if (type != current_class_type
+      && current_class_type
+      && LAMBDA_TYPE_P (current_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);
+      object = build_x_indirect_ref (EXPR_LOCATION (object), cap,
+                                    RO_NULL, tf_warning_or_error);
+    }
+
+  return object;
+}
+
 /* Returns the method basetype of the innermost non-lambda function, or
    NULL_TREE if none.  */
 
index b57b44ad149d04e38a9f6d6e0557f6cd492f0609..178b80aa24fdabed8b47c79ebf0867ad5b6a5413 100644 (file)
@@ -2863,13 +2863,6 @@ maybe_dummy_object (tree type, tree* binfop)
       && (same_type_ignoring_top_level_qualifiers_p
          (TREE_TYPE (current_class_ref), context)))
     decl = current_class_ref;
-  else if (current != current_class_type
-          && context == nonlambda_method_basetype ())
-    /* In a lambda, need to go through 'this' capture.  */
-    decl = (build_x_indirect_ref
-           (input_location, (lambda_expr_this_capture
-                             (CLASSTYPE_LAMBDA_EXPR (current_class_type))),
-            RO_NULL, tf_warning_or_error));
   else
     decl = build_dummy_object (context);
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this11.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this11.C
new file mode 100644 (file)
index 0000000..2618295
--- /dev/null
@@ -0,0 +1,22 @@
+// PR c++/51494, c++/56222
+// Uses of static members and creating pointers to members aren't odr-uses
+// of 'this'.
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+  static void f() {}
+  static int i;
+  int j;
+  void f(int);
+
+  void foo()
+  {
+    [] () {
+      ++i;
+      f();
+      &A::j;
+      (void(*)())&A::f;
+    };
+  }
+};