public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Marek Polacek <polacek@redhat.com>
To: Jason Merrill <jason@redhat.com>
Cc: GCC Patches <gcc-patches@gcc.gnu.org>, Jakub Jelinek <jakub@redhat.com>
Subject: Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions
Date: Mon, 17 Sep 2018 21:51:00 -0000	[thread overview]
Message-ID: <20180917213938.GL5587@redhat.com> (raw)
In-Reply-To: <20180914204521.GJ5587@redhat.com>

On Fri, Sep 14, 2018 at 04:45:22PM -0400, Marek Polacek wrote:
> On Fri, Sep 14, 2018 at 04:30:46PM -0400, Jason Merrill wrote:
> > On Fri, Sep 14, 2018 at 1:19 PM, Marek Polacek <polacek@redhat.com> wrote:
> > > This patch implements another bit of C++20, virtual calls in constant
> > > expression:
> > > <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1064r0.html>
> > > The basic idea is that since in a constant expression we know the dynamic
> > > type (to detect invalid code etc.), the restriction that prohibits virtual
> > > calls is unnecessary.
> > >
> > > Handling virtual function calls turned out to be fairly easy (as anticipated);
> > > I simply let the constexpr machinery figure out the dynamic type and then
> > > OBJ_TYPE_REF_TOKEN gives us the index into the virtual function table.  That
> > > way we get the function decl we're interested in, and cxx_eval_call_expression
> > > takes it from there.
> > >
> > > But handling pointer-to-virtual-member-functions doesn't work like that.
> > > get_member_function_from_ptrfunc creates a COND_EXPR which looks like
> > > if (pf.__pfn & 1) // is it a virtual function?
> > >   // yes, find the pointer in the vtable
> > > else
> > >   // no, just return the pointer
> > > so ideally we want to evaluate the then-branch.  Eventually it'll evaluate it
> > > to something like _ZTV2X2[2], but the vtable isn't constexpr so we'd end up
> > > with "not a constant expression" error.
> > 
> > Then let's mark the vtable as constexpr, there's no reason for it not to be.

Done.  But then I had to add indexes to the vtable's ctor (because find_array_ctor_elt
expects it), which broke an assert in gimple_get_virt_method_for_vtable.  But I
don't need the array_ref hack anymore!

Also, I had to set DECL_DECLARED_CONSTEXPR_P after maybe_commonize_var,
otherwise we run into the sorry in that function with -fno-weak...

> Ok, unfortunately it wasn't as easy as merely marking it DECL_DECLARED_CONSTEXPR_P
> in initialize_artificial_var because then I saw "used in its own initializer"
> error.  Which I don't know why, but now that I know you agree with this direction
> I can dig deeper.
>  
> > > Since the vtable initializer is
> > > a compile-time constant, I thought we could make it work by a hack as the one
> > > in cxx_eval_array_reference.  We'll then let cxx_eval_call_expression do its
> > > job and everything is hunky-dory.
> > >
> > > Except when it isn't: I noticed that the presence of _vptr doesn't make the
> > > class non-empty, and when cxx_eval_constant_expression saw a decl with an empty
> > > class type, it just evaluated it to { }.  But such a class still had gotten an
> > > initializer that looks like {.D.2082 = {._vptr.X2 = &_ZTV2X2 + 16}}.  So
> > > replacing it with { } will lose the proper initializer whereupon we fail.
> > > The check I've added to cxx_eval_constant_expression won't win any beauty
> > > contests but unfortunately EMPTY_CONSTRUCTOR_P doesn't work there.
> > 
> > Perhaps we should check !TYPE_POLYMORPHIC_P as well as
> > is_really_empty_class.  Perhaps there should be a predicate for that,
> > say, is_really_nearly_empty_class...

