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
This commit is contained in:
parent
e8db6cd5fb
commit
bf8d83098f
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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])),
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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; */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 } }
|
||||
};
|
||||
|
8
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual1.C
Normal file
8
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual1.C
Normal file
@ -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 } }
|
||||
};
|
49
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C
Normal file
49
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C
Normal file
@ -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);
|
52
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual3.C
Normal file
52
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual3.C
Normal file
@ -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);
|
57
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual4.C
Normal file
57
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual4.C
Normal file
@ -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);
|
60
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual5.C
Normal file
60
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual5.C
Normal file
@ -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);
|
25
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual6.C
Normal file
25
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual6.C
Normal file
@ -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);
|
87
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual7.C
Normal file
87
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual7.C
Normal file
@ -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);
|
50
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual8.C
Normal file
50
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual8.C
Normal file
@ -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);
|
83
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual9.C
Normal file
83
gcc/testsuite/g++.dg/cpp2a/constexpr-virtual9.C
Normal file
@ -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);
|
@ -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();
|
||||
~~~~~~~~~ ^~~~~~~
|
||||
|
Loading…
Reference in New Issue
Block a user