From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 67933 invoked by alias); 14 Sep 2018 19:31:12 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 64371 invoked by uid 89); 14 Sep 2018 19:31:04 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_LAZY_DOMAIN_SECURITY,SPF_HELO_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 14 Sep 2018 19:30:56 +0000 Received: from smtp.corp.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7A270285A6 for ; Fri, 14 Sep 2018 19:30:54 +0000 (UTC) Received: from redhat.com (ovpn-121-46.rdu2.redhat.com [10.10.121.46]) by smtp.corp.redhat.com (Postfix) with ESMTPS id B4890995A2; Fri, 14 Sep 2018 19:30:53 +0000 (UTC) Date: Fri, 14 Sep 2018 19:43:00 -0000 From: Marek Polacek To: Jakub Jelinek Cc: GCC Patches , Jason Merrill Subject: Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v2) Message-ID: <20180914193051.GF5587@redhat.com> References: <20180914171950.GE5587@redhat.com> <20180914173647.GR8250@tucnak> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20180914173647.GR8250@tucnak> User-Agent: Mutt/1.10.1 (2018-07-13) X-SW-Source: 2018-09/txt/msg00782.txt.bz2 On Fri, Sep 14, 2018 at 07:36:47PM +0200, Jakub Jelinek wrote: > On Fri, Sep 14, 2018 at 01:19:50PM -0400, Marek Polacek wrote: > > + /* We expect something in the form of &x.D.2103.D.2094; get x. */ > > + if (TREE_CODE (obj) != ADDR_EXPR) > > + return t; > > Shouldn't it then be a gcc_assert instead, or code like: > if (TREE_CODE (obj) != ADDR_EXPR) > { > if (!ctx->quiet) > error (...); > *non_constant_p = true; > } > to make it clear that we haven't handled it and don't consider it a constant > expression? Not an assert, but setting *non_constant_p is probably sensible. Thus: v2: Set *non_constant_p if OBJ_TYPE_REF is not in expected format. Bootstrapped/regtested on x86_64-linux. 2018-09-14 Marek Polacek P1064R0 - Allowing Virtual Function Calls in Constant Expressions * call.c (build_over_call): Add FIXME. * constexpr.c (cxx_eval_array_reference): Handle referencing the vtable. (cxx_eval_constant_expression): Don't ignore _vptr's initializer. (potential_constant_expression_1): Handle OBJ_TYPE_REF. * decl.c (grokdeclarator): Change error to pedwarn. Only warn when pedantic and not C++2a. * 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/constexpr.c gcc/cp/constexpr.c index 88c73787961..eb6b8fa1842 100644 --- gcc/cp/constexpr.c +++ gcc/cp/constexpr.c @@ -2414,16 +2414,27 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p) { tree oldary = TREE_OPERAND (t, 0); + tree oldidx = TREE_OPERAND (t, 1); + + /* The virtual table isn't constexpr, but has static storage duration and its + initializer is a compile-time constant, so we handle referencing an element + in the table specially. */ + if (TREE_TYPE (t) == vtable_entry_type) + { + VERIFY_CONSTANT (oldidx); + tree ctor = DECL_INITIAL (oldary); + return CONSTRUCTOR_ELT (ctor, tree_to_uhwi (oldidx))->value; + } + tree ary = cxx_eval_constant_expression (ctx, oldary, lval, non_constant_p, overflow_p); - tree index, oldidx; + tree index; HOST_WIDE_INT i = 0; tree elem_type = NULL_TREE; unsigned len = 0, elem_nchars = 1; if (*non_constant_p) return t; - oldidx = TREE_OPERAND (t, 1); index = cxx_eval_constant_expression (ctx, oldidx, false, non_constant_p, overflow_p); @@ -4209,7 +4220,14 @@ 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)) + && !(DECL_INITIAL (t) + && TREE_CODE (DECL_INITIAL (t)) == CONSTRUCTOR + /* But if DECL_INITIAL was { }, do mark it as constant. */ + && CONSTRUCTOR_NELTS (DECL_INITIAL (t)) > 0) && is_really_empty_class (TREE_TYPE (t))) { /* If the class is empty, we aren't actually loading anything. */ @@ -4778,7 +4796,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 +4805,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 +5916,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 +5924,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 % " - "and %", dname); + pedwarn (&richloc, OPT_Wpedantic, "member %qD can be declared both " + "% and % only in -std=c++2a or " + "-std=gnu++2a", dname); } } friendp = decl_spec_seq_has_spec_p (declspecs, ds_friend); 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 +struct X1 +{ + virtual T 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-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(); ~~~~~~~~~ ^~~~~~~