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]

[C++ PATCH] FIx constexpr virtual function call handling on ia64 (PR c++/87861)


On Thu, Sep 27, 2018 at 01:15:46AM -0400, Jason Merrill wrote:
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:33:26: error: non-constant condition for static assertion
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:33:23: error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr' function
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:37:27: error: non-constant condition for static assertion
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:37:24: error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr' function
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:41:26: error: non-constant condition for static assertion
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:41:23: error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr' function
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:45:26: error: non-constant condition for static assertion
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:45:23: error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr' function
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:49:27: error: non-constant condition for static assertion
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:49:24: error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr' function
> >> compiler exited with status 1
> >> FAIL: g++.dg/cpp2a/constexpr-virtual2.C   (test for excess errors)
> >
> > I think the primary problem here is:
> >       /* When using function descriptors, the address of the
> >          vtable entry is treated as a function pointer.  */
> >       if (TARGET_VTABLE_USES_DESCRIPTORS)
> >         e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
> >                      cp_build_addr_expr (e2, complain));
> > in typeck.c, on non-descriptor targets we have an INDIRECT_REF where we
> > read the vtable function pointer.  On ia64, the above optimizes the
> > INDIRECT_REF away, so what the cxx_eval_call_expression actually gets
> > after constexpr evaluating the CALL_FN is not ADDR_EXPR of a function,
> > but the address of the function descriptor (e.g. &_ZTV2X2 + 16 ).
> >
> > So, perhaps in cxx_eval_call_expression we need:
> >        if (TREE_CODE (fun) == ADDR_EXPR)
> >         fun = TREE_OPERAND (fun, 0);
> > +      else if (TARGET_VTABLE_USES_DESCRIPTORS
> > +              && TREE_CODE (fun) == POINTER_PLUS_EXPR
> > +              && ...)
> > where we verify that p+ first argument is ADDR_EXPR of a virtual table,
> > second arg is INTEGER_CST and just walk the DECL_INITIAL of that, finding
> > the FDESC_EXPR at the right offset (therefore, I believe you need following
> > rather than the patch you've posted, so that you can actually find it) and
> > finally pick the function from the FDESC_EXPR entry.
> > Makes me wonder what happens with indirect calls in constexpr evaluation,
> > e.g. if I do:
> > constexpr int bar () { return 42; }
> > constexpr int foo () { int (*fn) () = bar; return fn (); }
> > static_assert (foo () == 42);
> > but apparently this works.
> >
> > --- gcc/cp/class.c.jj   2018-09-20 09:56:59.229751895 +0200
> > +++ gcc/cp/class.c      2018-09-20 10:12:17.447370890 +0200
> > @@ -9266,7 +9266,6 @@ build_vtbl_initializer (tree binfo,
> >        tree vcall_index;
> >        tree fn, fn_original;
> >        tree init = NULL_TREE;
> > -      tree idx = size_int (jx++);
> >
> >        fn = BV_FN (v);
> >        fn_original = fn;
> > @@ -9370,7 +9369,7 @@ build_vtbl_initializer (tree binfo,
> >           int i;
> >           if (init == size_zero_node)
> >             for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
> > -             CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
> > +             CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init);
> >           else
> >             for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
> >               {
> > @@ -9378,11 +9377,11 @@ build_vtbl_initializer (tree binfo,
> >                                      fn, build_int_cst (NULL_TREE, i));
> >                 TREE_CONSTANT (fdesc) = 1;
> >
> > -               CONSTRUCTOR_APPEND_ELT (*inits, idx, fdesc);
> > +               CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), fdesc);
> >               }
> >         }
> >        else
> > -       CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
> > +       CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init);
> >      }
> >  }
> 
> This patch is OK.  And your suggestion for cxx_eval_call_expression
> sounds right, too.  Marek, will you follow up on that?

Here is the full patch.  Besides the above already posted hunks and
proposed cxx_eval_call_expression changes I had to also divide token
in the OBJ_TYPE_REF handling by TARGET_VTABLE_USES_DESCRIPTORS, because
DECL_VINDEX of the second virtual table function is there 2 and of the third
4 etc.

Tested with a cross to ia64-linux on all the constexpr-virtual*.C testcases,
Jeff tested it on ia64-linux native and I've bootstrapped/regtested on
x86_64-linux and i686-linux.  Ok for trunk?

2018-12-08  Jakub Jelinek  <jakub@redhat.com>

	PR c++/87861
	* class.c (build_vtbl_initializer): For TARGET_VTABLE_USES_DESCRIPTORS
	bump index for each added word.
	* constexpr.c (find_array_ctor_elt): Add forward declaration.
	(cxx_eval_call_expression): Handle TARGET_VTABLE_USES_DESCRIPTORS
	vtable calls.
	(cxx_eval_constant_expression) <case OBJ_TYPE_REF>: Divide token
	by TARGET_VTABLE_USES_DESCRIPTORS if non-zero.

