diff options
author | Marek Polacek <polacek@redhat.com> | 2018-09-18 19:16:28 +0000 |
---|---|---|
committer | Marek Polacek <mpolacek@gcc.gnu.org> | 2018-09-18 19:16:28 +0000 |
commit | bf8d83098ffafe1273b11eb5f4a596f96c90c42e (patch) | |
tree | 69c54203512e9f57ce7c3840298da4c7fe1adf99 | |
parent | e8db6cd5fb1ad254329e426dcc8e958c02e2284f (diff) | |
download | gcc-bf8d83098ffafe1273b11eb5f4a596f96c90c42e.zip gcc-bf8d83098ffafe1273b11eb5f4a596f96c90c42e.tar.gz gcc-bf8d83098ffafe1273b11eb5f4a596f96c90c42e.tar.bz2 |
P1064R0 - Allowing Virtual Function Calls in Constant Expressions
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
-rw-r--r-- | gcc/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/cp/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/cp/call.c | 5 | ||||
-rw-r--r-- | gcc/cp/class.c | 7 | ||||
-rw-r--r-- | gcc/cp/constexpr.c | 42 | ||||
-rw-r--r-- | gcc/cp/decl.c | 17 | ||||
-rw-r--r-- | gcc/gimple-fold.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/constexpr-virtual5.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/constexpr-virtual1.C | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C | 49 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/constexpr-virtual3.C | 52 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/constexpr-virtual4.C | 57 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/constexpr-virtual5.C | 60 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/constexpr-virtual6.C | 25 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/constexpr-virtual7.C | 87 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/constexpr-virtual8.C | 50 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/constexpr-virtual9.C | 83 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/diagnostic/virtual-constexpr.C | 7 |
19 files changed, 573 insertions, 21 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 92b878f..69e2e14 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fdc1247..7ea4b6d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 69503ca..ddf0ed0 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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])), diff --git a/gcc/cp/class.c b/gcc/cp/class.c index e950a74..9ca4644 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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); } } diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 88c7378..aa33319 100644 --- a/gcc/cp/constexpr.c +++ b/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 a/gcc/cp/decl.c b/gcc/cp/decl.c index 50b60e8..827c172 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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); diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 362ab59..1e84722 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 29481f0..af072db 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-virtual5.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-virtual5.C index 2465f9d..5f9ab4d 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-virtual5.C +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual1.C new file mode 100644 index 0000000..fcf8cac --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C new file mode 100644 index 0000000..9d82c5c --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual3.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual3.C new file mode 100644 index 0000000..d71422f --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual4.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual4.C new file mode 100644 index 0000000..2038beb --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual5.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual5.C new file mode 100644 index 0000000..6d27990 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual6.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual6.C new file mode 100644 index 0000000..ece5e70 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual7.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual7.C new file mode 100644 index 0000000..b0f4996 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual8.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual8.C new file mode 100644 index 0000000..4a7cc97 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual9.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual9.C new file mode 100644 index 0000000..3a12adc --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/diagnostic/virtual-constexpr.C b/gcc/testsuite/g++.dg/diagnostic/virtual-constexpr.C index 2c83236..9223c69 100644 --- a/gcc/testsuite/g++.dg/diagnostic/virtual-constexpr.C +++ b/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(); ~~~~~~~~~ ^~~~~~~ |