c++: 'new T[N]' and SFINAE [PR82110]
Here we're failing to treat 'new T[N]' as erroneous in a SFINAE context when T isn't default constructible because expand_aggr_init_1 doesn't communicate to build_aggr_init (its only SFINAE caller) whether the initialization was actually successful. To fix this, this patch makes expand_aggr_init_1 and its subroutine expand_default_init return true on success, false on failure so that build_aggr_init can properly return error_mark_node on failure. PR c++/82110 gcc/cp/ChangeLog: * init.c (build_aggr_init): Return error_mark_node if expand_aggr_init_1 returns false. (expand_default_init): Change return type to bool. Return false on error, true on success. (expand_aggr_init_1): Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/pr78765.C: Expect another conversion failure diagnostic. * g++.dg/template/sfinae14.C: Flip incorrect assertion. * g++.dg/cpp2a/concepts-requires27.C: New test.
This commit is contained in:
parent
ef2ace642a
commit
b9119edc09
|
@ -39,8 +39,8 @@ along with GCC; see the file COPYING3. If not see
|
|||
static bool begin_init_stmts (tree *, tree *);
|
||||
static tree finish_init_stmts (bool, tree, tree);
|
||||
static void construct_virtual_base (tree, tree);
|
||||
static void expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t);
|
||||
static void expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t);
|
||||
static bool expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t);
|
||||
static bool expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t);
|
||||
static void perform_member_init (tree, tree);
|
||||
static int member_init_ok_or_else (tree, tree, tree);
|
||||
static void expand_virtual_init (tree, tree);
|
||||
|
@ -1838,12 +1838,14 @@ build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain)
|
|||
is_global = begin_init_stmts (&stmt_expr, &compound_stmt);
|
||||
destroy_temps = stmts_are_full_exprs_p ();
|
||||
current_stmt_tree ()->stmts_are_full_exprs_p = 0;
|
||||
expand_aggr_init_1 (TYPE_BINFO (type), exp, exp,
|
||||
init, LOOKUP_NORMAL|flags, complain);
|
||||
bool ok = expand_aggr_init_1 (TYPE_BINFO (type), exp, exp,
|
||||
init, LOOKUP_NORMAL|flags, complain);
|
||||
stmt_expr = finish_init_stmts (is_global, stmt_expr, compound_stmt);
|
||||
current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
|
||||
TREE_READONLY (exp) = was_const;
|
||||
TREE_THIS_VOLATILE (exp) = was_volatile;
|
||||
if (!ok)
|
||||
return error_mark_node;
|
||||
|
||||
if ((VAR_P (exp) || TREE_CODE (exp) == PARM_DECL)
|
||||
&& TREE_SIDE_EFFECTS (stmt_expr)
|
||||
|
@ -1854,7 +1856,7 @@ build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain)
|
|||
return stmt_expr;
|
||||
}
|
||||
|
||||
static void
|
||||
static bool
|
||||
expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
||||
tsubst_flags_t complain)
|
||||
{
|
||||
|
@ -1889,6 +1891,9 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
|||
happen for direct-initialization, too. */
|
||||
init = digest_init (type, init, complain);
|
||||
|
||||
if (init == error_mark_node)
|
||||
return false;
|
||||
|
||||
/* A CONSTRUCTOR of the target's type is a previously digested
|
||||
initializer, whether that happened just above or in
|
||||
cp_parser_late_parsing_nsdmi.
|
||||
|
@ -1910,7 +1915,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
|||
init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init);
|
||||
TREE_SIDE_EFFECTS (init) = 1;
|
||||
finish_expr_stmt (init);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (init && TREE_CODE (init) != TREE_LIST
|
||||
|
@ -1927,8 +1932,12 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
|||
have already built up the constructor call so we could wrap it
|
||||
in an exception region. */;
|
||||
else
|
||||
init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP,
|
||||
flags, complain | tf_no_cleanup);
|
||||
{
|
||||
init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP,
|
||||
flags, complain | tf_no_cleanup);
|
||||
if (init == error_mark_node)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TREE_CODE (init) == MUST_NOT_THROW_EXPR)
|
||||
/* We need to protect the initialization of a catch parm with a
|
||||
|
@ -1944,7 +1953,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
|||
init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init);
|
||||
TREE_SIDE_EFFECTS (init) = 1;
|
||||
finish_expr_stmt (init);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (init == NULL_TREE)
|
||||
|
@ -1982,6 +1991,8 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
|||
&parms, binfo, flags,
|
||||
complain);
|
||||
base = fold_build_cleanup_point_expr (void_type_node, base);
|
||||
if (complete == error_mark_node || base == error_mark_node)
|
||||
return false;
|
||||
rval = build_if_in_charge (complete, base);
|
||||
}
|
||||
else
|
||||
|
@ -1991,6 +2002,8 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
|||
|
||||
rval = build_special_member_call (exp, ctor_name, &parms, binfo, flags,
|
||||
complain);
|
||||
if (rval == error_mark_node)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parms != NULL)
|
||||
|
@ -2010,10 +2023,12 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
|||
/* FIXME put back convert_to_void? */
|
||||
if (TREE_SIDE_EFFECTS (rval))
|
||||
finish_expr_stmt (rval);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This function is responsible for initializing EXP with INIT
|
||||
(if any).
|
||||
(if any). Returns true on success, false on failure.
|
||||
|
||||
BINFO is the binfo of the type for who we are performing the
|
||||
initialization. For example, if W is a virtual base class of A and B,
|
||||
|
@ -2032,7 +2047,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
|||
FLAGS is just passed to `build_new_method_call'. See that function
|
||||
for its description. */
|
||||
|
||||
static void
|
||||
static bool
|
||||
expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
||||
tsubst_flags_t complain)
|
||||
{
|
||||
|
@ -2058,7 +2073,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
|||
if (init)
|
||||
finish_expr_stmt (init);
|
||||
gcc_assert (!cleanups);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* List-initialization from {} becomes value-initialization for non-aggregate
|
||||
|
@ -2096,7 +2111,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
|||
/* If we don't need to mess with the constructor at all,
|
||||
then we're done. */
|
||||
if (! type_build_ctor_call (type))
|
||||
return;
|
||||
return true;
|
||||
|
||||
/* Otherwise fall through and call the constructor. */
|
||||
init = NULL_TREE;
|
||||
|
@ -2104,7 +2119,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
|||
|
||||
/* We know that expand_default_init can handle everything we want
|
||||
at this point. */
|
||||
expand_default_init (binfo, true_exp, exp, init, flags, complain);
|
||||
return expand_default_init (binfo, true_exp, exp, init, flags, complain);
|
||||
}
|
||||
|
||||
/* Report an error if TYPE is not a user-defined, class type. If
|
||||
|
|
|
@ -8,7 +8,7 @@ struct ValueType {
|
|||
int field;
|
||||
};
|
||||
|
||||
static constexpr ValueType var = 0; // { dg-error "conversion" }
|
||||
static constexpr ValueType var = 0; // { dg-error "conversion|convert" }
|
||||
|
||||
template <int> class ValueTypeInfo;
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// PR c++/82110
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
struct X { X() = delete; };
|
||||
|
||||
template<class T> concept C = requires(T t) { new T; };
|
||||
template<class T> concept D = requires(T t) { new T[1]; };
|
||||
|
||||
static_assert(!C<X>);
|
||||
static_assert(!D<X>);
|
|
@ -76,4 +76,4 @@ STATIC_ASSERT(!(has_new_one_arg<X, int X::*>::value));
|
|||
|
||||
STATIC_ASSERT((has_array_new<Y, int, 5>::value));
|
||||
STATIC_ASSERT(!(has_array_new<X, int Y::*, &Y::foo>::value));
|
||||
STATIC_ASSERT((has_array_new<X, int, 5>::value));
|
||||
STATIC_ASSERT(!(has_array_new<X, int, 5>::value));
|
||||
|
|
Loading…
Reference in New Issue