From 023d89c70b3912087d9e4a1db51993ed94fdd088 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 18 Nov 2014 08:34:08 -0500 Subject: [PATCH] re PR c++/58102 (rejects valid initialization of constexpr object with mutable member) PR c++/58102 * typeck2.c (store_init_value): Set it. * cp-tree.h (CONSTRUCTOR_MUTABLE_POISON): New. * constexpr.c (cxx_eval_outermost_constant_expr): Check it. From-SVN: r217713 --- gcc/cp/ChangeLog | 7 +++++++ gcc/cp/constexpr.c | 14 +++++++------- gcc/cp/cp-tree.h | 6 ++++++ gcc/cp/typeck2.c | 4 ++++ gcc/testsuite/g++.dg/cpp0x/constexpr-mutable2.C | 10 ++++++++++ 5 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-mutable2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6e7f657c6ee..1afd3cfa46a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2014-11-18 Jason Merrill + + PR c++/58102 + * typeck2.c (store_init_value): Set it. + * cp-tree.h (CONSTRUCTOR_MUTABLE_POISON): New. + * constexpr.c (cxx_eval_outermost_constant_expr): Check it. + 2014-11-17 Jason Merrill PR c++/33911 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 5b2565413b0..2f0708b40ec 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3315,15 +3315,15 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); - if (TREE_CODE (t) != CONSTRUCTOR - && cp_has_mutable_p (TREE_TYPE (t))) + /* Mutable logic is a bit tricky: we want to allow initialization of + constexpr variables with mutable members, but we can't copy those + members to another constexpr variable. */ + if (TREE_CODE (r) == CONSTRUCTOR + && CONSTRUCTOR_MUTABLE_POISON (r)) { - /* We allow a mutable type if the original expression was a - CONSTRUCTOR so that we can do aggregate initialization of - constexpr variables. */ if (!allow_non_constant) - error ("%qT cannot be the type of a complete constant expression " - "because it has mutable sub-objects", type); + error ("%qE is not a constant expression because it refers to " + "mutable subobjects of %qT", t, type); non_constant_p = true; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d3722d73f61..35423442ece 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -109,6 +109,7 @@ c-common.h, not after. DECLTYPE_FOR_LAMBDA_PROXY (in DECLTYPE_TYPE) REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF) AGGR_INIT_ZERO_FIRST (in AGGR_INIT_EXPR) + CONSTRUCTOR_MUTABLE_POISON (in CONSTRUCTOR) 3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out). ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -3497,6 +3498,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define CONSTRUCTOR_NO_IMPLICIT_ZERO(NODE) \ (TREE_LANG_FLAG_1 (CONSTRUCTOR_CHECK (NODE))) +/* True if this CONSTRUCTOR should not be used as a variable initializer + because it was loaded from a constexpr variable with mutable fields. */ +#define CONSTRUCTOR_MUTABLE_POISON(NODE) \ + (TREE_LANG_FLAG_2 (CONSTRUCTOR_CHECK (NODE))) + #define DIRECT_LIST_INIT_P(NODE) \ (BRACE_ENCLOSED_INITIALIZER_P (NODE) && CONSTRUCTOR_IS_DIRECT_INIT (NODE)) diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 01a0671341e..5748650ccf4 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -809,6 +809,10 @@ store_init_value (tree decl, tree init, vec** cleanups, int flags) value = cxx_constant_value (value, decl); } value = maybe_constant_init (value, decl); + if (TREE_CODE (value) == CONSTRUCTOR && cp_has_mutable_p (type)) + /* Poison this CONSTRUCTOR so it can't be copied to another + constexpr variable. */ + CONSTRUCTOR_MUTABLE_POISON (value) = true; const_init = (reduced_constant_expression_p (value) || error_operand_p (value)); DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init; diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-mutable2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-mutable2.C new file mode 100644 index 00000000000..c449c3aabc0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-mutable2.C @@ -0,0 +1,10 @@ +// PR c++/58102 +// { dg-do compile { target c++11 } } + +struct S { + mutable int n; + constexpr S() : n() {} +}; + +constexpr S s = {}; +constexpr S s2 = s; // { dg-error "mutable" } -- 2.30.2