--- gcc/cp/class.c.jj	2018-12-07 00:23:15.006998887 +0100
+++ gcc/cp/class.c	2018-12-07 09:39:52.736059638 +0100
@@ -9351,7 +9351,6 @@ build_vtbl_initializer (tree binfo,
       tree vcall_index;
       tree fn, fn_original;
       tree init = NULL_TREE;
-      tree idx = size_int (jx++);
 
       fn = BV_FN (v);
       fn_original = fn;
@@ -9455,7 +9454,7 @@ build_vtbl_initializer (tree binfo,
 	  int i;
 	  if (init == size_zero_node)
 	    for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
-	      CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
+	      CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init);
 	  else
 	    for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
 	      {
@@ -9463,11 +9462,11 @@ build_vtbl_initializer (tree binfo,
 				     fn, build_int_cst (NULL_TREE, i));
 		TREE_CONSTANT (fdesc) = 1;
 
-		CONSTRUCTOR_APPEND_ELT (*inits, idx, fdesc);
+		CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), fdesc);
 	      }
 	}
       else
-	CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
+	CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init);
     }
 }
 
--- gcc/cp/constexpr.c.jj	2018-12-07 00:23:41.000000000 +0100
+++ gcc/cp/constexpr.c	2018-12-07 10:59:46.840562829 +0100
@@ -41,6 +41,9 @@ do {									\
     return t;								\
  } while (0)
 
+static HOST_WIDE_INT find_array_ctor_elt (tree ary, tree dindex,
+					  bool insert = false);
+
 /* Returns true iff FUN is an instantiation of a constexpr function
    template or a defaulted constexpr function.  */
 
@@ -1516,6 +1519,36 @@ cxx_eval_call_expression (const constexp
       STRIP_NOPS (fun);
       if (TREE_CODE (fun) == ADDR_EXPR)
 	fun = TREE_OPERAND (fun, 0);
+      /* For TARGET_VTABLE_USES_DESCRIPTORS targets, there is no
+	 indirection, the called expression is a pointer into the
+	 virtual table which should contain FDESC_EXPR.  Extract the
+	 FUNCTION_DECL from there.  */
+      else if (TARGET_VTABLE_USES_DESCRIPTORS
+	       && TREE_CODE (fun) == POINTER_PLUS_EXPR
+	       && TREE_CODE (TREE_OPERAND (fun, 0)) == ADDR_EXPR
+	       && TREE_CODE (TREE_OPERAND (fun, 1)) == INTEGER_CST)
+	{
+	  tree d = TREE_OPERAND (TREE_OPERAND (fun, 0), 0);
+	  if (VAR_P (d)
+	      && DECL_VTABLE_OR_VTT_P (d)
+	      && TREE_CODE (TREE_TYPE (d)) == ARRAY_TYPE
+	      && TREE_TYPE (TREE_TYPE (d)) == vtable_entry_type
+	      && DECL_INITIAL (d)
+	      && TREE_CODE (DECL_INITIAL (d)) == CONSTRUCTOR)
+	    {
+	      tree i = int_const_binop (TRUNC_DIV_EXPR, TREE_OPERAND (fun, 1),
+					TYPE_SIZE_UNIT (vtable_entry_type));
+	      HOST_WIDE_INT idx = find_array_ctor_elt (DECL_INITIAL (d), i);
+	      if (idx >= 0)
+		{
+		  tree fdesc
+		    = (*CONSTRUCTOR_ELTS (DECL_INITIAL (d)))[idx].value;
+		  if (TREE_CODE (fdesc) == FDESC_EXPR
+		      && integer_zerop (TREE_OPERAND (fdesc, 1)))
+		    fun = TREE_OPERAND (fdesc, 0);
+		}
+	    }
+	}
     }
   if (TREE_CODE (fun) != FUNCTION_DECL)
     {
@@ -2240,7 +2273,7 @@ array_index_cmp (tree key, tree index)
    if none.  If INSERT is true, insert a matching element rather than fail.  */
 
 static HOST_WIDE_INT
-find_array_ctor_elt (tree ary, tree dindex, bool insert = false)
+find_array_ctor_elt (tree ary, tree dindex, bool insert)
 {
   if (tree_int_cst_sgn (dindex) < 0)
     return -1;
@@ -4834,6 +4867,8 @@ cxx_eval_constant_expression (const cons
 	/* Find the function decl in the virtual functions list.  TOKEN is
 	   the DECL_VINDEX that says which function we're looking for.  */
 	tree virtuals = BINFO_VIRTUALS (TYPE_BINFO (objtype));
+	if (TARGET_VTABLE_USES_DESCRIPTORS)
+	  token /= MAX (TARGET_VTABLE_USES_DESCRIPTORS, 1);
 	r = TREE_VALUE (chain_index (token, virtuals));
 	break;
       }


	Jakub


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