/* Report error messages, build initializers, and perform
some front-end optimizations for C++ compiler.
- Copyright (C) 1987-2022 Free Software Foundation, Inc.
+ Copyright (C) 1987-2024 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
all was well. */
static int
-abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use,
- tsubst_flags_t complain)
+abstract_virtuals_error (tree decl, tree type, abstract_class_use use,
+ tsubst_flags_t complain)
{
vec<tree, va_gc> *pure;
}
int
-abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain)
-{
- return abstract_virtuals_error_sfinae (decl, type, ACU_UNKNOWN, complain);
-}
-
-int
-abstract_virtuals_error_sfinae (abstract_class_use use, tree type,
- tsubst_flags_t complain)
+abstract_virtuals_error (tree decl, tree type,
+ tsubst_flags_t complain /* = tf_warning_or_error */)
{
- return abstract_virtuals_error_sfinae (NULL_TREE, type, use, complain);
+ return abstract_virtuals_error (decl, type, ACU_UNKNOWN, complain);
}
-
-/* Wrapper for the above function in the common case of wanting errors. */
-
int
-abstract_virtuals_error (tree decl, tree type)
+abstract_virtuals_error (abstract_class_use use, tree type,
+ tsubst_flags_t complain /* = tf_warning_or_error */)
{
- return abstract_virtuals_error_sfinae (decl, type, tf_warning_or_error);
+ return abstract_virtuals_error (NULL_TREE, type, use, complain);
}
-int
-abstract_virtuals_error (abstract_class_use use, tree type)
-{
- return abstract_virtuals_error_sfinae (use, type, tf_warning_or_error);
-}
/* Print an inform about the declaration of the incomplete type TYPE. */
and TYPE is the type that was invalid. DIAG_KIND indicates the
type of diagnostic (see diagnostic.def). */
-void
+bool
cxx_incomplete_type_diagnostic (location_t loc, const_tree value,
const_tree type, diagnostic_t diag_kind)
{
bool is_decl = false, complained = false;
- gcc_assert (diag_kind == DK_WARNING
- || diag_kind == DK_PEDWARN
- || diag_kind == DK_ERROR);
-
/* Avoid duplicate error message. */
if (TREE_CODE (type) == ERROR_MARK)
- return;
+ return false;
if (value)
{
break;
case VOID_TYPE:
- emit_diagnostic (diag_kind, loc, 0,
+ complained = emit_diagnostic (diag_kind, loc, 0,
"invalid use of %qT", type);
break;
type = TREE_TYPE (type);
goto retry;
}
- emit_diagnostic (diag_kind, loc, 0,
+ complained = emit_diagnostic (diag_kind, loc, 0,
"invalid use of array with unspecified bounds");
break;
add a fix-it hint. */
if (type_num_arguments (TREE_TYPE (member)) == 1)
richloc.add_fixit_insert_after ("()");
- emit_diagnostic (diag_kind, &richloc, 0,
+ complained = emit_diagnostic (diag_kind, &richloc, 0,
"invalid use of member function %qD "
"(did you forget the %<()%> ?)", member);
}
else
- emit_diagnostic (diag_kind, loc, 0,
+ complained = emit_diagnostic (diag_kind, loc, 0,
"invalid use of member %qD "
"(did you forget the %<&%> ?)", member);
}
if (is_auto (type))
{
if (CLASS_PLACEHOLDER_TEMPLATE (type))
- emit_diagnostic (diag_kind, loc, 0,
+ complained = emit_diagnostic (diag_kind, loc, 0,
"invalid use of placeholder %qT", type);
else
- emit_diagnostic (diag_kind, loc, 0,
+ complained = emit_diagnostic (diag_kind, loc, 0,
"invalid use of %qT", type);
}
else
- emit_diagnostic (diag_kind, loc, 0,
+ complained = emit_diagnostic (diag_kind, loc, 0,
"invalid use of template type parameter %qT", type);
break;
case BOUND_TEMPLATE_TEMPLATE_PARM:
- emit_diagnostic (diag_kind, loc, 0,
+ complained = emit_diagnostic (diag_kind, loc, 0,
"invalid use of template template parameter %qT",
TYPE_NAME (type));
break;
case TYPE_PACK_EXPANSION:
- emit_diagnostic (diag_kind, loc, 0,
+ complained = emit_diagnostic (diag_kind, loc, 0,
"invalid use of pack expansion %qT", type);
break;
case TYPENAME_TYPE:
case DECLTYPE_TYPE:
- emit_diagnostic (diag_kind, loc, 0,
+ complained = emit_diagnostic (diag_kind, loc, 0,
"invalid use of dependent type %qT", type);
break;
case LANG_TYPE:
if (type == init_list_type_node)
{
- emit_diagnostic (diag_kind, loc, 0,
+ complained = emit_diagnostic (diag_kind, loc, 0,
"invalid use of brace-enclosed initializer list");
break;
}
if (value && TREE_CODE (value) == COMPONENT_REF)
goto bad_member;
else if (value && TREE_CODE (value) == ADDR_EXPR)
- emit_diagnostic (diag_kind, loc, 0,
+ complained = emit_diagnostic (diag_kind, loc, 0,
"address of overloaded function with no contextual "
"type information");
else if (value && TREE_CODE (value) == OVERLOAD)
- emit_diagnostic (diag_kind, loc, 0,
+ complained = emit_diagnostic (diag_kind, loc, 0,
"overloaded function with no contextual type information");
else
- emit_diagnostic (diag_kind, loc, 0,
+ complained = emit_diagnostic (diag_kind, loc, 0,
"insufficient contextual information to determine type");
break;
default:
gcc_unreachable ();
}
+
+ return complained;
}
/* Print an error message for invalid use of an incomplete type.
: TYPE_FIELDS (type));
; prev = DECL_CHAIN (prev))
{
- prev = next_initializable_field (prev);
+ prev = next_aggregate_field (prev);
if (prev == field_index)
break;
tree ptype = TREE_TYPE (prev);
- if (type_build_dtor_call (ptype))
+ if (TYPE_P (ptype) && type_build_dtor_call (ptype))
{
tree pcref = build3 (COMPONENT_REF, ptype, dest, prev,
NULL_TREE);
else
{
build_init:
- code = build2 (INIT_EXPR, inner_type, sub, value);
+ code = cp_build_init_expr (sub, value);
}
code = build_stmt (input_location, EXPR_STMT, code);
add_stmt (code);
}
else if (init)
{
- tree ie = build2 (INIT_EXPR, void_type_node, dest, init);
+ tree ie = cp_build_init_expr (dest, init);
code = add_stmt_to_compound (ie, code);
}
}
code = build_vec_init (dest, NULL_TREE, init, /*value-init*/false,
/*from array*/1, tf_warning_or_error);
else
- code = build2 (INIT_EXPR, TREE_TYPE (dest), dest, init);
+ code = cp_build_init_expr (dest, init);
return code;
}
+/* T is the initializer of a constexpr variable. Set CONSTRUCTOR_MUTABLE_POISON
+ for any CONSTRUCTOR within T that contains (directly or indirectly) a mutable
+ member, thereby poisoning it so it can't be copied to another a constexpr
+ variable or read during constexpr evaluation. */
+
+static void
+poison_mutable_constructors (tree t)
+{
+ if (TREE_CODE (t) != CONSTRUCTOR)
+ return;
+
+ if (cp_has_mutable_p (TREE_TYPE (t)))
+ {
+ CONSTRUCTOR_MUTABLE_POISON (t) = true;
+
+ if (vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (t))
+ for (const constructor_elt &ce : *elts)
+ poison_mutable_constructors (ce.value);
+ }
+}
+
/* Perform appropriate conversions on the initial value of a variable,
store it in the declaration DECL,
and print any error messages that are appropriate.
bool const_init;
tree oldval = value;
if (DECL_DECLARED_CONSTEXPR_P (decl)
+ || DECL_DECLARED_CONSTINIT_P (decl)
|| (DECL_IN_AGGR_P (decl)
&& DECL_INITIALIZED_IN_CLASS_P (decl)))
{
value = fold_non_dependent_expr (value, tf_warning_or_error,
/*manifestly_const_eval=*/true,
decl);
+ if (value == error_mark_node)
+ ;
/* Diagnose a non-constant initializer for constexpr variable or
non-inline in-class-initialized static data member. */
- if (!require_constant_expression (value))
- value = error_mark_node;
- else if (processing_template_decl)
- /* In a template we might not have done the necessary
- transformations to make value actually constant,
- e.g. extend_ref_init_temps. */
- value = maybe_constant_init (value, decl, true);
+ else if (!is_constant_expression (value))
+ {
+ /* Maybe we want to give this message for constexpr variables as
+ well, but that will mean a lot of testsuite adjustment. */
+ if (DECL_DECLARED_CONSTINIT_P (decl))
+ error_at (location_of (decl),
+ "%<constinit%> variable %qD does not have a "
+ "constant initializer", decl);
+ require_constant_expression (value);
+ value = error_mark_node;
+ }
else
- value = cxx_constant_init (value, decl);
+ {
+ value = maybe_constant_init (value, decl, true);
+
+ /* In a template we might not have done the necessary
+ transformations to make value actually constant,
+ e.g. extend_ref_init_temps. */
+ if (!processing_template_decl
+ && !TREE_CONSTANT (value))
+ {
+ if (DECL_DECLARED_CONSTINIT_P (decl))
+ error_at (location_of (decl),
+ "%<constinit%> variable %qD does not have a "
+ "constant initializer", decl);
+ value = cxx_constant_init (value, decl);
+ }
+ }
}
else
value = fold_non_dependent_init (value, tf_warning_or_error,
/*manifestly_const_eval=*/true, 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;
+ poison_mutable_constructors (value);
const_init = (reduced_constant_expression_p (value)
|| error_operand_p (value));
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init;
if (!TYPE_REF_P (type))
TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
if (!const_init)
- {
- /* [dcl.constinit]/2 "If a variable declared with the constinit
- specifier has dynamic initialization, the program is
- ill-formed." */
- if (DECL_DECLARED_CONSTINIT_P (decl))
- {
- error_at (location_of (decl),
- "%<constinit%> variable %qD does not have a constant "
- "initializer", decl);
- if (require_constant_expression (value))
- cxx_constant_init (value, decl);
- value = error_mark_node;
- }
- else
- value = oldval;
- }
+ value = oldval;
}
/* Don't fold initializers of automatic variables in constexpr functions,
that might fold away something that needs to be diagnosed at constexpr
here it should have been digested into an actual value for the type. */
gcc_checking_assert (TREE_CODE (value) != CONSTRUCTOR
|| processing_template_decl
+ || VECTOR_TYPE_P (type)
|| !TREE_HAS_CONSTRUCTOR (value));
/* If the initializer is not a constant, fill in DECL_INITIAL with
return ok;
if (CP_INTEGRAL_TYPE_P (type)
- && TREE_CODE (ftype) == REAL_TYPE)
+ && SCALAR_FLOAT_TYPE_P (ftype))
ok = false;
else if (INTEGRAL_OR_ENUMERATION_TYPE_P (ftype)
&& CP_INTEGRAL_TYPE_P (type))
}
/* [dcl.init.list]#7.2: "from long double to double or float, or from
double to float". */
- else if (TREE_CODE (ftype) == REAL_TYPE
- && TREE_CODE (type) == REAL_TYPE)
- {
- if ((same_type_p (ftype, long_double_type_node)
- && (same_type_p (type, double_type_node)
- || same_type_p (type, float_type_node)))
- || (same_type_p (ftype, double_type_node)
- && same_type_p (type, float_type_node))
- || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype)))
+ else if (SCALAR_FLOAT_TYPE_P (ftype)
+ && SCALAR_FLOAT_TYPE_P (type))
+ {
+ if ((extended_float_type_p (ftype) || extended_float_type_p (type))
+ ? /* "from a floating-point type T to another floating-point type
+ whose floating-point conversion rank is neither greater than
+ nor equal to that of T".
+ So, it is ok if
+ cp_compare_floating_point_conversion_ranks (ftype, type)
+ returns -2 (type has greater conversion rank than ftype)
+ or [-1..1] (type has equal conversion rank as ftype, possibly
+ different subrank. Only do this if at least one of the
+ types is extended floating-point type, otherwise keep doing
+ what we did before (for the sake of non-standard
+ backend types). */
+ cp_compare_floating_point_conversion_ranks (ftype, type) >= 2
+ : ((same_type_p (ftype, long_double_type_node)
+ && (same_type_p (type, double_type_node)
+ || same_type_p (type, float_type_node)))
+ || (same_type_p (ftype, double_type_node)
+ && same_type_p (type, float_type_node))
+ || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype))))
{
if (TREE_CODE (init) == REAL_CST)
{
}
}
else if (INTEGRAL_OR_ENUMERATION_TYPE_P (ftype)
- && TREE_CODE (type) == REAL_TYPE)
+ && SCALAR_FLOAT_TYPE_P (type))
{
ok = false;
if (TREE_CODE (init) == INTEGER_CST)
else if (complain & tf_error)
{
int savederrorcount = errorcount;
- global_dc->pedantic_errors = 1;
- auto s = make_temp_override (global_dc->dc_warn_system_headers, true);
- pedwarn (loc, OPT_Wnarrowing,
- "narrowing conversion of %qE from %qH to %qI",
- init, ftype, type);
+ permerror_opt (loc, OPT_Wnarrowing,
+ "narrowing conversion of %qE from %qH to %qI",
+ init, ftype, type);
if (errorcount == savederrorcount)
ok = true;
- global_dc->pedantic_errors = flag_pedantic_errors;
}
}
if (ordinary_char_type_p (to_char_type)
&& ordinary_char_type_p (from_char_type))
return true;
+
+ /* P2513 (C++20/C++23): "an array of char or unsigned char may
+ be initialized by a UTF-8 string literal, or by such a string
+ literal enclosed in braces." */
+ if (from_char_type == char8_type_node
+ && (to_char_type == char_type_node
+ || to_char_type == unsigned_char_type_node))
+ return true;
+
return false;
}
the first element of d, which is the B base subobject. The base
of type B is copy-initialized from the D temporary, causing
object slicing. */
- tree field = next_initializable_field (TYPE_FIELDS (type));
+ tree field = next_aggregate_field (TYPE_FIELDS (type));
if (field && DECL_FIELD_IS_BASE (field))
{
if (warning_at (loc, 0, "initializing a base class of type %qT "
return digest_init_r (type, init, 0, flags, complain);
}
+/* Return true if SUBOB initializes the same object as FULL_EXPR.
+ For instance:
+
+ A a = A{}; // initializer
+ A a = (A{}); // initializer
+ A a = (1, A{}); // initializer
+ A a = true ? A{} : A{}; // initializer
+ auto x = A{}.x; // temporary materialization
+ auto x = foo(A{}); // temporary materialization
+
+ FULL_EXPR is the whole expression, SUBOB is its TARGET_EXPR subobject. */
+
+static bool
+potential_prvalue_result_of (tree subob, tree full_expr)
+{
+ if (subob == full_expr)
+ return true;
+ else if (TREE_CODE (full_expr) == TARGET_EXPR)
+ {
+ tree init = TARGET_EXPR_INITIAL (full_expr);
+ if (TREE_CODE (init) == COND_EXPR)
+ return (potential_prvalue_result_of (subob, TREE_OPERAND (init, 1))
+ || potential_prvalue_result_of (subob, TREE_OPERAND (init, 2)));
+ else if (TREE_CODE (init) == COMPOUND_EXPR)
+ return potential_prvalue_result_of (subob, TREE_OPERAND (init, 1));
+ /* ??? I don't know if this can be hit. */
+ else if (TREE_CODE (init) == PAREN_EXPR)
+ {
+ gcc_checking_assert (false);
+ return potential_prvalue_result_of (subob, TREE_OPERAND (init, 0));
+ }
+ }
+ return false;
+}
+
+/* Callback to replace PLACEHOLDER_EXPRs in a TARGET_EXPR (which isn't used
+ in the context of guaranteed copy elision). */
+
+static tree
+replace_placeholders_for_class_temp_r (tree *tp, int *, void *data)
+{
+ tree t = *tp;
+ tree full_expr = *static_cast<tree *>(data);
+
+ /* We're looking for a TARGET_EXPR nested in the whole expression. */
+ if (TREE_CODE (t) == TARGET_EXPR
+ && !potential_prvalue_result_of (t, full_expr))
+ {
+ tree init = TARGET_EXPR_INITIAL (t);
+ while (TREE_CODE (init) == COMPOUND_EXPR)
+ init = TREE_OPERAND (init, 1);
+ if (TREE_CODE (init) == CONSTRUCTOR
+ && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init))
+ {
+ tree obj = TARGET_EXPR_SLOT (t);
+ replace_placeholders (init, obj);
+ /* We should have dealt with all PLACEHOLDER_EXPRs. */
+ CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = false;
+ gcc_checking_assert (!find_placeholders (init));
+ }
+ }
+
+ return NULL_TREE;
+}
+
/* Process the initializer INIT for an NSDMI DECL (a FIELD_DECL). */
tree
digest_nsdmi_init (tree decl, tree init, tsubst_flags_t complain)
&& CP_AGGREGATE_TYPE_P (type))
init = reshape_init (type, init, complain);
init = digest_init_flags (type, init, flags, complain);
+ set_target_expr_eliding (init);
+
+ /* We may have temporary materialization in a NSDMI, if the initializer
+ has something like A{} in it. Digesting the {} could have introduced
+ a PLACEHOLDER_EXPR referring to A. Now that we've got a TARGET_EXPR,
+ we have an object we can refer to. The reason we bother doing this
+ here is for code like
+
+ struct A {
+ int x;
+ int y = x;
+ };
+
+ struct B {
+ int x = 0;
+ int y = A{x}.y; // #1
+ };
+
+ where in #1 we don't want to end up with two PLACEHOLDER_EXPRs for
+ different types on the same level in a {} when lookup_placeholder
+ wouldn't find a named object for the PLACEHOLDER_EXPR for A. Note,
+ temporary materialization does not occur when initializing an object
+ from a prvalue of the same type, therefore we must not replace the
+ placeholder with a temporary object so that it can be elided. */
+ cp_walk_tree (&init, replace_placeholders_for_class_temp_r, &init,
+ nullptr);
+
return init;
}
\f
new_flags |= LOOKUP_AGGREGATE_PAREN_INIT;
init = digest_init_r (type, init, nested ? 2 : 1, new_flags, complain);
/* When we defer constant folding within a statement, we may want to
- defer this folding as well. */
- tree t = fold_non_dependent_init (init, complain);
- if (TREE_CONSTANT (t))
- init = t;
+ defer this folding as well. Don't call this on CONSTRUCTORs because
+ their elements have already been folded, and we must avoid folding
+ the result of get_nsdmi. */
+ if (TREE_CODE (init) != CONSTRUCTOR)
+ {
+ tree t = fold_non_dependent_init (init, complain);
+ if (TREE_CONSTANT (t))
+ init = t;
+ set_target_expr_eliding (init);
+ }
return init;
}
strip_array_types (TREE_TYPE (ce->value)))));
picflags |= picflag_from_initializer (ce->value);
+ /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer
+ CONSTRUCTOR. */
+ if (TREE_CODE (ce->value) == CONSTRUCTOR
+ && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value))
+ {
+ CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
+ CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value) = 0;
+ }
}
/* No more initializers. If the array is unbounded, we are done. Otherwise,
if (next)
{
if (next != error_mark_node
- && ! seen_error () // Improves error-recovery on anew5.C.
&& (initializer_constant_valid_p (next, TREE_TYPE (next))
!= null_pointer_node))
{
}
picflags |= picflag_from_initializer (next);
+ /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer
+ CONSTRUCTOR. */
+ if (TREE_CODE (next) == CONSTRUCTOR
+ && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next))
+ {
+ CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
+ CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next) = 0;
+ }
if (len > i+1)
{
tree range = build2 (RANGE_EXPR, size_type_node,
{
gcc_assert (ce->value);
next = massage_init_elt (fldtype, next, nested, flags, complain);
+ /* We can't actually elide the temporary when initializing a
+ potentially-overlapping field from a function that returns by
+ value. */
+ if (ce->index
+ && TREE_CODE (next) == TARGET_EXPR
+ && unsafe_copy_elision_p (ce->index, next))
+ TARGET_EXPR_ELIDING_P (next) = false;
++idx;
}
}
a class, just build one up; if it's an array, recurse. */
next = build_constructor (init_list_type_node, NULL);
next = massage_init_elt (fldtype, next, nested, flags, complain);
+ if (TREE_CODE (next) == TARGET_EXPR
+ && unsafe_copy_elision_p (field, next))
+ TARGET_EXPR_ELIDING_P (next) = false;
/* Warn when some struct elements are implicitly initialized. */
if ((complain & tf_warning)
to zero. */
if ((complain & tf_warning)
&& !cp_unevaluated_operand
- && !EMPTY_CONSTRUCTOR_P (init))
+ && !EMPTY_CONSTRUCTOR_P (init)
+ && !is_really_empty_class (fldtype, /*ignore_vptr*/false))
warning (OPT_Wmissing_field_initializers,
"missing initializer for member %qD", field);
if (fldtype != TREE_TYPE (field))
next = cp_convert_and_check (TREE_TYPE (field), next, complain);
picflags |= picflag_from_initializer (next);
+ /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer CONSTRUCTOR. */
+ if (TREE_CODE (next) == CONSTRUCTOR
+ && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next))
+ {
+ CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
+ CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next) = 0;
+ }
CONSTRUCTOR_APPEND_ELT (v, field, next);
}
ce->value = massage_init_elt (TREE_TYPE (ce->index), ce->value, nested,
flags, complain);
+ /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer CONSTRUCTOR. */
+ if (ce->value
+ && TREE_CODE (ce->value) == CONSTRUCTOR
+ && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value))
+ {
+ CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
+ CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value) = 0;
+ }
return picflag_from_initializer (ce->value);
}
TREE_TYPE (expr) = ttype;
return expr;
}
- expr = build_non_dependent_expr (expr);
}
if (MAYBE_CLASS_TYPE_P (type))
/* Build an expression for "object + offset" where offset is the
value stored in the pointer-to-data-member. */
ptype = build_pointer_type (type);
- datum = fold_build_pointer_plus (fold_convert (ptype, datum), component);
+ datum = cp_convert (ptype, datum, complain);
+ if (!processing_template_decl)
+ datum = build2 (POINTER_PLUS_EXPR, ptype,
+ datum, convert_to_ptrofftype (component));
+ datum = cp_fully_fold (datum);
datum = cp_build_fold_indirect_ref (datum);
if (datum == error_mark_node)
return error_mark_node;
if (!complete_type_or_maybe_complain (type, NULL_TREE, complain))
return error_mark_node;
- if (abstract_virtuals_error_sfinae (ACU_CAST, type, complain))
+ if (abstract_virtuals_error (ACU_CAST, type, complain))
return error_mark_node;
/* [expr.type.conv]
if (parms == NULL_TREE)
{
exp = build_value_init (type, complain);
- exp = get_target_expr_sfinae (exp, complain);
+ exp = get_target_expr (exp, complain);
return exp;
}
}
}
}
+
+/* Record that any TARGET_EXPR in T are going to be elided in
+ cp_gimplify_init_expr (or sooner). */
+
+void
+set_target_expr_eliding (tree t)
+{
+ if (!t)
+ return;
+ switch (TREE_CODE (t))
+ {
+ case TARGET_EXPR:
+ TARGET_EXPR_ELIDING_P (t) = true;
+ break;
+ case COMPOUND_EXPR:
+ set_target_expr_eliding (TREE_OPERAND (t, 1));
+ break;
+ case COND_EXPR:
+ set_target_expr_eliding (TREE_OPERAND (t, 1));
+ set_target_expr_eliding (TREE_OPERAND (t, 2));
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Call the above in the process of building an INIT_EXPR. */
+
+tree
+cp_build_init_expr (location_t loc, tree target, tree init)
+{
+ set_target_expr_eliding (init);
+ tree ie = build2_loc (loc, INIT_EXPR, TREE_TYPE (target),
+ target, init);
+ TREE_SIDE_EFFECTS (ie) = true;
+ return ie;
+}