/* 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).
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
/*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 *);
/* 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 {
}
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;
}
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 (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;
|| (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;
from = TREE_TYPE (expr);
}
+ bool copy_list_init = false;
if (expr && BRACE_ENCLOSED_INITIALIZER_P (expr))
{
maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
/* 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. */
- CONSTRUCTOR_IS_DIRECT_INIT (expr) = false;
+ copy_list_init = true;
skip:;
}
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))
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;
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]));
}
}
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);
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 "
{
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)
{
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;
error ("invalid use of void expression");
return NULL;
}
- else if (invalid_nonstatic_memfn_p (arg->exp.locus, arg, complain))
+ else if (invalid_nonstatic_memfn_p (EXPR_LOCATION (arg), arg, complain))
return NULL;
}
return args;
}
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))
{
+ /* '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:
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)
/* 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;
}
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;
/* 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)
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.
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
else if (null_ptr_cst_p (expr) &&
(TYPE_PTR_OR_PTRMEM_P (totype) || NULLPTR_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);
maybe_warn_zero_as_null_pointer_constant (expr, loc);
}
}
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
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)
"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);
+ 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 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);
}
{
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;
}
{
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);
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;
}
&& 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)
{
}
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;
}
{
/* 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 (!TYPE_REF_P (ptype)
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%>)");
}
}
&& 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),
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);
&& 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])),
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))
/* Check that arguments to builtin functions match the expectations. */
if (fndecl
&& !processing_template_decl
- && DECL_BUILT_IN (fndecl)
- && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+ && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
{
int i;
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. */
if (!any_viable_p)
{
if (complain & tf_error)
- {
- 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
- {
- 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
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)
{
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))
{
if (warn)
{
auto_diagnostic_group d;
- 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);
+ 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);
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