diff mbox

[C++] PR 53186

Message ID 4FA264FD.1040102@oracle.com
State New
Headers show

Commit Message

Paolo Carlini May 3, 2012, 10:59 a.m. UTC
On 05/03/2012 03:27 AM, Paolo Carlini wrote:
> Hi,
>
> Vincenzo reported today that the work done by Roberto on 
> devirtualizing final methods, doesn't cover operators (of all sorts). 
> Thus I prepared the below, which passes the testsuite on x86_64-linux.
... I have an alternate proposal, which probably I like better, and also 
commonizes the bits added by Roberto to a function working on the 
LOOKUP_* flags. Also passes testing on x86_64-linux.

Thanks,
Paolo.

//////////////////////////
/cp
2012-05-03  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/53186
	* call.c (maybe_final_flags): New.
	(build_op_call_1, build_new_op_1, convert_like_real,
	build_new_method_call_1): Use it.

/testsuite
2012-05-03  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/53186
	* g++.dg/other/final2.C: New.

Comments

Jason Merrill May 3, 2012, 1:08 p.m. UTC | #1
What if we moved all the devirtualization logic from 
build_new_method_call_1 to build_over_call?

Jason
diff mbox

Patch

Index: cp/call.c
===================================================================
--- cp/call.c	(revision 187058)
+++ cp/call.c	(working copy)
@@ -4031,6 +4031,27 @@  build_operator_new_call (tree fnname, VEC(tree,gc)
    return build_over_call (cand, LOOKUP_NORMAL, complain);
 }
 
+/* If CAND can be devirtualized, because either the individual
+   method or the whole class type is declared final, return
+   FLAGS | LOOKUP_NONVIRTUAL, otherwise FLAGS.  */
+
+static int
+maybe_final_flags (struct z_candidate *cand, int flags)
+{
+  tree fn = cand->fn;
+  tree fntype = TREE_TYPE (fn);
+
+  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
+
+  if (DECL_FINAL_P (fn)
+      || (TREE_CODE (fntype) == METHOD_TYPE
+	  && CLASSTYPE_FINAL (TYPE_METHOD_BASETYPE (fntype))))
+    /* We can devirtualize.  */
+    flags |= LOOKUP_NONVIRTUAL;
+
+  return flags;
+}
+
 /* Build a new call to operator().  This may change ARGS.  */
 
 static tree
@@ -4149,7 +4170,8 @@  build_op_call_1 (tree obj, VEC(tree,gc) **args, ts
 	 DECL_NAME here.  */
       else if (TREE_CODE (cand->fn) == FUNCTION_DECL
 	       && DECL_OVERLOADED_OPERATOR_P (cand->fn) == CALL_EXPR)
-	result = build_over_call (cand, LOOKUP_NORMAL, complain);
+	result = build_over_call (cand, maybe_final_flags (cand, LOOKUP_NORMAL),
+				  complain);
       else
 	{
 	  obj = convert_like_with_context (cand->convs[0], obj, cand->fn, -1,
@@ -5163,7 +5185,9 @@  build_new_op_1 (enum tree_code code, int flags, tr
 	  if (resolve_args (arglist, complain) == NULL)
 	    result = error_mark_node;
 	  else
-	    result = build_over_call (cand, LOOKUP_NORMAL, complain);
+	    result = build_over_call (cand,
+				      maybe_final_flags (cand, LOOKUP_NORMAL),
+				      complain);
 	}
       else
 	{
@@ -5755,7 +5779,8 @@  convert_like_real (conversion *convs, tree expr, t
 	for (i = 0; i < cand->num_convs; ++i)
 	  cand->convs[i]->user_conv_p = true;
 
-	expr = build_over_call (cand, LOOKUP_NORMAL, complain);
+	expr = build_over_call (cand, maybe_final_flags (cand, LOOKUP_NORMAL),
+				complain);
 
 	/* If this is a constructor or a function returning an aggr type,
 	   we need to build up a TARGET_EXPR.  */
@@ -7417,9 +7442,9 @@  build_new_method_call_1 (tree instance, tree fns,
 	    {
 	      /* Optimize away vtable lookup if we know that this function
 		 can't be overridden.  */
+	      flags = maybe_final_flags (cand, flags);
 	      if (DECL_VINDEX (fn) && ! (flags & LOOKUP_NONVIRTUAL)
-		  && (resolves_to_fixed_type_p (instance, 0)
-		      || DECL_FINAL_P (fn) || CLASSTYPE_FINAL (basetype)))
+		  && resolves_to_fixed_type_p (instance, 0))
 		flags |= LOOKUP_NONVIRTUAL;
               if (explicit_targs)
                 flags |= LOOKUP_EXPLICIT_TMPL_ARGS;
Index: testsuite/g++.dg/other/final2.C
===================================================================
--- testsuite/g++.dg/other/final2.C	(revision 0)
+++ testsuite/g++.dg/other/final2.C	(revision 0)
@@ -0,0 +1,27 @@ 
+// PR c++/53186
+// { dg-options "-fdump-tree-original -std=c++11"  }
+
+struct F1
+{
+  virtual void operator()() final;
+  virtual operator int() final;
+  virtual int operator++() final;
+};
+
+struct F2 final
+{
+  virtual void operator()();
+  virtual operator int();
+  virtual int operator++();
+};
+
+void fooF1(F1& a) { a(); int m = a; ++a; }
+void fooF2(F2& a) { a(); int m = a; ++a; }
+
+// { dg-final { scan-tree-dump-times "F1::operator\\(\\)" 1 "original" } }
+// { dg-final { scan-tree-dump-times "F1::operator int" 1 "original" } }
+// { dg-final { scan-tree-dump-times "F1::operator\\+\\+" 1 "original" } }
+// { dg-final { scan-tree-dump-times "F2::operator\\(\\)" 1 "original" } }
+// { dg-final { scan-tree-dump-times "F2::operator int" 1 "original" } }
+// { dg-final { scan-tree-dump-times "F2::operator\\+\\+" 1 "original" } }
+// { dg-final { cleanup-tree-dump "original" } }