P1064R0 - Allowing Virtual Function Calls in Constant Expressions
authorMarek Polacek <polacek@redhat.com>
Tue, 18 Sep 2018 19:16:28 +0000 (19:16 +0000)
committerMarek Polacek <mpolacek@gcc.gnu.org>
Tue, 18 Sep 2018 19:16:28 +0000 (19:16 +0000)
P1064R0 - Allowing Virtual Function Calls in Constant Expressions
* call.c (build_over_call): No longer check if we're outside a template
function.
* class.c (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 (maybe_commonize_var): Bail out for any DECL_ARTIFICIAL.
(initialize_artificial_var): Mark the variable as constexpr.
(grokdeclarator): Change error to pedwarn.  Only warn when
pedantic and not C++2a.

* gimple-fold.c (gimple_get_virt_method_for_vtable): Adjust 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.

From-SVN: r264408

19 files changed:
gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/constexpr.c
gcc/cp/decl.c
gcc/gimple-fold.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/constexpr-virtual5.C
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/virtual-constexpr.C

index 92b878f2300d66a02c5087150dd69a0aff75ff34..69e2e147bb90c9443c743821def3972e3aa4e600 100644 (file)
@@ -1,3 +1,8 @@
+2018-09-18  Marek Polacek  <polacek@redhat.com>
+
+       P1064R0 - Allowing Virtual Function Calls in Constant Expressions
+       * gimple-fold.c (gimple_get_virt_method_for_vtable): Adjust assert.
+
 2018-09-18  Segher Boessenkool  <segher@kernel.crashing.org>
 
        * config/rs6000/rs6000.md: Remove old "Cygnus sibcall" comment.
index fdc1247746deda1742f8aafec95b618d15ebd6c2..7ea4b6d0f2ef3e6b25ea957eda6b33d9021a7fd2 100644 (file)
@@ -1,3 +1,18 @@
+2018-09-18  Marek Polacek  <polacek@redhat.com>
+
+       P1064R0 - Allowing Virtual Function Calls in Constant Expressions
+       * call.c (build_over_call): No longer check if we're outside a template
+       function.
+       * class.c (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 (maybe_commonize_var): Bail out for any DECL_ARTIFICIAL.
+       (initialize_artificial_var): Mark the variable as constexpr.
+       (grokdeclarator): Change error to pedwarn.  Only warn when
+       pedantic and not C++2a.
+
 2018-09-18  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/85065
index 69503ca7920ad9b92866da57f898afddbcd20650..ddf0ed044a023668cd955b057fa1234a486a3e9b 100644 (file)
@@ -8399,10 +8399,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
       && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL)
     maybe_warn_class_memaccess (input_location, fn, args);
 
-  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.  */
-      && !in_template_function ())
+  if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
     {
       tree t;
       tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (argarray[0])),
index e950a7423f7377c74e408dc43baa489b8fd94746..9ca464418717f36439ddacd1a172c71853d2e1c1 100644 (file)
@@ -9266,6 +9266,7 @@ 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;
@@ -9369,7 +9370,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 +9378,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);
     }
 }
 
index 88c737879614386d1022a80861d7b1ca754874bb..aa33319875fcad1cd87fefbb802e46dd0706a5f2 100644 (file)
@@ -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;  */
index 50b60e89df50803222339ed5a1b8ac91af709c3d..827c172033539f7121d056b61f09a714cfd81bbe 100644 (file)
@@ -5583,11 +5583,13 @@ layout_var_decl (tree decl)
 void
 maybe_commonize_var (tree decl)
 {
+  /* Don't mess with __FUNCTION__ and similar.  */
+  if (DECL_ARTIFICIAL (decl))
+    return;
+
   /* Static data in a function with comdat linkage also has comdat
      linkage.  */
   if ((TREE_STATIC (decl)
-       /* Don't mess with __FUNCTION__.  */
-       && ! DECL_ARTIFICIAL (decl)
        && DECL_FUNCTION_SCOPE_P (decl)
        && vague_linkage_p (DECL_CONTEXT (decl)))
       || (TREE_PUBLIC (decl) && DECL_INLINE_VAR_P (decl)))
@@ -6774,6 +6776,10 @@ initialize_artificial_var (tree decl, vec<constructor_elt, va_gc> *v)
   gcc_assert (TREE_CODE (init) == CONSTRUCTOR);
   DECL_INITIAL (decl) = init;
   DECL_INITIALIZED_P (decl) = 1;
+  /* Mark the decl 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;
   determine_visibility (decl);
   layout_var_decl (decl);
   maybe_commonize_var (decl);
@@ -10854,12 +10860,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);
index 362ab59e9c00ec338fa3594db0186442df8b82f2..1e84722d22d22204d6a6568dd4222ae08bb67a3f 100644 (file)
@@ -6988,12 +6988,13 @@ 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 can now produce indexed fields, and we check if the indexes
+     match.  */
   if (access_index < CONSTRUCTOR_NELTS (init))
     {
       fn = CONSTRUCTOR_ELT (init, access_index)->value;
-      gcc_checking_assert (!CONSTRUCTOR_ELT (init, access_index)->index);
+      tree idx = CONSTRUCTOR_ELT (init, access_index)->index;
+      gcc_checking_assert (!idx || tree_to_uhwi (idx) == access_index);
       STRIP_NOPS (fn);
     }
   else
index 29481f07fc7cfc81d60522aa27b87d62e3581ae2..af072db151ef6c1b5d8ecdd815e622acfbc4ac73 100644 (file)
@@ -1,3 +1,19 @@
+2018-09-18  Marek Polacek  <polacek@redhat.com>
+
+       P1064R0 - Allowing Virtual Function Calls in Constant Expressions
+       * 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.
+
 2018-09-18  Paul Thomas  <pault@gcc.gnu.org>
 
        PR fortran/87336
index 2465f9d9b4f3b095afb07b8d24c89384d1ffcfbe..5f9ab4d9c288ffa08390e06ace4ebbbfdf793d37 100644 (file)
@@ -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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual1.C
new file mode 100644 (file)
index 0000000..fcf8cac
--- /dev/null
@@ -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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C
new file mode 100644 (file)
index 0000000..9d82c5c
--- /dev/null
@@ -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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual3.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual3.C
new file mode 100644 (file)
index 0000000..d71422f
--- /dev/null
@@ -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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual4.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual4.C
new file mode 100644 (file)
index 0000000..2038beb
--- /dev/null
@@ -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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual5.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual5.C
new file mode 100644 (file)
index 0000000..6d27990
--- /dev/null
@@ -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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual6.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual6.C
new file mode 100644 (file)
index 0000000..ece5e70
--- /dev/null
@@ -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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual7.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual7.C
new file mode 100644 (file)
index 0000000..b0f4996
--- /dev/null
@@ -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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual8.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual8.C
new file mode 100644 (file)
index 0000000..4a7cc97
--- /dev/null
@@ -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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual9.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual9.C
new file mode 100644 (file)
index 0000000..3a12adc
--- /dev/null
@@ -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);
index 2c83236cae9f735ba74d76527dcea8d65622af2f..9223c6927376ce6a74f5a7cf31c943d23348f69f 100644 (file)
@@ -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();
    ~~~~~~~~~ ^~~~~~~