For now I've only added the !TYPE_POLYMORPHIC_P check, which works just fine.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-09-17  Marek Polacek  <polacek@redhat.com>

	P1064R0 - Allowing Virtual Function Calls in Constant Expressions
	* call.c (build_over_call): Add FIXME.
	* class.c (initialize_vtable): Mark the vtable as constexpr.
	(build_vtbl_initializer): Build vtable's constructor with indexes.
	* constexpr.c (cxx_eval_constant_expression): Don't ignore _vptr's
	initializer.  Handle OBJ_TYPE_REF.
	(potential_constant_expression_1): Handle OBJ_TYPE_REF.
	* decl.c (grokdeclarator): Change error to pedwarn.  Only warn when
	pedantic and not C++2a.

	* gimple-fold.c (gimple_get_virt_method_for_vtable): Remove assert.

	* g++.dg/cpp0x/constexpr-virtual5.C: Adjust dg-error.
	* g++.dg/cpp2a/constexpr-virtual1.C: New test.
	* g++.dg/cpp2a/constexpr-virtual2.C: New test.
	* g++.dg/cpp2a/constexpr-virtual3.C: New test.
	* g++.dg/cpp2a/constexpr-virtual4.C: New test.
	* g++.dg/cpp2a/constexpr-virtual5.C: New test.
	* g++.dg/cpp2a/constexpr-virtual6.C: New test.
	* g++.dg/cpp2a/constexpr-virtual7.C: New test.
	* g++.dg/cpp2a/constexpr-virtual8.C: New test.
	* g++.dg/cpp2a/constexpr-virtual9.C: New test.
	* g++.dg/diagnostic/virtual-constexpr.C: Skip for C++2a.  Use
	-pedantic-errors.  Adjust dg-error.

diff --git gcc/cp/call.c gcc/cp/call.c
index 69503ca7920..6c70874af40 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -8401,7 +8401,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 
   if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0
       /* Don't mess with virtual lookup in instantiate_non_dependent_expr;
-	 virtual functions can't be constexpr.  */
+	 virtual functions can't be constexpr.  FIXME Actually, no longer
+	 true in C++2a.  */
       && !in_template_function ())
     {
       tree t;
diff --git gcc/cp/class.c gcc/cp/class.c
index e950a7423f7..288033fe912 100644
--- gcc/cp/class.c
+++ gcc/cp/class.c
@@ -8681,6 +8681,10 @@ initialize_vtable (tree binfo, vec<constructor_elt, va_gc> *inits)
   layout_vtable_decl (binfo, vec_safe_length (inits));
   decl = get_vtbl_decl_for_binfo (binfo);
   initialize_artificial_var (decl, inits);
+  /* Mark the vtable as constexpr so that we can access its content
+     at compile time.  */
+  DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true;
+  DECL_DECLARED_CONSTEXPR_P (decl) = true;
   dump_vtable (BINFO_TYPE (binfo), binfo, decl);
 }
 
@@ -9266,6 +9270,7 @@ build_vtbl_initializer (tree binfo,
       tree vcall_index;
       tree fn, fn_original;
       tree init = NULL_TREE;
+      tree idx = build_int_cst (size_type_node, jx++);
 
       fn = BV_FN (v);
       fn_original = fn;
@@ -9369,7 +9374,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, NULL_TREE, init);
+	      CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
 	  else
 	    for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
 	      {
@@ -9377,11 +9382,11 @@ build_vtbl_initializer (tree binfo,
 				     fn, build_int_cst (NULL_TREE, i));
 		TREE_CONSTANT (fdesc) = 1;
 
-		CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, fdesc);
+		CONSTRUCTOR_APPEND_ELT (*inits, idx, fdesc);
 	      }
 	}
       else
-	CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, init);
+	CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
     }
 }
 
diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 88c73787961..aa33319875f 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -4209,7 +4209,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	 CONST_DECL for aggregate constants.  */
       if (lval)
 	return t;
