From f2acb8ad4361b3fa2185ab3177659d1ee9c54a7f Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 19 Nov 2014 17:06:26 -0500 Subject: [PATCH] re PR c++/63885 (ICE in static assert of constexpr forwarding xvalue container member rvalue reference) PR c++/63885 * constexpr.c (cxx_eval_constant_expression) [PARM_DECL]: Don't complain yet about a reference. [TARGET_EXPR]: Handle TARGET_EXPR with addr == true. [ADDR_EXPR]: Make sure we don't take the address of a CONSTRUCTOR. (cxx_bind_parameters_in_call): In the new scheme addr is always false. * typeck.c (build_address): Don't take the address of a CONSTRUCTOR. From-SVN: r217815 --- gcc/cp/ChangeLog | 8 +++ gcc/cp/constexpr.c | 14 ++++- gcc/cp/typeck.c | 1 + gcc/testsuite/g++.dg/cpp0x/constexpr-ref8.C | 61 +++++++++++++++++++++ 4 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-ref8.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6f947b4b811..8f21d8b1146 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,13 @@ 2014-11-19 Jason Merrill + PR c++/63885 + * constexpr.c (cxx_eval_constant_expression) [PARM_DECL]: Don't + complain yet about a reference. + [TARGET_EXPR]: Handle TARGET_EXPR with addr == true. + [ADDR_EXPR]: Make sure we don't take the address of a CONSTRUCTOR. + (cxx_bind_parameters_in_call): In the new scheme addr is always false. + * typeck.c (build_address): Don't take the address of a CONSTRUCTOR. + PR c++/57979 * init.c (decl_really_constant_value): Rename from integral_constant_value. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 52685450edf..41867b8dc28 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1061,6 +1061,7 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, x = ctx->object; x = cp_build_addr_expr (x, tf_warning_or_error); } + bool addr = false; if (parms && DECL_BY_REFERENCE (parms) && !use_new_call) { /* cp_genericize made this a reference for argument passing, but @@ -1071,9 +1072,9 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, gcc_assert (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE); type = TREE_TYPE (type); x = convert_from_reference (x); + addr = true; } - arg = cxx_eval_constant_expression (ctx, x, - TREE_CODE (type) == REFERENCE_TYPE, + arg = cxx_eval_constant_expression (ctx, x, addr, non_constant_p, overflow_p); /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p && ctx->quiet) @@ -2854,6 +2855,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = *p; else if (addr) /* Defer in case this is only used for its type. */; + else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) + /* Defer, there's no lvalue->rvalue conversion. */; else if (is_empty_class (TREE_TYPE (t))) { /* If the class is empty, we aren't actually loading anything. */ @@ -2934,6 +2937,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (!*non_constant_p) /* Adjust the type of the result to the type of the temporary. */ r = adjust_temp_type (TREE_TYPE (t), r); + if (addr) + { + tree slot = TARGET_EXPR_SLOT (t); + ctx->values->put (slot, r); + return slot; + } break; case INIT_EXPR: @@ -2995,6 +3004,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p) return t; + gcc_checking_assert (TREE_CODE (op) != CONSTRUCTOR); /* This function does more aggressive folding than fold itself. */ r = build_fold_addr_expr_with_type (op, TREE_TYPE (t)); if (TREE_CODE (r) == ADDR_EXPR && TREE_OPERAND (r, 0) == oldop) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 53fe67afc90..71568515389 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5305,6 +5305,7 @@ build_address (tree t) { if (error_operand_p (t) || !cxx_mark_addressable (t)) return error_mark_node; + gcc_checking_assert (TREE_CODE (t) != CONSTRUCTOR); t = build_fold_addr_expr (t); if (TREE_CODE (t) != ADDR_EXPR) t = rvalue (t); diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref8.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref8.C new file mode 100644 index 00000000000..04de9c7e04c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref8.C @@ -0,0 +1,61 @@ +// PR c++/63885 +// { dg-do compile { target c++11 } } + +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; + +template struct is_lvalue_reference { static const bool value = false; }; +template struct is_lvalue_reference { static const bool value = true; }; + +template struct conditional; +template struct conditional { typedef U type; }; +template struct conditional { typedef V type; }; + +template constexpr _Tp&& +forward(typename remove_reference<_Tp>::type& __t) noexcept +{ return static_cast<_Tp&&>(__t); } + +/////////////////////////////////////////////////////////////////////////////// + +template struct member_forward +{ + typedef typename remove_reference ::type::type T; + typedef typename conditional + < + is_lvalue_reference ::value, + T&, + T + >::type type; +}; + +template using member_forward_t = typename member_forward ::type; + +/////////////////////////////////////////////////////////////////////////////// + +template struct __get; +template < typename T> struct __get <0, T> +{ + constexpr static auto value (T arg) + -> decltype ((forward > (arg.t))) + { + return forward > (arg.t); + } +}; + +template constexpr auto get (T && arg) + -> decltype (__get ::value (forward (arg))) +{ + return __get ::value (forward (arg)); +} + +/////////////////////////////////////////////////////////////////////////////// + +template struct S +{ + typedef T type; + T t; + + template constexpr S (U && u) : t (forward (u)) {} +}; +static_assert (get <0> (S (1)) == 1, ""); // g++ 4.9 passes, g++ trunk r217559 fails -- 2.30.2