/* Functions related to invoking -*- C++ -*- methods and overloaded functions.
- Copyright (C) 1987-2018 Free Software Foundation, Inc.
+ Copyright (C) 1987-2019 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com) and
modified by Brendan Kehoe (brendan@cygnus.com).
#include "internal-fn.h"
#include "stringpool.h"
#include "attribs.h"
+#include "gcc-rich-location.h"
/* The various kinds of conversion. */
BOOL_BITFIELD bad_p : 1;
/* If KIND is ck_ref_bind ck_base_conv, true to indicate that a
temporary should be created to hold the result of the
- conversion. If KIND is ck_ambig, true if the context is
+ conversion. If KIND is ck_ambig or ck_user, true means force
copy-initialization. */
BOOL_BITFIELD need_temporary_p : 1;
/* If KIND is ck_ptr or ck_pmem, true to indicate that a conversion
BOOL_BITFIELD base_p : 1;
/* If KIND is ck_ref_bind, true when either an lvalue reference is
being bound to an lvalue expression or an rvalue reference is
- being bound to an rvalue expression. If KIND is ck_rvalue,
+ being bound to an rvalue expression. If KIND is ck_rvalue or ck_base,
true when we are treating an lvalue as an rvalue (12.8p33). If
- KIND is ck_base, always false. If ck_identity, we will be
- binding a reference directly or decaying to a pointer. */
+ ck_identity, we will be binding a reference directly or decaying to
+ a pointer. */
BOOL_BITFIELD rvaluedness_matches_p: 1;
BOOL_BITFIELD check_narrowing: 1;
+ /* Whether check_narrowing should only check TREE_CONSTANTs; used
+ in build_converted_constant_expr. */
+ BOOL_BITFIELD check_narrowing_const_only: 1;
/* The type of the expression resulting from the conversion. */
tree type;
union {
/*c_cast_p=*/false, (COMPLAIN))
static tree convert_like_real (conversion *, tree, tree, int, bool,
bool, tsubst_flags_t);
-static void op_error (location_t, enum tree_code, enum tree_code, tree,
- tree, tree, bool);
+static void op_error (const op_location_t &, enum tree_code, enum tree_code,
+ tree, tree, tree, bool);
static struct z_candidate *build_user_type_conversion_1 (tree, tree, int,
tsubst_flags_t);
static void print_z_candidate (location_t, const char *, struct z_candidate *);
tree, tsubst_flags_t);
static struct z_candidate *add_function_candidate
(struct z_candidate **, tree, tree, tree, const vec<tree, va_gc> *, tree,
- tree, int, tsubst_flags_t);
+ tree, int, conversion**, tsubst_flags_t);
static conversion *implicit_conversion (tree, tree, tree, bool, int,
tsubst_flags_t);
static conversion *reference_binding (tree, tree, tree, bool, int,
void
set_flags_from_callee (tree call)
{
- bool nothrow;
- tree decl = get_callee_fndecl (call);
+ /* Handle both CALL_EXPRs and AGGR_INIT_EXPRs. */
+ tree decl = cp_get_callee_fndecl_nofold (call);
/* We check both the decl and the type; a function may be known not to
throw without being declared throw(). */
- nothrow = decl && TREE_NOTHROW (decl);
- if (CALL_EXPR_FN (call))
- nothrow |= TYPE_NOTHROW_P (TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (call))));
- else if (internal_fn_flags (CALL_EXPR_IFN (call)) & ECF_NOTHROW)
+ bool nothrow = decl && TREE_NOTHROW (decl);
+ tree callee = cp_get_callee (call);
+ if (callee)
+ nothrow |= TYPE_NOTHROW_P (TREE_TYPE (TREE_TYPE (callee)));
+ else if (TREE_CODE (call) == CALL_EXPR
+ && internal_fn_flags (CALL_EXPR_IFN (call)) & ECF_NOTHROW)
nothrow = true;
if (!nothrow && at_function_scope_p () && cfun && cp_function_chain)
/* Don't pass empty class objects by value. This is useful
for tags in STL, which are used to control overload resolution.
We don't need to handle other cases of copying empty classes. */
- if (! decl || ! DECL_BUILT_IN (decl))
+ if (!decl || !fndecl_built_in_p (decl))
for (i = 0; i < n; i++)
{
tree arg = CALL_EXPR_ARG (function, i);
tree from;
/* The type of the parameter. */
tree to_type;
+ /* The location of the argument. */
+ location_t loc;
};
struct rejection_reason {
}
else if (CP_INTEGRAL_TYPE_P (type))
{
- t = fold_non_dependent_expr (t);
+ t = fold_non_dependent_expr (t, tf_none);
STRIP_NOPS (t);
if (integer_zerop (t) && !TREE_OVERFLOW (t))
return true;
}
static struct rejection_reason *
-arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to)
+arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to,
+ location_t loc)
{
struct rejection_reason *r = alloc_rejection (rr_arg_conversion);
int adjust = first_arg != NULL_TREE;
r->u.conversion.n_arg = n_arg - adjust;
r->u.conversion.from = from;
r->u.conversion.to_type = to;
+ r->u.conversion.loc = loc;
return r;
}
static struct rejection_reason *
-bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to)
+bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to,
+ location_t loc)
{
struct rejection_reason *r = alloc_rejection (rr_bad_arg_conversion);
int adjust = first_arg != NULL_TREE;
r->u.bad_conversion.n_arg = n_arg - adjust;
r->u.bad_conversion.from = from;
r->u.bad_conversion.to_type = to;
+ r->u.bad_conversion.loc = loc;
return r;
}
r->u.conversion.n_arg = 0;
r->u.conversion.from = from;
r->u.conversion.to_type = to;
+ r->u.conversion.loc = UNKNOWN_LOCATION;
return r;
}
r->u.conversion.n_arg = 0;
r->u.conversion.from = from;
r->u.conversion.to_type = to;
+ r->u.conversion.loc = UNKNOWN_LOCATION;
return r;
}
flags |= LOOKUP_NO_NARROWING;
/* Can't make an array of these types. */
- if (TREE_CODE (elttype) == REFERENCE_TYPE
+ if (TYPE_REF_P (elttype)
|| TREE_CODE (elttype) == FUNCTION_TYPE
|| VOID_TYPE_P (elttype))
return NULL;
return true;
}
+/* Helper for build_aggr_conv. Return true if FIELD is in PSET, or if
+ FIELD has ANON_AGGR_TYPE_P and any initializable field in there recursively
+ is in PSET. */
+
+static bool
+field_in_pset (hash_set<tree> *pset, tree field)
+{
+ if (pset->contains (field))
+ return true;
+ if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+ for (field = TYPE_FIELDS (TREE_TYPE (field));
+ field; field = DECL_CHAIN (field))
+ {
+ field = next_initializable_field (field);
+ if (field == NULL_TREE)
+ break;
+ if (field_in_pset (pset, field))
+ return true;
+ }
+ return false;
+}
+
/* Represent a conversion from CTOR, a braced-init-list, to TYPE, an
aggregate class, if such a conversion is possible. */
conversion *c;
tree field = next_initializable_field (TYPE_FIELDS (type));
tree empty_ctor = NULL_TREE;
+ hash_set<tree> *pset = NULL;
/* We already called reshape_init in implicit_conversion. */
context; they're always simple copy-initialization. */
flags = LOOKUP_IMPLICIT|LOOKUP_NO_NARROWING;
+ /* For designated initializers, verify that each initializer is convertible
+ to corresponding TREE_TYPE (ce->index) and mark those FIELD_DECLs as
+ visited. In the following loop then ignore already visited
+ FIELD_DECLs. */
+ if (CONSTRUCTOR_IS_DESIGNATED_INIT (ctor))
+ {
+ tree idx, val;
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), i, idx, val)
+ {
+ if (idx && TREE_CODE (idx) == FIELD_DECL)
+ {
+ tree ftype = TREE_TYPE (idx);
+ bool ok;
+
+ if (TREE_CODE (ftype) == ARRAY_TYPE
+ && TREE_CODE (val) == CONSTRUCTOR)
+ ok = can_convert_array (ftype, val, flags, complain);
+ else
+ ok = can_convert_arg (ftype, TREE_TYPE (val), val, flags,
+ complain);
+
+ if (!ok)
+ goto fail;
+ /* For unions, there should be just one initializer. */
+ if (TREE_CODE (type) == UNION_TYPE)
+ {
+ field = NULL_TREE;
+ i = 1;
+ break;
+ }
+ if (pset == NULL)
+ pset = new hash_set<tree>;
+ pset->add (idx);
+ }
+ else
+ goto fail;
+ }
+ }
+
for (; field; field = next_initializable_field (DECL_CHAIN (field)))
{
tree ftype = TREE_TYPE (field);
tree val;
bool ok;
+ if (pset && field_in_pset (pset, field))
+ continue;
if (i < CONSTRUCTOR_NELTS (ctor))
- val = CONSTRUCTOR_ELT (ctor, i)->value;
+ {
+ val = CONSTRUCTOR_ELT (ctor, i)->value;
+ ++i;
+ }
else if (DECL_INITIAL (field))
val = get_nsdmi (field, /*ctor*/false, complain);
- else if (TREE_CODE (ftype) == REFERENCE_TYPE)
+ else if (TYPE_REF_P (ftype))
/* Value-initialization of reference is ill-formed. */
- return NULL;
+ goto fail;
else
{
if (empty_ctor == NULL_TREE)
empty_ctor = build_constructor (init_list_type_node, NULL);
val = empty_ctor;
}
- ++i;
if (TREE_CODE (ftype) == ARRAY_TYPE
&& TREE_CODE (val) == CONSTRUCTOR)
complain);
if (!ok)
- return NULL;
+ goto fail;
if (TREE_CODE (type) == UNION_TYPE)
break;
}
if (i < CONSTRUCTOR_NELTS (ctor))
- return NULL;
+ {
+ fail:
+ if (pset)
+ delete pset;
+ return NULL;
+ }
+ if (pset)
+ delete pset;
c = alloc_conversion (ck_aggr);
c->type = type;
c->rank = cr_exact;
tree qualified_to;
to = non_reference (to);
- if (TREE_CODE (from) == REFERENCE_TYPE)
+ if (TYPE_REF_P (from))
{
fromref = true;
from = TREE_TYPE (from);
conv->rank = cr_pbool;
if (NULLPTR_TYPE_P (from) && (flags & LOOKUP_ONLYCONVERTING))
conv->bad_p = true;
+ if (flags & LOOKUP_NO_NARROWING)
+ conv->check_narrowing = true;
return conv;
}
|| (fcode == REAL_TYPE && !(flags & LOOKUP_NO_NON_INTEGRAL)))
|| SCOPED_ENUM_P (from))
return NULL;
+
+ /* If we're parsing an enum with no fixed underlying type, we're
+ dealing with an incomplete type, which renders the conversion
+ ill-formed. */
+ if (!COMPLETE_TYPE_P (from))
+ return NULL;
+
conv = build_conv (ck_std, to, conv);
/* Give this a better rank if it's a promotion. */
type. A temporary object is created to hold the result of
the conversion unless we're binding directly to a reference. */
conv->need_temporary_p = !(flags & LOOKUP_NO_TEMP_BIND);
+ if (flags & LOOKUP_PREFER_RVALUE)
+ /* Tell convert_like_real to set LOOKUP_PREFER_RVALUE. */
+ conv->rvaluedness_matches_p = true;
}
else
return NULL;
{
tree t;
- gcc_assert (TREE_CODE (type) == REFERENCE_TYPE);
- gcc_assert (TREE_CODE (conv->type) != REFERENCE_TYPE);
+ gcc_assert (TYPE_REF_P (type));
+ gcc_assert (!TYPE_REF_P (conv->type));
t = TREE_TYPE (type);
from = TREE_TYPE (expr);
}
+ bool copy_list_init = false;
if (expr && BRACE_ENCLOSED_INITIALIZER_P (expr))
{
maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
goto skip;
}
}
- /* Otherwise, if T is a reference type, a prvalue temporary of the
- type referenced by T is copy-list-initialized or
- direct-list-initialized, depending on the kind of initialization
- for the reference, and the reference is bound to that temporary. */
- conv = implicit_conversion (to, from, expr, c_cast_p,
- flags|LOOKUP_NO_TEMP_BIND, complain);
+ /* Otherwise, if T is a reference type, a prvalue temporary of the type
+ referenced by T is copy-list-initialized, and the reference is bound
+ to that temporary. */
+ copy_list_init = true;
skip:;
}
- if (TREE_CODE (from) == REFERENCE_TYPE)
+ if (TYPE_REF_P (from))
{
from = TREE_TYPE (from);
if (!TYPE_REF_IS_RVALUE (rfrom)
conv = build_identity_conv (tfrom, expr);
conv = direct_reference_binding (rto, conv);
- if (TREE_CODE (rfrom) == REFERENCE_TYPE)
+ if (TYPE_REF_P (rfrom))
/* Handle rvalue reference to function properly. */
conv->rvaluedness_matches_p
= (TYPE_REF_IS_RVALUE (rto) == TYPE_REF_IS_RVALUE (rfrom));
if (conv->user_conv_p)
{
+ if (copy_list_init)
+ /* Remember this was copy-list-initialization. */
+ conv->need_temporary_p = true;
+
/* If initializing the temporary used a conversion function,
recalculate the second conversion sequence. */
for (conversion *t = conv; t; t = next_conversion (t))
from = TREE_TYPE (expr);
}
- if (TREE_CODE (to) == REFERENCE_TYPE)
+ if (TYPE_REF_P (to))
conv = reference_binding (to, from, expr, c_cast_p, flags, complain);
else
conv = standard_conversion (to, from, expr, c_cast_p, flags, complain);
if (expr && BRACE_ENCLOSED_INITIALIZER_P (expr))
{
- if (is_std_init_list (to))
+ if (is_std_init_list (to) && !CONSTRUCTOR_IS_DESIGNATED_INIT (expr))
return build_list_conv (to, expr, flags, complain);
/* As an extension, allow list-initialization of _Complex. */
- if (TREE_CODE (to) == COMPLEX_TYPE)
+ if (TREE_CODE (to) == COMPLEX_TYPE
+ && !CONSTRUCTOR_IS_DESIGNATED_INIT (expr))
{
conv = build_complex_conv (to, expr, flags, complain);
if (conv)
if (nelts == 0)
elt = build_value_init (to, tf_none);
- else if (nelts == 1)
+ else if (nelts == 1 && !CONSTRUCTOR_IS_DESIGNATED_INIT (expr))
elt = CONSTRUCTOR_ELT (expr, 0)->value;
else
elt = error_mark_node;
return NULL;
}
+/* Like implicit_conversion, but return NULL if the conversion is bad.
+
+ This is not static so that check_non_deducible_conversion can call it within
+ add_template_candidate_real as part of overload resolution; it should not be
+ called outside of overload resolution. */
+
+conversion *
+good_conversion (tree to, tree from, tree expr,
+ int flags, tsubst_flags_t complain)
+{
+ conversion *c = implicit_conversion (to, from, expr, /*cast*/false,
+ flags, complain);
+ if (c && c->bad_p)
+ c = NULL;
+ return c;
+}
+
/* Add a new entry to the list of candidates. Used by the add_*_candidate
functions. ARGS will not be changed until a single candidate is
selected. */
return n;
}
+/* [over.match.copy]: When initializing a temporary object (12.2) to be bound
+ to the first parameter of a constructor where the parameter is of type
+ "reference to possibly cv-qualified T" and the constructor is called with a
+ single argument in the context of direct-initialization of an object of type
+ "cv2 T", explicit conversion functions are also considered.
+
+ So set LOOKUP_COPY_PARM to let reference_binding know that
+ it's being called in that context. */
+
+int
+conv_flags (int i, int nargs, tree fn, tree arg, int flags)
+{
+ int lflags = flags;
+ tree t;
+ if (i == 0 && nargs == 1 && DECL_CONSTRUCTOR_P (fn)
+ && (t = FUNCTION_FIRST_USER_PARMTYPE (fn))
+ && (same_type_ignoring_top_level_qualifiers_p
+ (non_reference (TREE_VALUE (t)), DECL_CONTEXT (fn))))
+ {
+ if (!(flags & LOOKUP_ONLYCONVERTING))
+ lflags |= LOOKUP_COPY_PARM;
+ if ((flags & LOOKUP_LIST_INIT_CTOR)
+ && BRACE_ENCLOSED_INITIALIZER_P (arg))
+ lflags |= LOOKUP_NO_CONVERSION;
+ }
+ else
+ lflags |= LOOKUP_ONLYCONVERTING;
+
+ return lflags;
+}
+
/* Create an overload candidate for the function or method FN called
with the argument list FIRST_ARG/ARGS and add it to CANDIDATES.
FLAGS is passed on to implicit_conversion.
tree fn, tree ctype, tree first_arg,
const vec<tree, va_gc> *args, tree access_path,
tree conversion_path, int flags,
+ conversion **convs,
tsubst_flags_t complain)
{
tree parmlist = TYPE_ARG_TYPES (TREE_TYPE (fn));
int i, len;
- conversion **convs;
tree parmnode;
tree orig_first_arg = first_arg;
int skip;
skip = 0;
len = vec_safe_length (args) - skip + (first_arg != NULL_TREE ? 1 : 0);
- convs = alloc_conversions (len);
+ if (!convs)
+ convs = alloc_conversions (len);
/* 13.3.2 - Viable functions [over.match.viable]
First, to be a viable function, a candidate function shall have enough
if (parmnode == void_list_node)
break;
+ if (convs[i])
+ {
+ /* Already set during deduction. */
+ parmnode = TREE_CHAIN (parmnode);
+ continue;
+ }
+
if (i == 0 && first_arg != NULL_TREE)
arg = first_arg;
else
if (parmnode)
{
tree parmtype = TREE_VALUE (parmnode);
- int lflags = flags;
parmnode = TREE_CHAIN (parmnode);
}
}
- /* Core issue 899: When [copy-]initializing a temporary to be bound
- to the first parameter of a copy constructor (12.8) called with
- a single argument in the context of direct-initialization,
- explicit conversion functions are also considered.
-
- So set LOOKUP_COPY_PARM to let reference_binding know that
- it's being called in that context. We generalize the above
- to handle move constructors and template constructors as well;
- the standardese should soon be updated similarly. */
- if (ctype && i == 0 && (len-skip == 1)
- && DECL_CONSTRUCTOR_P (fn)
- && parmtype != error_mark_node
- && (same_type_ignoring_top_level_qualifiers_p
- (non_reference (parmtype), ctype)))
- {
- if (!(flags & LOOKUP_ONLYCONVERTING))
- lflags |= LOOKUP_COPY_PARM;
- /* We allow user-defined conversions within init-lists, but
- don't list-initialize the copy parm, as that would mean
- using two levels of braces for the same type. */
- if ((flags & LOOKUP_LIST_INIT_CTOR)
- && BRACE_ENCLOSED_INITIALIZER_P (arg))
- lflags |= LOOKUP_NO_CONVERSION;
- }
- else
- lflags |= LOOKUP_ONLYCONVERTING;
+ int lflags = conv_flags (i, len-skip, fn, arg, flags);
t = implicit_conversion (parmtype, argtype, arg,
/*c_cast_p=*/false, lflags, complain);
if (! t)
{
viable = 0;
- reason = arg_conversion_rejection (first_arg, i, argtype, to_type);
+ reason = arg_conversion_rejection (first_arg, i, argtype, to_type,
+ EXPR_LOCATION (arg));
break;
}
if (t->bad_p)
{
viable = -1;
- reason = bad_arg_conversion_rejection (first_arg, i, arg, to_type);
+ reason = bad_arg_conversion_rejection (first_arg, i, arg, to_type,
+ EXPR_LOCATION (arg));
+
}
}
if (t->bad_p)
{
viable = -1;
- reason = bad_arg_conversion_rejection (NULL_TREE, i, arg, convert_type);
+ reason = bad_arg_conversion_rejection (NULL_TREE, i, arg, convert_type,
+ EXPR_LOCATION (arg));
}
if (i == 0)
/* We need something for printing the candidate. */
t = build_identity_conv (types[i], NULL_TREE);
reason = arg_conversion_rejection (NULL_TREE, i, argtypes[i],
- types[i]);
+ types[i], EXPR_LOCATION (args[i]));
}
else if (t->bad_p)
{
viable = 0;
reason = bad_arg_conversion_rejection (NULL_TREE, i, args[i],
- types[i]);
+ types[i],
+ EXPR_LOCATION (args[i]));
}
convs[i] = t;
}
{
viable = 0;
reason = arg_conversion_rejection (NULL_TREE, 0, argtypes[2],
- boolean_type_node);
+ boolean_type_node,
+ EXPR_LOCATION (args[2]));
}
}
we need candidates for both of them. */
if (type2 && !same_type_p (type1, type2)
&& TREE_CODE (type1) == TREE_CODE (type2)
- && (TREE_CODE (type1) == REFERENCE_TYPE
+ && (TYPE_REF_P (type1)
|| (TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
|| (TYPE_PTRDATAMEM_P (type1) && TYPE_PTRDATAMEM_P (type2))
|| TYPE_PTRMEMFUNC_P (type1)
type = TREE_TYPE (convs);
if (i == 0 && ref1
- && (TREE_CODE (type) != REFERENCE_TYPE
+ && (!TYPE_REF_P (type)
|| CP_TYPE_CONST_P (TREE_TYPE (type))))
continue;
- if (code == COND_EXPR && TREE_CODE (type) == REFERENCE_TYPE)
+ if (code == COND_EXPR && TYPE_REF_P (type))
vec_safe_push (types[i], type);
type = non_reference (type);
tree fn;
struct rejection_reason *reason = NULL;
int errs;
+ conversion **convs = NULL;
/* We don't do deduction on the in-charge parameter, the VTT
parameter or 'this'. */
gcc_assert (ia == nargs_without_in_chrg);
errs = errorcount+sorrycount;
+ if (!obj)
+ convs = alloc_conversions (nargs);
fn = fn_type_unification (tmpl, explicit_targs, targs,
args_without_in_chrg,
nargs_without_in_chrg,
- return_type, strict, flags, false,
- complain & tf_decltype);
+ return_type, strict, flags, convs,
+ false, complain & tf_decltype);
if (fn == error_mark_node)
{
goto fail;
}
+ /* Now the explicit specifier might have been deduced; check if this
+ declaration is explicit. If it is and we're ignoring non-converting
+ constructors, don't add this function to the set of candidates. */
+ if ((flags & LOOKUP_ONLYCONVERTING) && DECL_NONCONVERTING_P (fn))
+ return NULL;
+
if (DECL_CONSTRUCTOR_P (fn) && nargs == 2)
{
tree arg_types = FUNCTION_FIRST_USER_PARMTYPE (fn);
else
cand = add_function_candidate (candidates, fn, ctype,
first_arg, arglist, access_path,
- conversion_path, flags, complain);
+ conversion_path, flags, convs, complain);
if (DECL_TI_TEMPLATE (fn) != tmpl)
/* This situation can occur if a member template of a template
class is specialized. Then, instantiate_template might return
return fn1 == fn2;
}
-/* Print information about a candidate being rejected due to INFO. */
+/* Print information about a candidate FN being rejected due to INFO. */
static void
-print_conversion_rejection (location_t loc, struct conversion_info *info)
+print_conversion_rejection (location_t loc, struct conversion_info *info,
+ tree fn)
{
tree from = info->from;
if (!TYPE_P (from))
inform (loc, " no known conversion from %qH to %qI",
from, info->to_type);
else
- inform (loc, " no known conversion for argument %d from %qH to %qI",
- info->n_arg + 1, from, info->to_type);
+ {
+ if (TREE_CODE (fn) == FUNCTION_DECL)
+ loc = get_fndecl_argument_location (fn, info->n_arg);
+ inform (loc, " no known conversion for argument %d from %qH to %qI",
+ info->n_arg + 1, from, info->to_type);
+ }
}
/* Print information about a candidate with WANT parameters and we found
r->u.arity.expected);
break;
case rr_arg_conversion:
- print_conversion_rejection (cloc, &r->u.conversion);
+ print_conversion_rejection (cloc, &r->u.conversion, fn);
break;
case rr_bad_arg_conversion:
- print_conversion_rejection (cloc, &r->u.bad_conversion);
+ print_conversion_rejection (cloc, &r->u.bad_conversion, fn);
break;
case rr_explicit_conversion:
inform (cloc, " return type %qT of explicit conversion function "
r->u.template_unification.return_type,
r->u.template_unification.strict,
r->u.template_unification.flags,
- true, false);
+ NULL, true, false);
break;
case rr_invalid_copy:
inform (cloc,
We represent this in the conversion sequence with an
rvalue conversion, which means a constructor call. */
- if (TREE_CODE (totype) != REFERENCE_TYPE
+ if (!TYPE_REF_P (totype)
&& !(convflags & LOOKUP_NO_TEMP_BIND))
cand->second_conv
= build_conv (ck_rvalue, totype, cand->second_conv);
find a direct binding, so don't even consider temporaries. If
we don't find a direct binding, the caller will try again to
look for a temporary binding. */
- if (TREE_CODE (totype) == REFERENCE_TYPE)
+ if (TYPE_REF_P (totype))
convflags |= LOOKUP_NO_TEMP_BIND;
old_candidates = candidates;
{
cand->viable = 0;
cand->reason = arg_conversion_rejection (NULL_TREE, -2,
- rettype, totype);
+ rettype, totype,
+ EXPR_LOCATION (expr));
}
else if (DECL_NONCONVERTING_P (cand->fn)
&& ics->rank > cr_exact)
cand->viable = -1;
cand->reason
= bad_arg_conversion_rejection (NULL_TREE, -2,
- rettype, totype);
+ rettype, totype,
+ EXPR_LOCATION (expr));
}
else if (primary_template_specialization_p (cand->fn)
&& ics->rank > cr_exact)
}
cand = tourney (candidates, complain);
- if (cand == 0)
+ if (cand == NULL)
{
if (complain & tf_error)
{
+ auto_diagnostic_group d;
error ("conversion from %qH to %qI is ambiguous",
fromtype, totype);
print_z_candidates (location_of (expr), candidates);
if (cand->viable == -1)
conv->bad_p = true;
+ /* We're performing the maybe-rvalue overload resolution and
+ a conversion function is in play. Reject converting the return
+ value of the conversion function to a base class. */
+ if ((flags & LOOKUP_PREFER_RVALUE) && !DECL_CONSTRUCTOR_P (cand->fn))
+ for (conversion *t = cand->second_conv; t; t = next_conversion (t))
+ if (t->kind == ck_base)
+ return NULL;
+
/* Remember that this was a list-initialization. */
if (flags & LOOKUP_NO_NARROWING)
conv->check_narrowing = true;
conversion *conv;
void *p;
tree t;
- location_t loc = EXPR_LOC_OR_LOC (expr, input_location);
+ location_t loc = cp_expr_loc_or_loc (expr, input_location);
if (error_operand_p (expr))
return error_mark_node;
}
if (conv)
- expr = convert_like (conv, expr, complain);
+ {
+ conv->check_narrowing = true;
+ conv->check_narrowing_const_only = true;
+ expr = convert_like (conv, expr, complain);
+ }
else
- expr = error_mark_node;
+ {
+ if (complain & tf_error)
+ error_at (loc, "could not convert %qE from %qH to %qI", expr,
+ TREE_TYPE (expr), type);
+ expr = error_mark_node;
+ }
/* Free all the conversions we allocated. */
obstack_free (&conversion_obstack, p);
error ("invalid use of void expression");
return NULL;
}
- else if (invalid_nonstatic_memfn_p (input_location, arg, complain))
+ else if (invalid_nonstatic_memfn_p (EXPR_LOCATION (arg), arg, complain))
return NULL;
}
return args;
if (targs)
name = lookup_template_function (name, targs);
+ auto_diagnostic_group d;
if (!any_strictly_viable (candidates))
error_at (loc, "no matching function for call to %<%D(%A)%>",
name, build_tree_list_vec (args));
if (TYPE_PTRFN_P (totype)
|| TYPE_REFFN_P (totype)
- || (TREE_CODE (totype) == REFERENCE_TYPE
+ || (TYPE_REF_P (totype)
&& TYPE_PTRFN_P (TREE_TYPE (totype))))
for (ovl_iterator iter (TREE_VALUE (convs)); iter; ++iter)
{
{
if (complain & tf_error)
{
+ auto_diagnostic_group d;
error ("no match for call to %<(%T) (%A)%>", TREE_TYPE (obj),
build_tree_list_vec (*args));
print_z_candidates (location_of (TREE_TYPE (obj)), candidates);
{
if (complain & tf_error)
{
+ auto_diagnostic_group d;
error ("call of %<(%T) (%A)%> is ambiguous",
TREE_TYPE (obj), build_tree_list_vec (*args));
print_z_candidates (location_of (TREE_TYPE (obj)), candidates);
}
static void
-op_error (location_t loc, enum tree_code code, enum tree_code code2,
+op_error (const op_location_t &loc,
+ enum tree_code code, enum tree_code code2,
tree arg1, tree arg2, tree arg3, bool match)
{
bool assop = code == MODIFY_EXPR;
default:
if (arg2)
if (flag_diagnostics_show_caret)
- error_at (loc, op_error_string (G_("%<operator%s%>"), 2, match),
- opname, TREE_TYPE (arg1), TREE_TYPE (arg2));
+ {
+ binary_op_rich_location richloc (loc, arg1, arg2, true);
+ error_at (&richloc,
+ op_error_string (G_("%<operator%s%>"), 2, match),
+ opname, TREE_TYPE (arg1), TREE_TYPE (arg2));
+ }
else
error_at (loc, op_error_string (G_("%<operator%s%> in %<%E %s %E%>"),
2, match),
arguments to the conditional expression. */
static tree
-build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
+build_conditional_expr_1 (const op_location_t &loc,
+ tree arg1, tree arg2, tree arg3,
tsubst_flags_t complain)
{
tree arg2_type;
arg3_type = unlowered_expr_type (arg3);
if (VOID_TYPE_P (arg2_type) || VOID_TYPE_P (arg3_type))
{
- /* Do the conversions. We don't these for `void' type arguments
- since it can't have any effect and since decay_conversion
- does not handle that case gracefully. */
- if (!VOID_TYPE_P (arg2_type))
- arg2 = decay_conversion (arg2, complain);
- if (!VOID_TYPE_P (arg3_type))
- arg3 = decay_conversion (arg3, complain);
- arg2_type = TREE_TYPE (arg2);
- arg3_type = TREE_TYPE (arg3);
+ /* 'void' won't help in resolving an overloaded expression on the
+ other side, so require it to resolve by itself. */
+ if (arg2_type == unknown_type_node)
+ {
+ arg2 = resolve_nondeduced_context_or_error (arg2, complain);
+ arg2_type = TREE_TYPE (arg2);
+ }
+ if (arg3_type == unknown_type_node)
+ {
+ arg3 = resolve_nondeduced_context_or_error (arg3, complain);
+ arg3_type = TREE_TYPE (arg3);
+ }
/* [expr.cond]
One of the following shall hold:
--The second or the third operand (but not both) is a
- throw-expression (_except.throw_); the result is of the
- type of the other and is an rvalue.
+ throw-expression (_except.throw_); the result is of the type
+ and value category of the other.
--Both the second and the third operands have type void; the
- result is of type void and is an rvalue.
-
- We must avoid calling force_rvalue for expressions of type
- "void" because it will complain that their value is being
- used. */
+ result is of type void and is a prvalue. */
if (TREE_CODE (arg2) == THROW_EXPR
&& TREE_CODE (arg3) != THROW_EXPR)
{
- if (!VOID_TYPE_P (arg3_type))
- {
- arg3 = force_rvalue (arg3, complain);
- if (arg3 == error_mark_node)
- return error_mark_node;
- }
- arg3_type = TREE_TYPE (arg3);
result_type = arg3_type;
+ is_glvalue = glvalue_p (arg3);
}
else if (TREE_CODE (arg2) != THROW_EXPR
&& TREE_CODE (arg3) == THROW_EXPR)
{
- if (!VOID_TYPE_P (arg2_type))
- {
- arg2 = force_rvalue (arg2, complain);
- if (arg2 == error_mark_node)
- return error_mark_node;
- }
- arg2_type = TREE_TYPE (arg2);
result_type = arg2_type;
+ is_glvalue = glvalue_p (arg2);
}
else if (VOID_TYPE_P (arg2_type) && VOID_TYPE_P (arg3_type))
- result_type = void_type_node;
+ {
+ result_type = void_type_node;
+ is_glvalue = false;
+ }
else
{
if (complain & tf_error)
{
if (VOID_TYPE_P (arg2_type))
- error_at (EXPR_LOC_OR_LOC (arg3, loc),
+ error_at (cp_expr_loc_or_loc (arg3, loc),
"second operand to the conditional operator "
"is of type %<void%>, but the third operand is "
"neither a throw-expression nor of type %<void%>");
else
- error_at (EXPR_LOC_OR_LOC (arg2, loc),
+ error_at (cp_expr_loc_or_loc (arg2, loc),
"third operand to the conditional operator "
"is of type %<void%>, but the second operand is "
"neither a throw-expression nor of type %<void%>");
return error_mark_node;
}
- is_glvalue = false;
goto valid_operands;
}
/* [expr.cond]
&& same_type_p (arg2_type, arg3_type))
{
result_type = arg2_type;
- if (processing_template_decl)
- /* Let lvalue_kind know this was a glvalue. */
- result_type = cp_build_reference_type (result_type, xvalue_p (arg2));
-
arg2 = mark_lvalue_use (arg2);
arg3 = mark_lvalue_use (arg3);
goto valid_operands;
{
if (complain & tf_error)
{
+ auto_diagnostic_group d;
op_error (loc, COND_EXPR, NOP_EXPR, arg1, arg2, arg3, FALSE);
print_z_candidates (loc, candidates);
}
if (TREE_CODE (arg2_type) == ENUMERAL_TYPE
&& TREE_CODE (arg3_type) == ENUMERAL_TYPE)
{
- if (TREE_CODE (orig_arg2) == CONST_DECL
- && TREE_CODE (orig_arg3) == CONST_DECL
- && DECL_CONTEXT (orig_arg2) == DECL_CONTEXT (orig_arg3))
+ tree stripped_orig_arg2 = tree_strip_any_location_wrapper (orig_arg2);
+ tree stripped_orig_arg3 = tree_strip_any_location_wrapper (orig_arg3);
+ if (TREE_CODE (stripped_orig_arg2) == CONST_DECL
+ && TREE_CODE (stripped_orig_arg3) == CONST_DECL
+ && (DECL_CONTEXT (stripped_orig_arg2)
+ == DECL_CONTEXT (stripped_orig_arg3)))
/* Two enumerators from the same enumeration can have different
types when the enumeration is still being defined. */;
else if (complain & tf_warning)
return error_mark_node;
valid_operands:
+ if (processing_template_decl && is_glvalue)
+ {
+ /* Let lvalue_kind know this was a glvalue. */
+ tree arg = (result_type == arg2_type ? arg2 : arg3);
+ result_type = cp_build_reference_type (result_type, xvalue_p (arg));
+ }
+
result = build3_loc (loc, COND_EXPR, result_type, arg1, arg2, arg3);
/* If the ARG2 and ARG3 are the same and don't have side-effects,
/* Wrapper for above. */
tree
-build_conditional_expr (location_t loc, tree arg1, tree arg2, tree arg3,
+build_conditional_expr (const op_location_t &loc,
+ tree arg1, tree arg2, tree arg3,
tsubst_flags_t complain)
{
tree ret;
access_path,
conversion_path,
flags,
+ NULL,
complain);
}
}
}
static tree
-build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
- tree arg2, tree arg3, tree *overload, tsubst_flags_t complain)
+build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
+ tree arg1, tree arg2, tree arg3, tree *overload,
+ tsubst_flags_t complain)
{
struct z_candidate *candidates = 0, *cand;
vec<tree, va_gc> *arglist;
{
parmtype = TREE_VALUE (parmlist);
- if (TREE_CODE (parmtype) == REFERENCE_TYPE)
+ if (TYPE_REF_P (parmtype))
parmtype = TREE_TYPE (parmtype);
if (TREE_CODE (TREE_TYPE (args[i])) == ENUMERAL_TYPE
&& (same_type_ignoring_top_level_qualifiers_p
{
/* ... Otherwise, report the more generic
"no matching operator found" error */
+ auto_diagnostic_group d;
op_error (loc, code, code2, arg1, arg2, arg3, FALSE);
print_z_candidates (loc, candidates);
}
{
if (complain & tf_error)
{
+ auto_diagnostic_group d;
op_error (loc, code, code2, arg1, arg2, arg3, TRUE);
print_z_candidates (loc, candidates);
}
/* Wrapper for above. */
tree
-build_new_op (location_t loc, enum tree_code code, int flags,
+build_new_op (const op_location_t &loc, enum tree_code code, int flags,
tree arg1, tree arg2, tree arg3,
tree *overload, tsubst_flags_t complain)
{
return (a && same_type_p (TREE_VALUE (a), align_type_node));
}
+/* True if T is std::destroying_delete_t. */
+
+static bool
+std_destroying_delete_t_p (tree t)
+{
+ return (TYPE_CONTEXT (t) == std_node
+ && id_equal (TYPE_IDENTIFIER (t), "destroying_delete_t"));
+}
+
+/* A deallocation function with at least two parameters whose second parameter
+ type is of type std::destroying_delete_t is a destroying operator delete. A
+ destroying operator delete shall be a class member function named operator
+ delete. [ Note: Array deletion cannot use a destroying operator
+ delete. --end note ] */
+
+tree
+destroying_delete_p (tree t)
+{
+ tree a = TYPE_ARG_TYPES (TREE_TYPE (t));
+ if (!a || !TREE_CHAIN (a))
+ return NULL_TREE;
+ tree type = TREE_VALUE (TREE_CHAIN (a));
+ return std_destroying_delete_t_p (type) ? type : NULL_TREE;
+}
+
/* Returns true iff T, an element of an OVERLOAD chain, is a usual deallocation
function (3.7.4.2 [basic.stc.dynamic.deallocation]) with a parameter of
std::align_val_t. */
return false;
tree a = FUNCTION_ARG_CHAIN (t);
+ if (destroying_delete_p (t))
+ a = TREE_CHAIN (a);
if (same_type_p (TREE_VALUE (a), align_type_node)
&& TREE_CHAIN (a) == void_list_node)
return true;
tree chain = FUNCTION_ARG_CHAIN (t);
if (!chain)
return false;
+ if (destroying_delete_p (t))
+ chain = TREE_CHAIN (chain);
if (chain == void_list_node
|| ((!global || flag_sized_deallocation)
&& second_parm_is_size_t (t)))
fns = lookup_name_nonclass (fnname);
/* Strip const and volatile from addr. */
+ tree oaddr = addr;
addr = cp_convert (ptr_type_node, addr, complain);
if (placement)
-Wc++14-compat. */
else if (!flag_sized_deallocation)
{
- if ((complain & tf_warning)
- && warning (OPT_Wc__14_compat, msg1))
- inform (DECL_SOURCE_LOCATION (fn), msg2, fn);
+ if (complain & tf_warning)
+ {
+ auto_diagnostic_group d;
+ if (warning (OPT_Wc__14_compat, msg1))
+ inform (DECL_SOURCE_LOCATION (fn), msg2, fn);
+ }
goto ok;
}
if (complain & tf_warning_or_error)
{
+ auto_diagnostic_group d;
if (permerror (input_location, msg1))
{
/* Only mention C++14 for namespace-scope delete. */
continue;
}
+ /* -- If any of the deallocation functions is a destroying
+ operator delete, all deallocation functions that are not
+ destroying operator deletes are eliminated from further
+ consideration. */
+ bool fn_destroying = destroying_delete_p (fn);
+ bool elt_destroying = destroying_delete_p (elt);
+ if (elt_destroying != fn_destroying)
+ {
+ if (elt_destroying)
+ fn = elt;
+ continue;
+ }
+
/* -- If the type has new-extended alignment, a function with a
parameter of type std::align_val_t is preferred; otherwise a
function without such a parameter is preferred. If exactly one
}
else
{
+ tree destroying = destroying_delete_p (fn);
+ if (destroying)
+ {
+ /* Strip const and volatile from addr but retain the type of the
+ object. */
+ tree rtype = TREE_TYPE (TREE_TYPE (oaddr));
+ rtype = cv_unqualified (rtype);
+ rtype = TYPE_POINTER_TO (rtype);
+ addr = cp_convert (rtype, oaddr, complain);
+ destroying = build_functional_cast (destroying, NULL_TREE,
+ complain);
+ }
+
tree ret;
vec<tree, va_gc> *args = make_tree_vector ();
args->quick_push (addr);
+ if (destroying)
+ args->quick_push (destroying);
if (second_parm_is_size_t (fn))
args->quick_push (size);
if (aligned_deallocation_fn_p (fn))
return error_mark_node;
}
+/* Issue diagnostics about a disallowed access of DECL, using DIAG_DECL
+ in the diagnostics.
+
+ If ISSUE_ERROR is true, then issue an error about the
+ access, followed by a note showing the declaration.
+ Otherwise, just show the note. */
+
+void
+complain_about_access (tree decl, tree diag_decl, bool issue_error)
+{
+ if (TREE_PRIVATE (decl))
+ {
+ if (issue_error)
+ error ("%q#D is private within this context", diag_decl);
+ inform (DECL_SOURCE_LOCATION (diag_decl),
+ "declared private here");
+ }
+ else if (TREE_PROTECTED (decl))
+ {
+ if (issue_error)
+ error ("%q#D is protected within this context", diag_decl);
+ inform (DECL_SOURCE_LOCATION (diag_decl),
+ "declared protected here");
+ }
+ else
+ {
+ if (issue_error)
+ error ("%q#D is inaccessible within this context", diag_decl);
+ inform (DECL_SOURCE_LOCATION (diag_decl), "declared here");
+ }
+}
+
/* If the current scope isn't allowed to access DECL along
BASETYPE_PATH, give an error. The most derived class in
BASETYPE_PATH is the one used to qualify DECL. DIAG_DECL is
if (!accessible_p (basetype_path, decl, true))
{
+ if (flag_new_inheriting_ctors)
+ diag_decl = strip_inheriting_ctors (diag_decl);
if (complain & tf_error)
- {
- if (flag_new_inheriting_ctors)
- diag_decl = strip_inheriting_ctors (diag_decl);
- if (TREE_PRIVATE (decl))
- {
- error ("%q#D is private within this context", diag_decl);
- inform (DECL_SOURCE_LOCATION (diag_decl),
- "declared private here");
- if (afi)
- afi->record_access_failure (basetype_path, diag_decl);
- }
- else if (TREE_PROTECTED (decl))
- {
- error ("%q#D is protected within this context", diag_decl);
- inform (DECL_SOURCE_LOCATION (diag_decl),
- "declared protected here");
- if (afi)
- afi->record_access_failure (basetype_path, diag_decl);
- }
- else
- {
- error ("%q#D is inaccessible within this context", diag_decl);
- inform (DECL_SOURCE_LOCATION (diag_decl), "declared here");
- if (afi)
- afi->record_access_failure (basetype_path, diag_decl);
- }
- }
+ complain_about_access (decl, diag_decl, true);
+ if (afi)
+ afi->record_access_failure (basetype_path, decl, diag_decl);
return false;
}
return expr;
}
+/* Get any location for EXPR, falling back to input_location.
+
+ If the result is in a system header and is the virtual location for
+ a token coming from the expansion of a macro, unwind it to the
+ location of the expansion point of the macro (e.g. to avoid the
+ diagnostic being suppressed for expansions of NULL where "NULL" is
+ in a system header). */
+
+static location_t
+get_location_for_expr_unwinding_for_system_header (tree expr)
+{
+ location_t loc = EXPR_LOC_OR_LOC (expr, input_location);
+ loc = expansion_point_location_if_in_system_header (loc);
+ return loc;
+}
+
/* Perform warnings about peculiar, but valid, conversions from/to NULL.
+ Also handle a subset of zero as null warnings.
EXPR is implicitly converted to type TOTYPE.
FN and ARGNUM are used for diagnostics. */
if (null_node_p (expr) && TREE_CODE (totype) != BOOLEAN_TYPE
&& ARITHMETIC_TYPE_P (totype))
{
- source_location loc =
- expansion_point_location_if_in_system_header (input_location);
-
+ location_t loc = get_location_for_expr_unwinding_for_system_header (expr);
if (fn)
- warning_at (loc, OPT_Wconversion_null,
- "passing NULL to non-pointer argument %P of %qD",
- argnum, fn);
+ {
+ auto_diagnostic_group d;
+ if (warning_at (loc, OPT_Wconversion_null,
+ "passing NULL to non-pointer argument %P of %qD",
+ argnum, fn))
+ inform (get_fndecl_argument_location (fn, argnum),
+ " declared here");
+ }
else
warning_at (loc, OPT_Wconversion_null,
"converting to non-pointer type %qT from NULL", totype);
else if (TREE_CODE (TREE_TYPE (expr)) == BOOLEAN_TYPE
&& TYPE_PTR_P (totype))
{
+ location_t loc = get_location_for_expr_unwinding_for_system_header (expr);
if (fn)
- warning_at (input_location, OPT_Wconversion_null,
- "converting %<false%> to pointer type for argument %P "
- "of %qD", argnum, fn);
+ {
+ auto_diagnostic_group d;
+ if (warning_at (loc, OPT_Wconversion_null,
+ "converting %<false%> to pointer type for argument "
+ "%P of %qD", argnum, fn))
+ inform (get_fndecl_argument_location (fn, argnum),
+ " declared here");
+ }
else
- warning_at (input_location, OPT_Wconversion_null,
+ warning_at (loc, OPT_Wconversion_null,
"converting %<false%> to pointer type %qT", totype);
}
+ /* Handle zero as null pointer warnings for cases other
+ than EQ_EXPR and NE_EXPR */
+ else if (null_ptr_cst_p (expr) &&
+ (TYPE_PTR_OR_PTRMEM_P (totype) || NULLPTR_TYPE_P (totype)))
+ {
+ location_t loc = get_location_for_expr_unwinding_for_system_header (expr);
+ maybe_warn_zero_as_null_pointer_constant (expr, loc);
+ }
}
/* We gave a diagnostic during a conversion. If this was in the second
ARGNUM is zero based, -1 indicates the `this' argument of a method.
Return the location of the FNDECL itself if there are problems. */
-static location_t
+location_t
get_fndecl_argument_location (tree fndecl, int argnum)
{
+ /* The locations of implicitly-declared functions are likely to be
+ more meaningful than those of their parameters. */
+ if (DECL_ARTIFICIAL (fndecl))
+ return DECL_SOURCE_LOCATION (fndecl);
+
int i;
tree param;
return DECL_SOURCE_LOCATION (param);
}
+/* If FNDECL is non-NULL, issue a note highlighting ARGNUM
+ within its declaration (or the fndecl itself if something went
+ wrong). */
+
+void
+maybe_inform_about_fndecl_for_bogus_argument_init (tree fn, int argnum)
+{
+ if (fn)
+ inform (get_fndecl_argument_location (fn, argnum),
+ " initializing argument %P of %qD", argnum, fn);
+}
+
/* Perform the conversions in CONVS on the expression EXPR. FN and
ARGNUM are used for diagnostics. ARGNUM is zero based, -1
indicates the `this' argument of a method. INNER is nonzero when
tree totype = convs->type;
diagnostic_t diag_kind;
int flags;
- location_t loc = EXPR_LOC_OR_LOC (expr, input_location);
+ location_t loc = cp_expr_loc_or_loc (expr, input_location);
if (convs->bad_p && !(complain & tf_error))
return error_mark_node;
{
if (t->kind == ck_user && t->cand->reason)
{
+ auto_diagnostic_group d;
complained = permerror (loc, "invalid user-defined conversion "
"from %qH to %qI", TREE_TYPE (expr),
totype);
complain);
else
expr = cp_convert (totype, expr, complain);
- if (complained && fn)
- inform (DECL_SOURCE_LOCATION (fn),
- " initializing argument %P of %qD", argnum, fn);
+ if (complained)
+ maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
return expr;
}
else if (t->kind == ck_user || !t->bad_p)
break;
}
if (!complained)
- complained = permerror (loc, "invalid conversion from %qH to %qI",
- TREE_TYPE (expr), totype);
- if (complained && fn)
- inform (get_fndecl_argument_location (fn, argnum),
- " initializing argument %P of %qD", argnum, fn);
+ {
+ range_label_for_type_mismatch label (TREE_TYPE (expr), totype);
+ gcc_rich_location richloc (loc, &label);
+ complained = permerror (&richloc,
+ "invalid conversion from %qH to %qI",
+ TREE_TYPE (expr), totype);
+ }
+ if (complained)
+ maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
return cp_convert (totype, expr, complain);
}
if (DECL_NONCONVERTING_P (convfn) && DECL_CONSTRUCTOR_P (convfn)
&& BRACE_ENCLOSED_INITIALIZER_P (expr)
/* Unless this is for direct-list-initialization. */
- && !CONSTRUCTOR_IS_DIRECT_INIT (expr)
+ && (!CONSTRUCTOR_IS_DIRECT_INIT (expr) || convs->need_temporary_p)
/* And in C++98 a default constructor can't be explicit. */
&& cxx_dialect >= cxx11)
{
if (CONSTRUCTOR_NELTS (expr) == 0
&& FUNCTION_FIRST_USER_PARMTYPE (convfn) != void_list_node)
{
+ auto_diagnostic_group d;
if (pedwarn (loc, 0, "converting to %qT from initializer list "
"would use explicit constructor %qD",
totype, convfn))
/* If we're initializing from {}, it's value-initialization. */
if (BRACE_ENCLOSED_INITIALIZER_P (expr)
&& CONSTRUCTOR_NELTS (expr) == 0
- && TYPE_HAS_DEFAULT_CONSTRUCTOR (totype))
+ && TYPE_HAS_DEFAULT_CONSTRUCTOR (totype)
+ && !processing_template_decl)
{
bool direct = CONSTRUCTOR_IS_DIRECT_INIT (expr);
if (abstract_virtuals_error_sfinae (NULL_TREE, totype, complain))
return expr;
}
- expr = mark_rvalue_use (expr);
+ /* We don't know here whether EXPR is being used as an lvalue or
+ rvalue, but we know it's read. */
+ mark_exp_read (expr);
/* Pass LOOKUP_NO_CONVERSION so rvalue/base handling knows not to allow
any more UDCs. */
? LOOKUP_IMPLICIT : LOOKUP_NORMAL);
build_user_type_conversion (totype, convs->u.expr, flags, complain);
gcc_assert (seen_error ());
- if (fn)
- inform (DECL_SOURCE_LOCATION (fn),
- " initializing argument %P of %qD", argnum, fn);
+ maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
}
return error_mark_node;
{
/* Conversion to std::initializer_list<T>. */
tree elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (totype), 0);
- tree new_ctor = build_constructor (init_list_type_node, NULL);
unsigned len = CONSTRUCTOR_NELTS (expr);
- tree array, val, field;
- vec<constructor_elt, va_gc> *vec = NULL;
- unsigned ix;
+ tree array;
- /* Convert all the elements. */
- FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), ix, val)
+ if (len)
{
- tree sub = convert_like_real (convs->u.list[ix], val, fn, argnum,
- false, false, complain);
- if (sub == error_mark_node)
- return sub;
- if (!BRACE_ENCLOSED_INITIALIZER_P (val)
- && !check_narrowing (TREE_TYPE (sub), val, complain))
- return error_mark_node;
- CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_ctor), NULL_TREE, sub);
- if (!TREE_CONSTANT (sub))
- TREE_CONSTANT (new_ctor) = false;
+ tree val; unsigned ix;
+
+ tree new_ctor = build_constructor (init_list_type_node, NULL);
+
+ /* Convert all the elements. */
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), ix, val)
+ {
+ tree sub = convert_like_real (convs->u.list[ix], val, fn,
+ argnum, false, false, complain);
+ if (sub == error_mark_node)
+ return sub;
+ if (!BRACE_ENCLOSED_INITIALIZER_P (val)
+ && !check_narrowing (TREE_TYPE (sub), val, complain))
+ return error_mark_node;
+ CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_ctor),
+ NULL_TREE, sub);
+ if (!TREE_CONSTANT (sub))
+ TREE_CONSTANT (new_ctor) = false;
+ }
+ /* Build up the array. */
+ elttype = cp_build_qualified_type
+ (elttype, cp_type_quals (elttype) | TYPE_QUAL_CONST);
+ array = build_array_of_n_type (elttype, len);
+ array = finish_compound_literal (array, new_ctor, complain);
+ /* Take the address explicitly rather than via decay_conversion
+ to avoid the error about taking the address of a temporary. */
+ array = cp_build_addr_expr (array, complain);
}
- /* Build up the array. */
- elttype = cp_build_qualified_type
- (elttype, cp_type_quals (elttype) | TYPE_QUAL_CONST);
- array = build_array_of_n_type (elttype, len);
- array = finish_compound_literal (array, new_ctor, complain);
- /* Take the address explicitly rather than via decay_conversion
- to avoid the error about taking the address of a temporary. */
- array = cp_build_addr_expr (array, complain);
+ else
+ array = nullptr_node;
+
array = cp_convert (build_pointer_type (elttype), array, complain);
if (array == error_mark_node)
return error_mark_node;
totype = complete_type_or_maybe_complain (totype, NULL_TREE, complain);
if (!totype)
return error_mark_node;
- field = next_initializable_field (TYPE_FIELDS (totype));
+ tree field = next_initializable_field (TYPE_FIELDS (totype));
+ vec<constructor_elt, va_gc> *vec = NULL;
CONSTRUCTOR_APPEND_ELT (vec, field, array);
field = next_initializable_field (DECL_CHAIN (field));
CONSTRUCTOR_APPEND_ELT (vec, field, size_int (len));
- new_ctor = build_constructor (totype, vec);
+ tree new_ctor = build_constructor (totype, vec);
return get_target_expr_sfinae (new_ctor, complain);
}
{
if (complain & tf_error)
{
+ auto_diagnostic_group d;
maybe_print_user_conv_context (convs);
- if (fn)
- inform (DECL_SOURCE_LOCATION (fn),
- " initializing argument %P of %qD", argnum, fn);
+ maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
}
return error_mark_node;
}
expr = build_temp (expr, totype, flags, &diag_kind, complain);
if (diag_kind && complain)
{
+ auto_diagnostic_group d;
maybe_print_user_conv_context (convs);
- if (fn)
- inform (DECL_SOURCE_LOCATION (fn),
- " initializing argument %P of %qD", argnum, fn);
+ maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
}
return build_cplus_new (totype, expr, complain);
if (convs->bad_p && !next_conversion (convs)->bad_p)
{
tree extype = TREE_TYPE (expr);
+ auto_diagnostic_group d;
if (TYPE_REF_IS_RVALUE (ref_type)
&& lvalue_p (expr))
error_at (loc, "cannot bind rvalue reference of type %qH to "
else
gcc_unreachable ();
maybe_print_user_conv_context (convs);
- if (fn)
- inform (DECL_SOURCE_LOCATION (fn),
- " initializing argument %P of %qD", argnum, fn);
+ maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
+
return error_mark_node;
}
}
if (convs->check_narrowing
- && !check_narrowing (totype, expr, complain))
+ && !check_narrowing (totype, expr, complain,
+ convs->check_narrowing_const_only))
return error_mark_node;
+ warning_sentinel w (warn_zero_as_null_pointer_constant);
if (issue_conversion_warnings)
expr = cp_convert_and_check (totype, expr, complain);
else
convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain)
{
tree arg_type;
- location_t loc = EXPR_LOC_OR_LOC (arg, input_location);
+ location_t loc = cp_expr_loc_or_loc (arg, input_location);
/* [expr.call]
&& TYPE_MODE (TREE_TYPE (prom)) != TYPE_MODE (arg_type)
&& (complain & tf_warning))
warning_at (loc, OPT_Wabi, "scoped enum %qT passed through ... as "
- "%qT before -fabi-version=6, %qT after", arg_type,
+ "%qT before %<-fabi-version=6%>, %qT after", arg_type,
TREE_TYPE (prom), ENUM_UNDERLYING_TYPE (arg_type));
if (!abi_version_at_least (6))
arg = prom;
/* va_arg (EXPR, TYPE) is a builtin. Make sure it is not abused. */
tree
-build_x_va_arg (source_location loc, tree expr, tree type)
+build_x_va_arg (location_t loc, tree expr, tree type)
{
if (processing_template_decl)
{
expr = mark_lvalue_use (expr);
- if (TREE_CODE (type) == REFERENCE_TYPE)
+ if (TYPE_REF_P (type))
{
error ("cannot receive reference type %qT through %<...%>", type);
return error_mark_node;
push_deferring_access_checks (dk_no_check);
/* We must make a copy of ARG, in case subsequent processing
alters any part of it. */
- arg = break_out_target_exprs (arg);
+ arg = break_out_target_exprs (arg, /*clear location*/true);
+
arg = convert_for_initialization (0, type, arg, LOOKUP_IMPLICIT,
ICR_DEFAULT_ARGUMENT, fn, parmnum,
complain);
"argument of function call might be a candidate "
"for a format attribute");
}
- maybe_warn_parm_abi (type, EXPR_LOC_OR_LOC (val, input_location));
+ maybe_warn_parm_abi (type, cp_expr_loc_or_loc (val, input_location));
}
+
+ if (complain & tf_warning)
+ warn_for_address_or_pointer_of_packed_member (type, val);
+
return val;
}
if (c->kind == ck_rvalue)
return true;
- if (c->kind == ck_user && TREE_CODE (c->type) != REFERENCE_TYPE)
+ if (c->kind == ck_user && !TYPE_REF_P (c->type))
return true;
if (c->kind == ck_identity && c->u.expr
&& TREE_CODE (c->u.expr) == TARGET_EXPR)
return false;
}
+/* Call the trivial destructor for INSTANCE, which can be either an lvalue of
+ class type or a pointer to class type. */
+
+tree
+build_trivial_dtor_call (tree instance)
+{
+ gcc_assert (!is_dummy_object (instance));
+
+ if (!flag_lifetime_dse)
+ {
+ no_clobber:
+ return fold_convert (void_type_node, instance);
+ }
+
+ if (INDIRECT_TYPE_P (TREE_TYPE (instance)))
+ {
+ if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (instance))))
+ goto no_clobber;
+ instance = cp_build_fold_indirect_ref (instance);
+ }
+
+ /* A trivial destructor should still clobber the object. */
+ tree clobber = build_clobber (TREE_TYPE (instance));
+ return build2 (MODIFY_EXPR, void_type_node,
+ instance, clobber);
+}
+
/* Subroutine of the various build_*_call functions. Overload resolution
has chosen a winning candidate CAND; build up a CALL_EXPR accordingly.
ARGS is a TREE_LIST of the unconverted arguments to the call. FLAGS is a
{
/* The implicit move specified in 15.8.3/3 fails "...if the type of
the first parameter of the selected constructor is not an rvalue
- reference to the object’s type (possibly cv-qualified)...." */
+ reference to the object's type (possibly cv-qualified)...." */
gcc_assert (!(complain & tf_error));
tree ptype = convs[0]->type;
- if (TREE_CODE (ptype) != REFERENCE_TYPE
+ if (!TYPE_REF_P (ptype)
|| !TYPE_REF_IS_RVALUE (ptype)
|| CONVERSION_RANK (convs[0]) > cr_exact)
return error_mark_node;
{
if (complain & tf_error)
{
+ auto_diagnostic_group d;
if (permerror (input_location, "passing %qT as %<this%> "
"argument discards qualifiers",
TREE_TYPE (argtype)))
pedwarn (DECL_SOURCE_LOCATION (cand->fn), 0,
" in call to %qD", cand->fn);
pedwarn (input_location, 0,
- " (you can disable this with -fno-deduce-init-list)");
+ " (you can disable this with "
+ "%<-fno-deduce-init-list%>)");
}
}
/* For -Wformat undo the implicit passing by hidden reference
done by convert_arg_to_ellipsis. */
if (TREE_CODE (argarray[j]) == ADDR_EXPR
- && TREE_CODE (TREE_TYPE (argarray[j])) == REFERENCE_TYPE)
+ && TYPE_REF_P (TREE_TYPE (argarray[j])))
fargs[j] = TREE_OPERAND (argarray[j], 0);
else
- fargs[j] = maybe_constant_value (argarray[j]);
+ fargs[j] = argarray[j];
}
warned_p = check_function_arguments (input_location, fn, TREE_TYPE (fn),
targ = arg;
/* Strip the reference binding for the constructor parameter. */
if (CONVERT_EXPR_P (targ)
- && TREE_CODE (TREE_TYPE (targ)) == REFERENCE_TYPE)
+ && TYPE_REF_P (TREE_TYPE (targ)))
targ = TREE_OPERAND (targ, 0);
/* But don't strip any other reference bindings; binding a temporary to a
reference prevents copy elision. */
while ((CONVERT_EXPR_P (targ)
- && TREE_CODE (TREE_TYPE (targ)) != REFERENCE_TYPE)
+ && !TYPE_REF_P (TREE_TYPE (targ)))
|| TREE_CODE (targ) == NON_LVALUE_EXPR)
targ = TREE_OPERAND (targ, 0);
if (TREE_CODE (targ) == ADDR_EXPR)
/* See unsafe_copy_elision_p. */
|| DECL_BASE_CONSTRUCTOR_P (fn));
- /* [class.copy]: the copy constructor is implicitly defined even if
- the implementation elided its use. */
- if (!trivial && !force_elide)
+ fa = argarray[0];
+ bool unsafe = unsafe_copy_elision_p (fa, arg);
+ bool eliding_temp = (TREE_CODE (arg) == TARGET_EXPR && !unsafe);
+
+ /* [class.copy]: the copy constructor is implicitly defined even if the
+ implementation elided its use. But don't warn about deprecation when
+ eliding a temporary, as then no copy is actually performed. */
+ warning_sentinel s (warn_deprecated_copy, eliding_temp);
+ if (force_elide)
+ /* The language says this isn't called. */;
+ else if (!trivial)
{
if (!mark_used (fn, complain) && !(complain & tf_error))
return error_mark_node;
already_used = true;
}
+ else
+ cp_warn_deprecated_use (fn, complain);
/* If we're creating a temp and we already have one, don't create a
new one. If we're not creating a temp but we get one, use
INIT_EXPR to collapse the temp into our target. Otherwise, if the
ctor is trivial, do a bitwise copy with a simple TARGET_EXPR for a
temp or an INIT_EXPR otherwise. */
- fa = argarray[0];
if (is_dummy_object (fa))
{
if (TREE_CODE (arg) == TARGET_EXPR)
return force_target_expr (DECL_CONTEXT (fn), arg, complain);
}
else if ((trivial || TREE_CODE (arg) == TARGET_EXPR)
- && !unsafe_copy_elision_p (fa, arg))
+ && !unsafe)
{
tree to = cp_stabilize_reference (cp_build_fold_indirect_ref (fa));
tree type = TREE_TYPE (to);
tree as_base = CLASSTYPE_AS_BASE (type);
tree arg = argarray[1];
+ location_t loc = cp_expr_loc_or_loc (arg, input_location);
- if (is_really_empty_class (type))
+ if (is_really_empty_class (type, /*ignore_vptr*/true))
{
/* Avoid copying empty classes. */
val = build2 (COMPOUND_EXPR, type, arg, to);
}
else if (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (as_base)))
{
+ if (is_std_init_list (type)
+ && conv_binds_ref_to_prvalue (convs[1]))
+ warning_at (loc, OPT_Winit_list_lifetime,
+ "assignment from temporary initializer_list does not "
+ "extend the lifetime of the underlying array");
arg = cp_build_fold_indirect_ref (arg);
val = build2 (MODIFY_EXPR, TREE_TYPE (to), to, arg);
}
TREE_NO_WARNING (val) = 1;
}
+ cp_warn_deprecated_use (fn, complain);
+
return val;
}
else if (trivial_fn_p (fn))
{
if (DECL_DESTRUCTOR_P (fn))
- return fold_convert (void_type_node, argarray[0]);
+ return build_trivial_dtor_call (argarray[0]);
else if (default_ctor_p (fn))
{
if (is_dummy_object (argarray[0]))
&& 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])),
unsigned srcidx = !dstidx;
tree dest = (*args)[dstidx];
- if (!TREE_TYPE (dest) || !POINTER_TYPE_P (TREE_TYPE (dest)))
+ if (!TREE_TYPE (dest) || !INDIRECT_TYPE_P (TREE_TYPE (dest)))
return;
tree srctype = NULL_TREE;
bool special = same_type_ignoring_top_level_qualifiers_p (ctx, desttype);
tree binfo = TYPE_BINFO (ctx);
- /* FIXME: The following if statement is overly permissive (see
- bug 84851). Remove it in GCC 9. */
- if (special
- && !BINFO_VTABLE (binfo)
- && !BINFO_N_BASE_BINFOS (binfo)
- && (DECL_CONSTRUCTOR_P (current_function_decl)
- || DECL_DESTRUCTOR_P (current_function_decl)))
- return;
-
if (special
&& !BINFO_VTABLE (binfo)
&& !first_non_trivial_field (desttype))
case BUILT_IN_MEMPCPY:
/* Determine the type of the source object. */
srctype = TREE_TYPE ((*args)[srcidx]);
- if (!srctype || !POINTER_TYPE_P (srctype))
+ if (!srctype || !INDIRECT_TYPE_P (srctype))
srctype = void_type_node;
else
srctype = TREE_TYPE (srctype);
tree fndecl;
/* Remember roughly where this call is. */
- location_t loc = EXPR_LOC_OR_LOC (fn, input_location);
+ location_t loc = cp_expr_loc_or_loc (fn, input_location);
fn = build_call_a (fn, nargs, argarray);
SET_EXPR_LOCATION (fn, loc);
/* Check that arguments to builtin functions match the expectations. */
if (fndecl
- && DECL_BUILT_IN (fndecl)
- && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+ && !processing_template_decl
+ && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
{
int i;
/* We need to take care that values to BUILT_IN_NORMAL
are reduced. */
for (i = 0; i < nargs; i++)
- argarray[i] = fold_non_dependent_expr (argarray[i]);
+ argarray[i] = maybe_constant_value (argarray[i]);
if (!check_builtin_function_arguments (EXPR_LOCATION (fn), vNULL, fndecl,
nargs, argarray))
tree ret;
gcc_assert (IDENTIFIER_CDTOR_P (name) || name == assign_op_identifier);
+
+ if (error_operand_p (instance))
+ return error_mark_node;
+
+ if (IDENTIFIER_DTOR_P (name))
+ {
+ gcc_assert (args == NULL || vec_safe_is_empty (*args));
+ if (!type_build_dtor_call (TREE_TYPE (instance)))
+ /* Shortcut to avoid lazy destructor declaration. */
+ return build_trivial_dtor_call (instance);
+ }
+
if (TYPE_P (binfo))
{
/* Resolve the name. */
instance = build_dummy_object (class_type);
else
{
- if (IDENTIFIER_DTOR_P (name))
- gcc_assert (args == NULL || vec_safe_is_empty (*args));
-
/* Convert to the base class, if necessary. */
if (!same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (instance), BINFO_TYPE (binfo)))
return CONST_CAST (char *, pretty_name);
}
+/* If CANDIDATES contains exactly one candidate, return it, otherwise
+ return NULL. */
+
+static z_candidate *
+single_z_candidate (z_candidate *candidates)
+{
+ if (candidates == NULL)
+ return NULL;
+
+ if (candidates->next)
+ return NULL;
+
+ return candidates;
+}
+
+/* If CANDIDATE is invalid due to a bad argument type, return the
+ pertinent conversion_info.
+
+ Otherwise, return NULL. */
+
+static const conversion_info *
+maybe_get_bad_conversion_for_unmatched_call (const z_candidate *candidate)
+{
+ /* Must be an rr_arg_conversion or rr_bad_arg_conversion. */
+ rejection_reason *r = candidate->reason;
+
+ if (r == NULL)
+ return NULL;
+
+ switch (r->code)
+ {
+ default:
+ return NULL;
+
+ case rr_arg_conversion:
+ return &r->u.conversion;
+
+ case rr_bad_arg_conversion:
+ return &r->u.bad_conversion;
+ }
+}
+
+/* Issue an error and note complaining about a bad argument type at a
+ callsite with a single candidate FNDECL.
+
+ ARG_LOC is the location of the argument (or UNKNOWN_LOCATION, in which
+ case input_location is used).
+ FROM_TYPE is the type of the actual argument; TO_TYPE is the type of
+ the formal parameter. */
+
+void
+complain_about_bad_argument (location_t arg_loc,
+ tree from_type, tree to_type,
+ tree fndecl, int parmnum)
+{
+ auto_diagnostic_group d;
+ range_label_for_type_mismatch rhs_label (from_type, to_type);
+ range_label *label = &rhs_label;
+ if (arg_loc == UNKNOWN_LOCATION)
+ {
+ arg_loc = input_location;
+ label = NULL;
+ }
+ gcc_rich_location richloc (arg_loc, label);
+ error_at (&richloc,
+ "cannot convert %qH to %qI",
+ from_type, to_type);
+ maybe_inform_about_fndecl_for_bogus_argument_init (fndecl,
+ parmnum);
+}
+
+/* Subroutine of build_new_method_call_1, for where there are no viable
+ candidates for the call. */
+
+static void
+complain_about_no_candidates_for_method_call (tree instance,
+ z_candidate *candidates,
+ tree explicit_targs,
+ tree basetype,
+ tree optype, tree name,
+ bool skip_first_for_error,
+ vec<tree, va_gc> *user_args)
+{
+ auto_diagnostic_group d;
+ if (!COMPLETE_OR_OPEN_TYPE_P (basetype))
+ cxx_incomplete_type_error (instance, basetype);
+ else if (optype)
+ error ("no matching function for call to %<%T::operator %T(%A)%#V%>",
+ basetype, optype, build_tree_list_vec (user_args),
+ TREE_TYPE (instance));
+ else
+ {
+ /* Special-case for when there's a single candidate that's failing
+ due to a bad argument type. */
+ if (z_candidate *candidate = single_z_candidate (candidates))
+ if (const conversion_info *conv
+ = maybe_get_bad_conversion_for_unmatched_call (candidate))
+ {
+ complain_about_bad_argument (conv->loc,
+ conv->from, conv->to_type,
+ candidate->fn, conv->n_arg);
+ return;
+ }
+
+ tree arglist = build_tree_list_vec (user_args);
+ tree errname = name;
+ bool twiddle = false;
+ if (IDENTIFIER_CDTOR_P (errname))
+ {
+ twiddle = IDENTIFIER_DTOR_P (errname);
+ errname = constructor_name (basetype);
+ }
+ if (explicit_targs)
+ errname = lookup_template_function (errname, explicit_targs);
+ if (skip_first_for_error)
+ arglist = TREE_CHAIN (arglist);
+ error ("no matching function for call to %<%T::%s%E(%A)%#V%>",
+ basetype, &"~"[!twiddle], errname, arglist,
+ TREE_TYPE (instance));
+ }
+ print_z_candidates (location_of (name), candidates);
+}
+
/* Build a call to "INSTANCE.FN (ARGS)". If FN_P is non-NULL, it will
be set, upon return, to the function called. ARGS may be NULL.
This may change ARGS. */
basetype = TYPE_MAIN_VARIANT (TREE_TYPE (instance));
gcc_assert (CLASS_TYPE_P (basetype));
- if (processing_template_decl)
- {
- orig_args = args == NULL ? NULL : make_tree_vector_copy (*args);
- instance = build_non_dependent_expr (instance);
- if (args != NULL)
- make_args_non_dependent (*args);
- }
-
user_args = args == NULL ? NULL : *args;
/* Under DR 147 A::A() is an invalid constructor call,
not a functional cast. */
basetype = DECL_CONTEXT (fn);
name = constructor_name (basetype);
+ auto_diagnostic_group d;
if (permerror (input_location,
"cannot call constructor %<%T::%D%> directly",
basetype, name))
return call;
}
+ if (processing_template_decl)
+ {
+ orig_args = args == NULL ? NULL : make_tree_vector_copy (*args);
+ instance = build_non_dependent_expr (instance);
+ if (args != NULL)
+ make_args_non_dependent (*args);
+ }
+
/* Process the argument list. */
if (args != NULL && *args != NULL)
{
*args = resolve_args (*args, complain);
if (*args == NULL)
return error_mark_node;
+ user_args = *args;
}
/* Consider the object argument to be used even if we end up selecting a
if (!any_viable_p)
{
if (complain & tf_error)
- {
- if (!COMPLETE_OR_OPEN_TYPE_P (basetype))
- cxx_incomplete_type_error (instance, basetype);
- else if (optype)
- error ("no matching function for call to %<%T::operator %T(%A)%#V%>",
- basetype, optype, build_tree_list_vec (user_args),
- TREE_TYPE (instance));
- else
- {
- tree arglist = build_tree_list_vec (user_args);
- tree errname = name;
- bool twiddle = false;
- if (IDENTIFIER_CDTOR_P (errname))
- {
- twiddle = IDENTIFIER_DTOR_P (errname);
- errname = constructor_name (basetype);
- }
- if (explicit_targs)
- errname = lookup_template_function (errname, explicit_targs);
- if (skip_first_for_error)
- arglist = TREE_CHAIN (arglist);
- error ("no matching function for call to %<%T::%s%E(%A)%#V%>",
- basetype, &"~"[!twiddle], errname, arglist,
- TREE_TYPE (instance));
- }
- print_z_candidates (location_of (name), candidates);
- }
+ complain_about_no_candidates_for_method_call (instance, candidates,
+ explicit_targs, basetype,
+ optype, name,
+ skip_first_for_error,
+ user_args);
call = error_mark_node;
}
else
arglist = build_tree_list_vec (user_args);
if (skip_first_for_error)
arglist = TREE_CHAIN (arglist);
+ auto_diagnostic_group d;
if (!any_strictly_viable (candidates))
error ("no matching function for call to %<%s(%A)%>",
pretty_name, arglist);
Specifically, we need to do the reference binding comparison at the
end of this function. */
- if (ics1->user_conv_p || ics1->kind == ck_list || ics1->kind == ck_aggr)
+ if (ics1->user_conv_p || ics1->kind == ck_list
+ || ics1->kind == ck_aggr || ics2->kind == ck_aggr)
{
conversion *t1;
conversion *t2;
- for (t1 = ics1; t1->kind != ck_user; t1 = next_conversion (t1))
+ for (t1 = ics1; t1 && t1->kind != ck_user; t1 = next_conversion (t1))
if (t1->kind == ck_ambig || t1->kind == ck_aggr
|| t1->kind == ck_list)
break;
- for (t2 = ics2; t2->kind != ck_user; t2 = next_conversion (t2))
+ for (t2 = ics2; t2 && t2->kind != ck_user; t2 = next_conversion (t2))
if (t2->kind == ck_ambig || t2->kind == ck_aggr
|| t2->kind == ck_list)
break;
- if (t1->kind != t2->kind)
+ if (!t1 || !t2 || t1->kind != t2->kind)
return 0;
else if (t1->kind == ck_user)
{
tree t = TREE_TYPE (TREE_TYPE (l->fn));
tree f = TREE_TYPE (TREE_TYPE (w->fn));
- if (TREE_CODE (t) == TREE_CODE (f) && POINTER_TYPE_P (t))
+ if (TREE_CODE (t) == TREE_CODE (f) && INDIRECT_TYPE_P (t))
{
t = TREE_TYPE (t);
f = TREE_TYPE (f);
else if (warn)
{
tree source = source_type (w->convs[0]);
- if (POINTER_TYPE_P (source))
+ if (INDIRECT_TYPE_P (source))
source = TREE_TYPE (source);
+ auto_diagnostic_group d;
if (warning (OPT_Wconversion, "choosing %qD over %qD", w->fn, l->fn)
&& warning (OPT_Wconversion, " for conversion from %qH to %qI",
source, w->second_conv->type))
{
if (complain & tf_error)
{
+ auto_diagnostic_group d;
if (permerror (input_location,
"default argument mismatch in "
"overload resolution"))
tweak:
- /* Extension: If the worst conversion for one candidate is worse than the
+ /* Extension: If the worst conversion for one candidate is better than the
worst conversion for the other, take the first. */
if (!pedantic && (complain & tf_warning_or_error))
{
return 0;
if (warn)
{
- pedwarn (input_location, 0,
- "ISO C++ says that these are ambiguous, even "
- "though the worst conversion for the first is better than "
- "the worst conversion for the second:");
- print_z_candidate (input_location, _("candidate 1:"), w);
- print_z_candidate (input_location, _("candidate 2:"), l);
+ auto_diagnostic_group d;
+ if (pedwarn (input_location, 0,
+ "ISO C++ says that these are ambiguous, even "
+ "though the worst conversion for the first is "
+ "better than the worst conversion for the second:"))
+ {
+ print_z_candidate (input_location, _("candidate 1:"), w);
+ print_z_candidate (input_location, _("candidate 2:"), l);
+ }
}
else
add_warning (w, l);
{
conversion *conv;
void *p;
- location_t loc = EXPR_LOC_OR_LOC (expr, input_location);
+ location_t loc = cp_expr_loc_or_loc (expr, input_location);
- if (TREE_CODE (type) == REFERENCE_TYPE)
+ if (TYPE_REF_P (type))
expr = mark_lvalue_use (expr);
else
expr = mark_rvalue_use (expr);
else if (invalid_nonstatic_memfn_p (loc, expr, complain))
/* We gave an error. */;
else
- error_at (loc, "could not convert %qE from %qH to %qI", expr,
- TREE_TYPE (expr), type);
+ {
+ range_label_for_type_mismatch label (TREE_TYPE (expr), type);
+ gcc_rich_location rich_loc (loc, &label);
+ error_at (&rich_loc, "could not convert %qE from %qH to %qI",
+ expr, TREE_TYPE (expr), type);
+ }
}
expr = error_mark_node;
}
expr = build1 (IMPLICIT_CONV_EXPR, type, expr);
if (!(flags & LOOKUP_ONLYCONVERTING))
IMPLICIT_CONV_EXPR_DIRECT_INIT (expr) = true;
+ if (flags & LOOKUP_NO_NARROWING)
+ IMPLICIT_CONV_EXPR_BRACED_INIT (expr) = true;
}
else
expr = convert_like (conv, expr, complain);
&& (TREE_STATIC (decl) || CP_DECL_THREAD_LOCAL_P (decl)))
{
/* Namespace-scope or local static; give it a mangled name. */
- /* FIXME share comdat with decl? */
+
+ /* If an initializer is visible to multiple translation units, those
+ translation units must agree on the addresses of the
+ temporaries. Therefore the temporaries must be given a consistent name
+ and vague linkage. The mangled name of a temporary is the name of the
+ non-temporary object in whose initializer they appear, prefixed with
+ GR and suffixed with a sequence number mangled using the usual rules
+ for a seq-id. Temporaries are numbered with a pre-order, depth-first,
+ left-to-right walk of the complete initializer. */
TREE_STATIC (var) = TREE_STATIC (decl);
+ TREE_PUBLIC (var) = TREE_PUBLIC (decl);
+ if (vague_linkage_p (decl))
+ comdat_linkage (var);
+
CP_DECL_THREAD_LOCAL_P (var) = CP_DECL_THREAD_LOCAL_P (decl);
set_decl_tls_model (var, DECL_TLS_MODEL (decl));
tree name = mangle_ref_init_variable (decl);
DECL_NAME (var) = name;
SET_DECL_ASSEMBLER_NAME (var, name);
-
- var = pushdecl (var);
}
else
/* Create a new cleanup level if necessary. */
maybe_push_cleanup_level (type);
- return var;
+ return pushdecl (var);
}
/* EXPR is the initializer for a variable DECL of reference or
lvalue-rvalue conversion applied to "a glvalue of literal type
that refers to a non-volatile temporary object initialized
with a constant expression". Rather than try to communicate
- that this VAR_DECL is a temporary, just mark it constexpr.
-
- Currently this is only useful for initializer_list temporaries,
- since reference vars can't appear in constant expressions. */
+ that this VAR_DECL is a temporary, just mark it constexpr. */
DECL_DECLARED_CONSTEXPR_P (var) = true;
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (var) = true;
TREE_CONSTANT (var) = true;
+ TREE_READONLY (var) = true;
}
DECL_INITIAL (var) = init;
init = NULL_TREE;
{
conversion *conv;
void *p;
- location_t loc = EXPR_LOC_OR_LOC (expr, input_location);
+ location_t loc = cp_expr_loc_or_loc (expr, input_location);
if (type == error_mark_node || error_operand_p (expr))
return error_mark_node;
if (TREE_CODE (sub) != ADDR_EXPR)
return init;
/* Deal with binding to a subobject. */
- for (p = &TREE_OPERAND (sub, 0); TREE_CODE (*p) == COMPONENT_REF; )
+ for (p = &TREE_OPERAND (sub, 0);
+ (TREE_CODE (*p) == COMPONENT_REF
+ || TREE_CODE (*p) == ARRAY_REF); )
p = &TREE_OPERAND (*p, 0);
if (TREE_CODE (*p) == TARGET_EXPR)
{
tree type = TREE_TYPE (init);
if (processing_template_decl)
return init;
- if (TREE_CODE (type) == REFERENCE_TYPE)
+ if (TYPE_REF_P (type))
init = extend_ref_init_temps_1 (decl, init, cleanups);
else
{
type_has_extended_temps (tree type)
{
type = strip_array_types (type);
- if (TREE_CODE (type) == REFERENCE_TYPE)
+ if (TYPE_REF_P (type))
return true;
if (CLASS_TYPE_P (type))
{