+      /* is_really_empty_class doesn't take into account _vptr, so initializing
+	 otherwise empty class with { } would overwrite the initializer that
+	 initialize_vtable created for us.  */
       if (COMPLETE_TYPE_P (TREE_TYPE (t))
+	  && !TYPE_POLYMORPHIC_P (TREE_TYPE (t))
 	  && is_really_empty_class (TREE_TYPE (t)))
 	{
 	  /* If the class is empty, we aren't actually loading anything.  */
@@ -4778,7 +4782,6 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case MODOP_EXPR:
       /* GCC internal stuff.  */
     case VA_ARG_EXPR:
-    case OBJ_TYPE_REF:
     case NON_DEPENDENT_EXPR:
     case BASELINK:
     case OFFSET_REF:
@@ -4788,6 +4791,34 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       *non_constant_p = true;
       break;
 
+    case OBJ_TYPE_REF:
+      {
+	/* Virtual function call.  Let the constexpr machinery figure out
+	   the dynamic type.  */
+	int token = tree_to_shwi (OBJ_TYPE_REF_TOKEN (t));
+	tree obj = OBJ_TYPE_REF_OBJECT (t);
+	obj = cxx_eval_constant_expression (ctx, obj, lval, non_constant_p,
+					    overflow_p);
+	/* We expect something in the form of &x.D.2103.D.2094; get x. */
+	if (TREE_CODE (obj) != ADDR_EXPR)
+	  {
+	    if (!ctx->quiet)
+	      error_at (cp_expr_loc_or_loc (t, input_location),
+			"expression %qE is not a constant expression", t);
+	    *non_constant_p = true;
+	    return t;
+	  }
+	obj = TREE_OPERAND (obj, 0);
+	while (handled_component_p (obj))
+	  obj = TREE_OPERAND (obj, 0);
+	tree objtype = TREE_TYPE (obj);
+	/* 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));
+	r = TREE_VALUE (chain_index (token, virtuals));
+	break;
+      }
+
     case PLACEHOLDER_EXPR:
       /* Use of the value or address of the current object.  */
       if (tree ctor = lookup_placeholder (ctx, lval, TREE_TYPE (t)))
@@ -5871,7 +5902,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case OACC_UPDATE:
       /* GCC internal stuff.  */
     case VA_ARG_EXPR:
-    case OBJ_TYPE_REF:
     case TRANSACTION_EXPR:
     case ASM_EXPR:
     case AT_ENCODE_EXPR:
@@ -5880,6 +5910,14 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
 	error_at (loc, "expression %qE is not a constant expression", t);
       return false;
 
+    case OBJ_TYPE_REF:
+      if (cxx_dialect >= cxx2a)
+	/* In C++2a virtual calls can be constexpr, don't give up yet.  */
+	return true;
+      else if (flags & tf_error)
+	error_at (loc, "virtual functions cannot be constexpr before C++2a");
+      return false;
+
     case TYPEID_EXPR:
       /* -- a typeid expression whose operand is of polymorphic
             class type;  */
diff --git gcc/cp/decl.c gcc/cp/decl.c
index 50b60e89df5..da3749254e9 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -10854,12 +10854,13 @@ grokdeclarator (const cp_declarator *declarator,
 	  storage_class = sc_none;
 	  staticp = 0;
 	}
-      if (constexpr_p)
+      if (constexpr_p && cxx_dialect < cxx2a)
 	{
 	  gcc_rich_location richloc (declspecs->locations[ds_virtual]);
 	  richloc.add_range (declspecs->locations[ds_constexpr]);
-	  error_at (&richloc, "member %qD cannot be declared both %<virtual%> "
-		    "and %<constexpr%>", dname);
+	  pedwarn (&richloc, OPT_Wpedantic, "member %qD can be declared both "
+		   "%<virtual%> and %<constexpr%> only in -std=c++2a or "
+		   "-std=gnu++2a", dname);
 	}
     }
   friendp = decl_spec_seq_has_spec_p (declspecs, ds_friend);
diff --git gcc/gimple-fold.c gcc/gimple-fold.c
index 362ab59e9c0..dd30a30b8c5 100644
--- gcc/gimple-fold.c
+++ gcc/gimple-fold.c
@@ -6988,12 +6988,11 @@ gimple_get_virt_method_for_vtable (HOST_WIDE_INT token,
   access_index = offset / BITS_PER_UNIT / elt_size;
   gcc_checking_assert (offset % (elt_size * BITS_PER_UNIT) == 0);
 
-  /* This code makes an assumption that there are no 
-     indexed fileds produced by C++ FE, so we can directly index the array. */
+  /* The C++ FE now produces indexed fields but we can index the array
+     directly. */
   if (access_index < CONSTRUCTOR_NELTS (init))
     {
       fn = CONSTRUCTOR_ELT (init, access_index)->value;
-      gcc_checking_assert (!CONSTRUCTOR_ELT (init, access_index)->index);
       STRIP_NOPS (fn);
     }
   else
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-virtual5.C gcc/testsuite/g++.dg/cpp0x/constexpr-virtual5.C
index 2465f9d9b4f..5f9ab4d9c28 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-virtual5.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-virtual5.C
@@ -2,5 +2,5 @@
 // { dg-do compile { target c++11 } }
 
 struct S {
-  constexpr virtual int f() { return 1; }  // { dg-error "13:member .f. cannot be declared both .virtual. and .constexpr." }
+  constexpr virtual int f() { return 1; }  // { dg-error "13:member .f. can be declared both .virtual. and .constexpr." "" { target c++17_down } }
 };
diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-virtual1.C gcc/testsuite/g++.dg/cpp2a/constexpr-virtual1.C
index e69de29bb2d..fcf8cac6417 100644
--- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual1.C
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual1.C
@@ -0,0 +1,8 @@
+// P1064R0
+// { dg-do compile { target c++11 } }
+// { dg-options "-pedantic-errors" }
+
+struct X
+{
+  constexpr virtual int f() { return 0; } // { dg-error "member .f. can be declared both .virtual. and .constexpr. only" "" { target c++17_down } }
+};
diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C
index e69de29bb2d..9d82c5c59ac 100644
--- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C
@@ -0,0 +1,49 @@
+// P1064R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct X1
+{
+  virtual int f() const = 0;
+};
+
+struct X2: public X1
+{
+  constexpr virtual int f() const { return 2; }
+};
+
+struct X3: public X2
+{
+  virtual int f() const { return 3; }
+};
+
+struct X4: public X3
+{
+  constexpr virtual int f() const { return 4; }
+};
+
+constexpr int (X1::*pf)() const = &X1::f;
+
+constexpr X2 x2;
+static_assert(x2.f() == 2);
+static_assert((x2.*pf)() == 2);
+
+constexpr X1 const& r2 = x2;
+static_assert(r2.f() == 2);
+static_assert((r2.*pf)() == 2);
+
+constexpr X1 const* p2 = &x2;
+static_assert(p2->f() == 2);
+static_assert((p2->*pf)() == 2);
+
+constexpr X4 x4;
+static_assert(x4.f() == 4);
+static_assert((x4.*pf)() == 4);
+
+constexpr X1 const& r4 = x4;
+static_assert(r4.f() == 4);
+static_assert((r4.*pf)() == 4);
+
+constexpr X1 const* p4 = &x4;
+static_assert(p4->f() == 4);
+static_assert((p4->*pf)() == 4);
diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-virtual3.C gcc/testsuite/g++.dg/cpp2a/constexpr-virtual3.C
index e69de29bb2d..d71422fc4d0 100644
--- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual3.C
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual3.C
@@ -0,0 +1,52 @@
+// P1064R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct X1
+{
+  virtual int f() const = 0;
+};
+
+struct X2: public X1
+{
+  int i2 = 42;
+  constexpr virtual int f() const { return 2; }
+};
+
+struct X3: public X2
+{
+  int i3 = 42;
+  virtual int f() const { return 3; }
+};
+
+struct X4: public X3
+{
+  int i4 = 42;
+  constexpr virtual int f() const { return 4; }
+};
+
+constexpr int (X1::*pf)() const = &X1::f;
+
+constexpr X2 x2;
+static_assert(x2.f() == 2);
+static_assert((x2.*pf)() == 2);
+
+constexpr X1 const& r2 = x2;
+static_assert(r2.f() == 2);
+static_assert((r2.*pf)() == 2);
+
+constexpr X1 const* p2 = &x2;
+static_assert(p2->f() == 2);
+static_assert((p2->*pf)() == 2);
+
+constexpr X4 x4;
+static_assert(x4.f() == 4);
+static_assert((x4.*pf)() == 4);
+
+constexpr X1 const& r4 = x4;
+static_assert(r4.f() == 4);
+static_assert((r4.*pf)() == 4);
+
+constexpr X1 const* p4 = &x4;
+static_assert(p4->f() == 4);
+static_assert((p4->*pf)() == 4);
diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-virtual4.C gcc/testsuite/g++.dg/cpp2a/constexpr-virtual4.C
index e69de29bb2d..2038bebc6d1 100644
--- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual4.C
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual4.C
@@ -0,0 +1,57 @@
+// P1064R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct X1
+{
+  virtual int f1() const = 0;
+  virtual int f2() const = 0;
+  virtual int f3() const = 0;
+};
+
+struct X2: public X1
+{
+  constexpr virtual int f1() const { return 21; }
+  constexpr virtual int f2() const { return 22; }
+  constexpr virtual int f3() const { return 23; }
+};
+
+struct X3: public X2
+{
+  virtual int f1() const { return 31; }
+  virtual int f2() const { return 32; }
+  virtual int f3() const { return 33; }
+};
+
+struct X4: public X3
+{
+  constexpr virtual int f1() const { return 41; }
+  constexpr virtual int f2() const { return 42; }
+  constexpr virtual int f3() const { return 43; }
+};
+
+constexpr int (X1::*pf)() const = &X1::f2;
+
+constexpr X2 x2;
+static_assert(x2.f2() == 22);
+static_assert((x2.*pf)() == 22);
+
+constexpr X1 const& r2 = x2;
+static_assert(r2.f2() == 22);
+static_assert((r2.*pf)() == 22);
+
+constexpr X1 const* p2 = &x2;
+static_assert(p2->f2() == 22);
+static_assert((p2->*pf)() == 22);
+
+constexpr X4 x4;
+static_assert(x4.f2() == 42);
+static_assert((x4.*pf)() == 42);
+
+constexpr X1 const& r4 = x4;
+static_assert(r4.f2() == 42);
+static_assert((r4.*pf)() == 42);
+
+constexpr X1 const* p4 = &x4;
+static_assert(p4->f2() == 42);
+static_assert((p4->*pf)() == 42);
diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-virtual5.C gcc/testsuite/g++.dg/cpp2a/constexpr-virtual5.C
index e69de29bb2d..6d27990a8b6 100644
--- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual5.C
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual5.C
@@ -0,0 +1,60 @@
+// P1064R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct X1
+{
+  virtual int f1() const = 0;
+  virtual int f2() const = 0;
+  virtual int f3() const = 0;
+};
+
+struct X2: public X1
+{
+  int i2 = 42;
+  constexpr virtual int f1() const { return 21; }
+  constexpr virtual int f2() const { return 22; }
+  constexpr virtual int f3() const { return 23; }
+};
+
+struct X3: public X2
+{
+  int i3 = 42;
+  virtual int f1() const { return 31; }
+  virtual int f2() const { return 32; }
+  virtual int f3() const { return 33; }
+};
+
+struct X4: public X3
+{
+  int i4 = 42;
+  constexpr virtual int f1() const { return 41; }
+  constexpr virtual int f2() const { return 42; }
+  constexpr virtual int f3() const { return 43; }
+};
+
+constexpr int (X1::*pf)() const = &X1::f2;
+
+constexpr X2 x2;
+static_assert(x2.f2() == 22);
+static_assert((x2.*pf)() == 22);
+
+constexpr X1 const& r2 = x2;
+static_assert(r2.f2() == 22);
+static_assert((r2.*pf)() == 22);
+
+constexpr X1 const* p2 = &x2;
+static_assert(p2->f2() == 22);
+static_assert((p2->*pf)() == 22);
+
+constexpr X4 x4;
+static_assert(x4.f2() == 42);
+static_assert((x4.*pf)() == 42);
+
+constexpr X1 const& r4 = x4;
+static_assert(r4.f2() == 42);
+static_assert((r4.*pf)() == 42);
+
+constexpr X1 const* p4 = &x4;
+static_assert(p4->f2() == 42);
+static_assert((p4->*pf)() == 42);
diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-virtual6.C gcc/testsuite/g++.dg/cpp2a/constexpr-virtual6.C
index e69de29bb2d..ece5e703c32 100644
--- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual6.C
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual6.C
@@ -0,0 +1,25 @@
+// P1064R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct X1
+{
+  constexpr virtual X1 const *f() const { return this; }
+};
+
+struct Y
+{
+  int m = 0;
+};
+
+struct X2: public Y, public X1
+{
+  constexpr virtual X2 const *f() const { return this; }
+};
+
+constexpr X1 x1;
+static_assert(x1.f() == &x1);
+
+constexpr X2 x2;
+constexpr X1 const& r2 = x2;
+static_assert(r2.f() == &r2);
diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-virtual7.C gcc/testsuite/g++.dg/cpp2a/constexpr-virtual7.C
index e69de29bb2d..b0f499608ef 100644
--- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual7.C
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual7.C
@@ -0,0 +1,87 @@
+// P1064R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct X1
+{
+  virtual int f() const = 0;
+};
+
+struct X2: public X1
+{
+  constexpr virtual int f() const { return 2; }
+};
+
+struct X3: public X2
+{
+  virtual int f() const { return 3; }
+};
+
+struct X4: public X3
+{
+  constexpr virtual int f() const { return 4; }
+};
+
+constexpr int (X1::*pf)() const = &X1::f;
+
+constexpr X2 x2;
+
+struct S
+{
+  int i, j;
+  constexpr S() : i(x2.f()), j((x2.*pf)()) { }
+};
+
+static_assert(S().i == 2);
+static_assert(S().j == 2);
+
+constexpr X1 const& r2 = x2;
+
+struct S2
+{
+  int i, j;
+  constexpr S2() : i(r2.f()), j((r2.*pf)()) { }
+};
+
+static_assert(S2().i == 2);
+static_assert(S2().j == 2);
+
+constexpr X1 const* p2 = &x2;
+struct S3
+{
+  int i, j;
+  constexpr S3() : i(p2->f()), j((p2->*pf)()) { }
+};
+
+static_assert(S3().i == 2);
+static_assert(S3().j == 2);
+
+constexpr X4 x4;
+struct S4
+{
+  int i, j;
+  constexpr S4() : i(x4.f()), j((x4.*pf)()) { }
+};
+
+static_assert(S4().i == 4);
+static_assert(S4().j == 4);
+
+constexpr X1 const& r4 = x4;
+struct S5
+{
+  int i, j;
+  constexpr S5() : i(r4.f()), j((r4.*pf)()) { }
+};
+
+static_assert(S5().i == 4);
+static_assert(S5().j == 4);
+
+constexpr X1 const* p4 = &x4;
+struct S6
+{
+  int i, j;
+  constexpr S6() : i(p4->f()), j((p4->*pf)()) { }
+};
+
+static_assert(S6().i == 4);
+static_assert(S6().j == 4);
diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-virtual8.C gcc/testsuite/g++.dg/cpp2a/constexpr-virtual8.C
index e69de29bb2d..4a7cc972a91 100644
--- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual8.C
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual8.C
@@ -0,0 +1,50 @@
+// P1064R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+template<typename T>
+struct X1
+{
+  virtual T f() const = 0;
+};
+
+struct X2: public X1<int>
+{
+  constexpr virtual int f() const { return 2; }
+};
+
+struct X3: public X2
+{
+  virtual int f() const { return 3; }
+};
+
+struct X4: public X3
+{
+  constexpr virtual int f() const { return 4; }
+};
+
+constexpr int (X1<int>::*pf)() const = &X1<int>::f;
+
+constexpr X2 x2;
+static_assert(x2.f() == 2);
+static_assert((x2.*pf)() == 2);
+
+constexpr X1<int> const& r2 = x2;
+static_assert(r2.f() == 2);
+static_assert((r2.*pf)() == 2);
+
+constexpr X1<int> const* p2 = &x2;
+static_assert(p2->f() == 2);
+static_assert((p2->*pf)() == 2);
+
+constexpr X4 x4;
+static_assert(x4.f() == 4);
+static_assert((x4.*pf)() == 4);
+
+constexpr X1<int> const& r4 = x4;
+static_assert(r4.f() == 4);
+static_assert((r4.*pf)() == 4);
+
+constexpr X1<int> const* p4 = &x4;
+static_assert(p4->f() == 4);
+static_assert((p4->*pf)() == 4);
diff --git gcc/testsuite/g++.dg/cpp2a/constexpr-virtual9.C gcc/testsuite/g++.dg/cpp2a/constexpr-virtual9.C
index e69de29bb2d..3a12adc2659 100644
--- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual9.C
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual9.C
@@ -0,0 +1,83 @@
+// P1064R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct X1
+{
+  virtual int f() const = 0;
+  virtual int f(int) const = 0;
+  virtual int f(int, int) const = 0;
+};
+
+struct X2: public X1
+{
+  constexpr virtual int f() const { return 2; }
+  constexpr virtual int f(int) const { return 12; }
+  constexpr virtual int f(int, int) const { return 22; }
+};
+
+struct X3: public X2
+{
+  virtual int f() const { return 3; }
+  virtual int f(int) const { return 13; }
+  virtual int f(int, int) const { return 23; }
+};
+
+struct X4: public X3
+{
+  constexpr virtual int f() const { return 4; }
+  constexpr virtual int f(int) const { return 14; }
+  constexpr virtual int f(int, int) const { return 24; }
+};
+
+constexpr int (X1::*pf)() const = &X1::f;
+constexpr int (X1::*pf1)(int) const = &X1::f;
+constexpr int (X1::*pf2)(int, int) const = &X1::f;
+
+constexpr X2 x2;
+static_assert(x2.f() == 2);
+static_assert((x2.*pf)() == 2);
+static_assert(x2.f(1) == 12);
+static_assert((x2.*pf1)(1) == 12);
+static_assert(x2.f(1, 2) == 22);
+static_assert((x2.*pf2)(1, 2) == 22);
+
+constexpr X1 const& r2 = x2;
+static_assert(r2.f() == 2);
+static_assert((r2.*pf)() == 2);
+static_assert(r2.f(1) == 12);
+static_assert((r2.*pf1)(1) == 12);
+static_assert(r2.f(1, 2) == 22);
+static_assert((r2.*pf2)(1, 2) == 22);
+
+constexpr X1 const* p2 = &x2;
+static_assert(p2->f() == 2);
+static_assert((p2->*pf)() == 2);
+static_assert(p2->f(1) == 12);
+static_assert((p2->*pf1)(1) == 12);
+static_assert(p2->f(1, 2) == 22);
+static_assert((p2->*pf2)(1, 2) == 22);
+
+constexpr X4 x4;
+static_assert(x4.f() == 4);
+static_assert((x4.*pf)() == 4);
+static_assert(x4.f(1) == 14);
+static_assert((x4.*pf1)(1) == 14);
+static_assert(x4.f(1, 2) == 24);
+static_assert((x4.*pf2)(1, 2) == 24);
+
+constexpr X1 const& r4 = x4;
+static_assert(r4.f() == 4);
+static_assert((r4.*pf)() == 4);
+static_assert(r4.f(1) == 14);
+static_assert((r4.*pf1)(1) == 14);
+static_assert(r4.f(1, 2) == 24);
+static_assert((r4.*pf2)(1, 2) == 24);
+
+constexpr X1 const* p4 = &x4;
+static_assert(p4->f() == 4);
+static_assert((p4->*pf)() == 4);
+static_assert(p4->f(1) == 14);
+static_assert((p4->*pf1)(1) == 14);
+static_assert(p4->f(1, 2) == 24);
+static_assert((p4->*pf2)(1, 2) == 24);
diff --git gcc/testsuite/g++.dg/diagnostic/virtual-constexpr.C gcc/testsuite/g++.dg/diagnostic/virtual-constexpr.C
index 2c83236cae9..9223c692737 100644
--- gcc/testsuite/g++.dg/diagnostic/virtual-constexpr.C
+++ gcc/testsuite/g++.dg/diagnostic/virtual-constexpr.C
@@ -1,14 +1,15 @@
-// { dg-options "-fdiagnostics-show-caret" }
+// { dg-options "-fdiagnostics-show-caret -pedantic-errors" }
 // { dg-do compile { target c++11 } }
+// { dg-skip-if "virtual constexpr" { *-*-* } { "-std=gnu++2a" } { "" } }
 
 struct S
 {
-  virtual constexpr void foo();  // { dg-error "3:member .foo. cannot be declared both .virtual. and .constexpr." }
+  virtual constexpr void foo();  // { dg-error "3:member .foo. can be declared both .virtual. and .constexpr." }
 /* { dg-begin-multiline-output "" }
    virtual constexpr void foo();
    ^~~~~~~ ~~~~~~~~~
    { dg-end-multiline-output "" } */
-  constexpr virtual void bar();  // { dg-error "13:member .bar. cannot be declared both .virtual. and .constexpr." }
+  constexpr virtual void bar();  // { dg-error "13:member .bar. can be declared both .virtual. and .constexpr." }
 /* { dg-begin-multiline-output "" }
    constexpr virtual void bar();
    ~~~~~~~~~ ^~~~~~~

  reply	other threads:[~2018-09-17 21:39 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-09-14 17:21 Marek Polacek
2018-09-14 17:41 ` Jakub Jelinek
2018-09-14 19:43   ` C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v2) Marek Polacek
2018-09-14 20:32 ` C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions Jason Merrill
2018-09-14 20:46   ` Marek Polacek
2018-09-17 21:51     ` Marek Polacek [this message]
2018-09-18  3:48       ` Jason Merrill
2018-09-18 15:37         ` C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4) Marek Polacek
2018-09-18 18:36           ` Jason Merrill
2018-09-18 18:58             ` Marek Polacek
2018-09-19 13:27               ` Andreas Schwab
2018-09-19 14:19                 ` Marek Polacek
2018-09-19 15:10                   ` Andreas Schwab
2018-09-19 15:11                     ` Marek Polacek
2018-09-19 17:35                       ` Jason Merrill
2018-09-20  8:26                         ` Andreas Schwab
2018-09-20  9:23                           ` Jakub Jelinek
2018-09-27  7:16                             ` Jason Merrill
2018-09-27 23:18                               ` Marek Polacek
2018-09-28  5:44                                 ` Jason Merrill
2018-09-28  6:48                                 ` Jakub Jelinek
2018-12-08  9:07                               ` [C++ PATCH] FIx constexpr virtual function call handling on ia64 (PR c++/87861) Jakub Jelinek
2018-12-11 18:53                                 ` Jason Merrill
2018-10-08 14:18                             ` C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4) Andreas Schwab
2018-10-10 11:53                               ` Jakub Jelinek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180917213938.GL5587@redhat.com \
    --to=polacek@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jakub@redhat.com \
    --cc=jason@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).