mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-03 00:29:47 +00:00
13321 lines
410 KiB
C++
13321 lines
410 KiB
C++
/* Functions related to invoking -*- C++ -*- methods and overloaded functions.
|
|
Copyright (C) 1987-2022 Free Software Foundation, Inc.
|
|
Contributed by Michael Tiemann (tiemann@cygnus.com) and
|
|
modified by Brendan Kehoe (brendan@cygnus.com).
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
GCC is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
/* High-level class interface. */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "target.h"
|
|
#include "cp-tree.h"
|
|
#include "timevar.h"
|
|
#include "stringpool.h"
|
|
#include "cgraph.h"
|
|
#include "stor-layout.h"
|
|
#include "trans-mem.h"
|
|
#include "flags.h"
|
|
#include "toplev.h"
|
|
#include "intl.h"
|
|
#include "convert.h"
|
|
#include "langhooks.h"
|
|
#include "c-family/c-objc.h"
|
|
#include "internal-fn.h"
|
|
#include "stringpool.h"
|
|
#include "attribs.h"
|
|
#include "gcc-rich-location.h"
|
|
|
|
/* The various kinds of conversion. */
|
|
|
|
enum conversion_kind {
|
|
ck_identity,
|
|
ck_lvalue,
|
|
ck_fnptr,
|
|
ck_qual,
|
|
ck_std,
|
|
ck_ptr,
|
|
ck_pmem,
|
|
ck_base,
|
|
ck_ref_bind,
|
|
ck_user,
|
|
ck_ambig,
|
|
ck_list,
|
|
ck_aggr,
|
|
ck_rvalue
|
|
};
|
|
|
|
/* The rank of the conversion. Order of the enumerals matters; better
|
|
conversions should come earlier in the list. */
|
|
|
|
enum conversion_rank {
|
|
cr_identity,
|
|
cr_exact,
|
|
cr_promotion,
|
|
cr_std,
|
|
cr_pbool,
|
|
cr_user,
|
|
cr_ellipsis,
|
|
cr_bad
|
|
};
|
|
|
|
/* An implicit conversion sequence, in the sense of [over.best.ics].
|
|
The first conversion to be performed is at the end of the chain.
|
|
That conversion is always a cr_identity conversion. */
|
|
|
|
struct conversion {
|
|
/* The kind of conversion represented by this step. */
|
|
conversion_kind kind;
|
|
/* The rank of this conversion. */
|
|
conversion_rank rank;
|
|
BOOL_BITFIELD user_conv_p : 1;
|
|
BOOL_BITFIELD ellipsis_p : 1;
|
|
BOOL_BITFIELD this_p : 1;
|
|
/* True if this conversion would be permitted with a bending of
|
|
language standards, e.g. disregarding pointer qualifiers or
|
|
converting integers to pointers. */
|
|
BOOL_BITFIELD bad_p : 1;
|
|
/* If KIND is ck_ref_bind or ck_base, true to indicate that a
|
|
temporary should be created to hold the result of the
|
|
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
|
|
from a pointer-to-derived to pointer-to-base is being performed. */
|
|
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 or ck_base,
|
|
true when we are treating an lvalue as an rvalue (12.8p33). If
|
|
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;
|
|
/* True if this conversion is taking place in a copy-initialization context
|
|
and we should only consider converting constructors. Only set in
|
|
ck_base and ck_rvalue. */
|
|
BOOL_BITFIELD copy_init_p : 1;
|
|
/* The type of the expression resulting from the conversion. */
|
|
tree type;
|
|
union {
|
|
/* The next conversion in the chain. Since the conversions are
|
|
arranged from outermost to innermost, the NEXT conversion will
|
|
actually be performed before this conversion. This variant is
|
|
used only when KIND is neither ck_identity, ck_aggr, ck_ambig nor
|
|
ck_list. Please use the next_conversion function instead
|
|
of using this field directly. */
|
|
conversion *next;
|
|
/* The expression at the beginning of the conversion chain. This
|
|
variant is used only if KIND is ck_identity, ck_aggr, or ck_ambig.
|
|
You can use conv_get_original_expr to get this expression. */
|
|
tree expr;
|
|
/* The array of conversions for an initializer_list, so this
|
|
variant is used only when KIN D is ck_list. */
|
|
conversion **list;
|
|
} u;
|
|
/* The function candidate corresponding to this conversion
|
|
sequence. This field is only used if KIND is ck_user. */
|
|
struct z_candidate *cand;
|
|
};
|
|
|
|
#define CONVERSION_RANK(NODE) \
|
|
((NODE)->bad_p ? cr_bad \
|
|
: (NODE)->ellipsis_p ? cr_ellipsis \
|
|
: (NODE)->user_conv_p ? cr_user \
|
|
: (NODE)->rank)
|
|
|
|
#define BAD_CONVERSION_RANK(NODE) \
|
|
((NODE)->ellipsis_p ? cr_ellipsis \
|
|
: (NODE)->user_conv_p ? cr_user \
|
|
: (NODE)->rank)
|
|
|
|
static struct obstack conversion_obstack;
|
|
static bool conversion_obstack_initialized;
|
|
struct rejection_reason;
|
|
|
|
static struct z_candidate * tourney (struct z_candidate *, tsubst_flags_t);
|
|
static int equal_functions (tree, tree);
|
|
static int joust (struct z_candidate *, struct z_candidate *, bool,
|
|
tsubst_flags_t);
|
|
static int compare_ics (conversion *, conversion *);
|
|
static void maybe_warn_class_memaccess (location_t, tree,
|
|
const vec<tree, va_gc> *);
|
|
static tree build_over_call (struct z_candidate *, int, tsubst_flags_t);
|
|
static tree convert_like (conversion *, tree, tsubst_flags_t);
|
|
static tree convert_like_with_context (conversion *, tree, tree, int,
|
|
tsubst_flags_t);
|
|
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 *);
|
|
static void print_z_candidates (location_t, struct z_candidate *);
|
|
static tree build_this (tree);
|
|
static struct z_candidate *splice_viable (struct z_candidate *, bool, bool *);
|
|
static bool any_strictly_viable (struct z_candidate *);
|
|
static struct z_candidate *add_template_candidate
|
|
(struct z_candidate **, tree, tree, tree, tree, const vec<tree, va_gc> *,
|
|
tree, tree, tree, int, unification_kind_t, bool, tsubst_flags_t);
|
|
static struct z_candidate *add_template_candidate_real
|
|
(struct z_candidate **, tree, tree, tree, tree, const vec<tree, va_gc> *,
|
|
tree, tree, tree, int, tree, unification_kind_t, bool, tsubst_flags_t);
|
|
static bool is_complete (tree);
|
|
static struct z_candidate *add_conv_candidate
|
|
(struct z_candidate **, tree, tree, const vec<tree, va_gc> *, tree,
|
|
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, conversion**, bool, tsubst_flags_t);
|
|
static conversion *implicit_conversion (tree, tree, tree, bool, int,
|
|
tsubst_flags_t);
|
|
static conversion *reference_binding (tree, tree, tree, bool, int,
|
|
tsubst_flags_t);
|
|
static conversion *build_conv (conversion_kind, tree, conversion *);
|
|
static conversion *build_list_conv (tree, tree, int, tsubst_flags_t);
|
|
static conversion *next_conversion (conversion *);
|
|
static bool is_subseq (conversion *, conversion *);
|
|
static conversion *maybe_handle_ref_bind (conversion **);
|
|
static void maybe_handle_implicit_object (conversion **);
|
|
static struct z_candidate *add_candidate
|
|
(struct z_candidate **, tree, tree, const vec<tree, va_gc> *, size_t,
|
|
conversion **, tree, tree, int, struct rejection_reason *, int);
|
|
static tree source_type (conversion *);
|
|
static void add_warning (struct z_candidate *, struct z_candidate *);
|
|
static conversion *direct_reference_binding (tree, conversion *);
|
|
static bool promoted_arithmetic_type_p (tree);
|
|
static conversion *conditional_conversion (tree, tree, tsubst_flags_t);
|
|
static char *name_as_c_string (tree, tree, bool *);
|
|
static tree prep_operand (tree);
|
|
static void add_candidates (tree, tree, const vec<tree, va_gc> *, tree, tree,
|
|
bool, tree, tree, int, struct z_candidate **,
|
|
tsubst_flags_t);
|
|
static conversion *merge_conversion_sequences (conversion *, conversion *);
|
|
static tree build_temp (tree, tree, int, diagnostic_t *, tsubst_flags_t);
|
|
static conversion *build_identity_conv (tree, tree);
|
|
static inline bool conv_binds_to_array_of_unknown_bound (conversion *);
|
|
static bool conv_is_prvalue (conversion *);
|
|
static tree prevent_lifetime_extension (tree);
|
|
|
|
/* Returns nonzero iff the destructor name specified in NAME matches BASETYPE.
|
|
NAME can take many forms... */
|
|
|
|
bool
|
|
check_dtor_name (tree basetype, tree name)
|
|
{
|
|
/* Just accept something we've already complained about. */
|
|
if (name == error_mark_node)
|
|
return true;
|
|
|
|
if (TREE_CODE (name) == TYPE_DECL)
|
|
name = TREE_TYPE (name);
|
|
else if (TYPE_P (name))
|
|
/* OK */;
|
|
else if (identifier_p (name))
|
|
{
|
|
if ((MAYBE_CLASS_TYPE_P (basetype)
|
|
|| TREE_CODE (basetype) == ENUMERAL_TYPE)
|
|
&& name == constructor_name (basetype))
|
|
return true;
|
|
|
|
/* Otherwise lookup the name, it could be an unrelated typedef
|
|
of the correct type. */
|
|
name = lookup_name (name, LOOK_want::TYPE);
|
|
if (!name)
|
|
return false;
|
|
name = TREE_TYPE (name);
|
|
if (name == error_mark_node)
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
/* In the case of:
|
|
|
|
template <class T> struct S { ~S(); };
|
|
int i;
|
|
i.~S();
|
|
|
|
NAME will be a class template. */
|
|
gcc_assert (DECL_CLASS_TEMPLATE_P (name));
|
|
return false;
|
|
}
|
|
|
|
return same_type_p (TYPE_MAIN_VARIANT (basetype), TYPE_MAIN_VARIANT (name));
|
|
}
|
|
|
|
/* We want the address of a function or method. We avoid creating a
|
|
pointer-to-member function. */
|
|
|
|
tree
|
|
build_addr_func (tree function, tsubst_flags_t complain)
|
|
{
|
|
tree type = TREE_TYPE (function);
|
|
|
|
/* We have to do these by hand to avoid real pointer to member
|
|
functions. */
|
|
if (TREE_CODE (type) == METHOD_TYPE)
|
|
{
|
|
if (TREE_CODE (function) == OFFSET_REF)
|
|
{
|
|
tree object = build_address (TREE_OPERAND (function, 0));
|
|
return get_member_function_from_ptrfunc (&object,
|
|
TREE_OPERAND (function, 1),
|
|
complain);
|
|
}
|
|
function = build_address (function);
|
|
}
|
|
else if (TREE_CODE (function) == FUNCTION_DECL
|
|
&& DECL_IMMEDIATE_FUNCTION_P (function))
|
|
function = build_address (function);
|
|
else
|
|
function = decay_conversion (function, complain, /*reject_builtin=*/false);
|
|
|
|
return function;
|
|
}
|
|
|
|
/* Build a CALL_EXPR, we can handle FUNCTION_TYPEs, METHOD_TYPEs, or
|
|
POINTER_TYPE to those. Note, pointer to member function types
|
|
(TYPE_PTRMEMFUNC_P) must be handled by our callers. There are
|
|
two variants. build_call_a is the primitive taking an array of
|
|
arguments, while build_call_n is a wrapper that handles varargs. */
|
|
|
|
tree
|
|
build_call_n (tree function, int n, ...)
|
|
{
|
|
if (n == 0)
|
|
return build_call_a (function, 0, NULL);
|
|
else
|
|
{
|
|
tree *argarray = XALLOCAVEC (tree, n);
|
|
va_list ap;
|
|
int i;
|
|
|
|
va_start (ap, n);
|
|
for (i = 0; i < n; i++)
|
|
argarray[i] = va_arg (ap, tree);
|
|
va_end (ap);
|
|
return build_call_a (function, n, argarray);
|
|
}
|
|
}
|
|
|
|
/* Update various flags in cfun and the call itself based on what is being
|
|
called. Split out of build_call_a so that bot_manip can use it too. */
|
|
|
|
void
|
|
set_flags_from_callee (tree 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(). */
|
|
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 (cfun && cp_function_chain && !cp_unevaluated_operand)
|
|
{
|
|
if (!nothrow && at_function_scope_p ())
|
|
cp_function_chain->can_throw = 1;
|
|
|
|
if (decl && TREE_THIS_VOLATILE (decl))
|
|
current_function_returns_abnormally = 1;
|
|
}
|
|
|
|
TREE_NOTHROW (call) = nothrow;
|
|
}
|
|
|
|
tree
|
|
build_call_a (tree function, int n, tree *argarray)
|
|
{
|
|
tree decl;
|
|
tree result_type;
|
|
tree fntype;
|
|
int i;
|
|
|
|
function = build_addr_func (function, tf_warning_or_error);
|
|
|
|
gcc_assert (TYPE_PTR_P (TREE_TYPE (function)));
|
|
fntype = TREE_TYPE (TREE_TYPE (function));
|
|
gcc_assert (FUNC_OR_METHOD_TYPE_P (fntype));
|
|
result_type = TREE_TYPE (fntype);
|
|
/* An rvalue has no cv-qualifiers. */
|
|
if (SCALAR_TYPE_P (result_type) || VOID_TYPE_P (result_type))
|
|
result_type = cv_unqualified (result_type);
|
|
|
|
function = build_call_array_loc (input_location,
|
|
result_type, function, n, argarray);
|
|
set_flags_from_callee (function);
|
|
|
|
decl = get_callee_fndecl (function);
|
|
|
|
if (decl && !TREE_USED (decl))
|
|
{
|
|
/* We invoke build_call directly for several library
|
|
functions. These may have been declared normally if
|
|
we're building libgcc, so we can't just check
|
|
DECL_ARTIFICIAL. */
|
|
gcc_assert (DECL_ARTIFICIAL (decl)
|
|
|| !strncmp (IDENTIFIER_POINTER (DECL_NAME (decl)),
|
|
"__", 2));
|
|
mark_used (decl);
|
|
}
|
|
|
|
require_complete_eh_spec_types (fntype, decl);
|
|
|
|
TREE_HAS_CONSTRUCTOR (function) = (decl && DECL_CONSTRUCTOR_P (decl));
|
|
|
|
/* 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 || !fndecl_built_in_p (decl))
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
tree arg = CALL_EXPR_ARG (function, i);
|
|
if (is_empty_class (TREE_TYPE (arg))
|
|
&& simple_empty_class_p (TREE_TYPE (arg), arg, INIT_EXPR))
|
|
{
|
|
while (TREE_CODE (arg) == TARGET_EXPR)
|
|
/* We're disconnecting the initializer from its target,
|
|
don't create a temporary. */
|
|
arg = TARGET_EXPR_INITIAL (arg);
|
|
tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (arg));
|
|
arg = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t);
|
|
CALL_EXPR_ARG (function, i) = arg;
|
|
}
|
|
}
|
|
|
|
return function;
|
|
}
|
|
|
|
/* New overloading code. */
|
|
|
|
struct z_candidate;
|
|
|
|
struct candidate_warning {
|
|
z_candidate *loser;
|
|
candidate_warning *next;
|
|
};
|
|
|
|
/* Information for providing diagnostics about why overloading failed. */
|
|
|
|
enum rejection_reason_code {
|
|
rr_none,
|
|
rr_arity,
|
|
rr_explicit_conversion,
|
|
rr_template_conversion,
|
|
rr_arg_conversion,
|
|
rr_bad_arg_conversion,
|
|
rr_template_unification,
|
|
rr_invalid_copy,
|
|
rr_inherited_ctor,
|
|
rr_constraint_failure
|
|
};
|
|
|
|
struct conversion_info {
|
|
/* The index of the argument, 0-based. */
|
|
int n_arg;
|
|
/* The actual argument or its type. */
|
|
tree from;
|
|
/* The type of the parameter. */
|
|
tree to_type;
|
|
/* The location of the argument. */
|
|
location_t loc;
|
|
};
|
|
|
|
struct rejection_reason {
|
|
enum rejection_reason_code code;
|
|
union {
|
|
/* Information about an arity mismatch. */
|
|
struct {
|
|
/* The expected number of arguments. */
|
|
int expected;
|
|
/* The actual number of arguments in the call. */
|
|
int actual;
|
|
/* Whether EXPECTED should be treated as a lower bound. */
|
|
bool least_p;
|
|
} arity;
|
|
/* Information about an argument conversion mismatch. */
|
|
struct conversion_info conversion;
|
|
/* Same, but for bad argument conversions. */
|
|
struct conversion_info bad_conversion;
|
|
/* Information about template unification failures. These are the
|
|
parameters passed to fn_type_unification. */
|
|
struct {
|
|
tree tmpl;
|
|
tree explicit_targs;
|
|
int num_targs;
|
|
const tree *args;
|
|
unsigned int nargs;
|
|
tree return_type;
|
|
unification_kind_t strict;
|
|
int flags;
|
|
} template_unification;
|
|
/* Information about template instantiation failures. These are the
|
|
parameters passed to instantiate_template. */
|
|
struct {
|
|
tree tmpl;
|
|
tree targs;
|
|
} template_instantiation;
|
|
} u;
|
|
};
|
|
|
|
struct z_candidate {
|
|
/* The FUNCTION_DECL that will be called if this candidate is
|
|
selected by overload resolution. */
|
|
tree fn;
|
|
/* If not NULL_TREE, the first argument to use when calling this
|
|
function. */
|
|
tree first_arg;
|
|
/* The rest of the arguments to use when calling this function. If
|
|
there are no further arguments this may be NULL or it may be an
|
|
empty vector. */
|
|
const vec<tree, va_gc> *args;
|
|
/* The implicit conversion sequences for each of the arguments to
|
|
FN. */
|
|
conversion **convs;
|
|
/* The number of implicit conversion sequences. */
|
|
size_t num_convs;
|
|
/* If FN is a user-defined conversion, the standard conversion
|
|
sequence from the type returned by FN to the desired destination
|
|
type. */
|
|
conversion *second_conv;
|
|
struct rejection_reason *reason;
|
|
/* If FN is a member function, the binfo indicating the path used to
|
|
qualify the name of FN at the call site. This path is used to
|
|
determine whether or not FN is accessible if it is selected by
|
|
overload resolution. The DECL_CONTEXT of FN will always be a
|
|
(possibly improper) base of this binfo. */
|
|
tree access_path;
|
|
/* If FN is a non-static member function, the binfo indicating the
|
|
subobject to which the `this' pointer should be converted if FN
|
|
is selected by overload resolution. The type pointed to by
|
|
the `this' pointer must correspond to the most derived class
|
|
indicated by the CONVERSION_PATH. */
|
|
tree conversion_path;
|
|
tree template_decl;
|
|
tree explicit_targs;
|
|
candidate_warning *warnings;
|
|
z_candidate *next;
|
|
int viable;
|
|
|
|
/* The flags active in add_candidate. */
|
|
int flags;
|
|
|
|
bool rewritten () const { return (flags & LOOKUP_REWRITTEN); }
|
|
bool reversed () const { return (flags & LOOKUP_REVERSED); }
|
|
};
|
|
|
|
/* Returns true iff T is a null pointer constant in the sense of
|
|
[conv.ptr]. */
|
|
|
|
bool
|
|
null_ptr_cst_p (tree t)
|
|
{
|
|
tree type = TREE_TYPE (t);
|
|
|
|
/* [conv.ptr]
|
|
|
|
A null pointer constant is an integer literal ([lex.icon]) with value
|
|
zero or a prvalue of type std::nullptr_t. */
|
|
if (NULLPTR_TYPE_P (type))
|
|
return true;
|
|
|
|
if (cxx_dialect >= cxx11)
|
|
{
|
|
STRIP_ANY_LOCATION_WRAPPER (t);
|
|
|
|
/* Core issue 903 says only literal 0 is a null pointer constant. */
|
|
if (TREE_CODE (t) == INTEGER_CST
|
|
&& !TREE_OVERFLOW (t)
|
|
&& TREE_CODE (type) == INTEGER_TYPE
|
|
&& integer_zerop (t)
|
|
&& !char_type_p (type))
|
|
return true;
|
|
}
|
|
else if (CP_INTEGRAL_TYPE_P (type))
|
|
{
|
|
t = fold_non_dependent_expr (t, tf_none);
|
|
STRIP_NOPS (t);
|
|
if (integer_zerop (t) && !TREE_OVERFLOW (t))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* Returns true iff T is a null member pointer value (4.11). */
|
|
|
|
bool
|
|
null_member_pointer_value_p (tree t)
|
|
{
|
|
tree type = TREE_TYPE (t);
|
|
if (!type)
|
|
return false;
|
|
else if (TYPE_PTRMEMFUNC_P (type))
|
|
return (TREE_CODE (t) == CONSTRUCTOR
|
|
&& CONSTRUCTOR_NELTS (t)
|
|
&& integer_zerop (CONSTRUCTOR_ELT (t, 0)->value));
|
|
else if (TYPE_PTRDATAMEM_P (type))
|
|
return integer_all_onesp (t);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/* Returns nonzero if PARMLIST consists of only default parms,
|
|
ellipsis, and/or undeduced parameter packs. */
|
|
|
|
bool
|
|
sufficient_parms_p (const_tree parmlist)
|
|
{
|
|
for (; parmlist && parmlist != void_list_node;
|
|
parmlist = TREE_CHAIN (parmlist))
|
|
if (!TREE_PURPOSE (parmlist)
|
|
&& !PACK_EXPANSION_P (TREE_VALUE (parmlist)))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/* Allocate N bytes of memory from the conversion obstack. The memory
|
|
is zeroed before being returned. */
|
|
|
|
static void *
|
|
conversion_obstack_alloc (size_t n)
|
|
{
|
|
void *p;
|
|
if (!conversion_obstack_initialized)
|
|
{
|
|
gcc_obstack_init (&conversion_obstack);
|
|
conversion_obstack_initialized = true;
|
|
}
|
|
p = obstack_alloc (&conversion_obstack, n);
|
|
memset (p, 0, n);
|
|
return p;
|
|
}
|
|
|
|
/* Allocate rejection reasons. */
|
|
|
|
static struct rejection_reason *
|
|
alloc_rejection (enum rejection_reason_code code)
|
|
{
|
|
struct rejection_reason *p;
|
|
p = (struct rejection_reason *) conversion_obstack_alloc (sizeof *p);
|
|
p->code = code;
|
|
return p;
|
|
}
|
|
|
|
static struct rejection_reason *
|
|
arity_rejection (tree first_arg, int expected, int actual, bool least_p = false)
|
|
{
|
|
struct rejection_reason *r = alloc_rejection (rr_arity);
|
|
int adjust = first_arg != NULL_TREE;
|
|
r->u.arity.expected = expected - adjust;
|
|
r->u.arity.actual = actual - adjust;
|
|
r->u.arity.least_p = least_p;
|
|
return r;
|
|
}
|
|
|
|
static struct rejection_reason *
|
|
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,
|
|
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;
|
|
}
|
|
|
|
static struct rejection_reason *
|
|
explicit_conversion_rejection (tree from, tree to)
|
|
{
|
|
struct rejection_reason *r = alloc_rejection (rr_explicit_conversion);
|
|
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;
|
|
}
|
|
|
|
static struct rejection_reason *
|
|
template_conversion_rejection (tree from, tree to)
|
|
{
|
|
struct rejection_reason *r = alloc_rejection (rr_template_conversion);
|
|
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;
|
|
}
|
|
|
|
static struct rejection_reason *
|
|
template_unification_rejection (tree tmpl, tree explicit_targs, tree targs,
|
|
const tree *args, unsigned int nargs,
|
|
tree return_type, unification_kind_t strict,
|
|
int flags)
|
|
{
|
|
size_t args_n_bytes = sizeof (*args) * nargs;
|
|
tree *args1 = (tree *) conversion_obstack_alloc (args_n_bytes);
|
|
struct rejection_reason *r = alloc_rejection (rr_template_unification);
|
|
r->u.template_unification.tmpl = tmpl;
|
|
r->u.template_unification.explicit_targs = explicit_targs;
|
|
r->u.template_unification.num_targs = TREE_VEC_LENGTH (targs);
|
|
/* Copy args to our own storage. */
|
|
memcpy (args1, args, args_n_bytes);
|
|
r->u.template_unification.args = args1;
|
|
r->u.template_unification.nargs = nargs;
|
|
r->u.template_unification.return_type = return_type;
|
|
r->u.template_unification.strict = strict;
|
|
r->u.template_unification.flags = flags;
|
|
return r;
|
|
}
|
|
|
|
static struct rejection_reason *
|
|
template_unification_error_rejection (void)
|
|
{
|
|
return alloc_rejection (rr_template_unification);
|
|
}
|
|
|
|
static struct rejection_reason *
|
|
invalid_copy_with_fn_template_rejection (void)
|
|
{
|
|
struct rejection_reason *r = alloc_rejection (rr_invalid_copy);
|
|
return r;
|
|
}
|
|
|
|
static struct rejection_reason *
|
|
inherited_ctor_rejection (void)
|
|
{
|
|
struct rejection_reason *r = alloc_rejection (rr_inherited_ctor);
|
|
return r;
|
|
}
|
|
|
|
/* Build a constraint failure record. */
|
|
|
|
static struct rejection_reason *
|
|
constraint_failure (void)
|
|
{
|
|
struct rejection_reason *r = alloc_rejection (rr_constraint_failure);
|
|
return r;
|
|
}
|
|
|
|
/* Dynamically allocate a conversion. */
|
|
|
|
static conversion *
|
|
alloc_conversion (conversion_kind kind)
|
|
{
|
|
conversion *c;
|
|
c = (conversion *) conversion_obstack_alloc (sizeof (conversion));
|
|
c->kind = kind;
|
|
return c;
|
|
}
|
|
|
|
/* Make sure that all memory on the conversion obstack has been
|
|
freed. */
|
|
|
|
void
|
|
validate_conversion_obstack (void)
|
|
{
|
|
if (conversion_obstack_initialized)
|
|
gcc_assert ((obstack_next_free (&conversion_obstack)
|
|
== obstack_base (&conversion_obstack)));
|
|
}
|
|
|
|
/* Dynamically allocate an array of N conversions. */
|
|
|
|
static conversion **
|
|
alloc_conversions (size_t n)
|
|
{
|
|
return (conversion **) conversion_obstack_alloc (n * sizeof (conversion *));
|
|
}
|
|
|
|
/* True iff the active member of conversion::u for code CODE is NEXT. */
|
|
|
|
static inline bool
|
|
has_next (conversion_kind code)
|
|
{
|
|
return !(code == ck_identity
|
|
|| code == ck_ambig
|
|
|| code == ck_list
|
|
|| code == ck_aggr);
|
|
}
|
|
|
|
static conversion *
|
|
build_conv (conversion_kind code, tree type, conversion *from)
|
|
{
|
|
conversion *t;
|
|
conversion_rank rank = CONVERSION_RANK (from);
|
|
|
|
/* Only call this function for conversions that use u.next. */
|
|
gcc_assert (from == NULL || has_next (code));
|
|
|
|
/* Note that the caller is responsible for filling in t->cand for
|
|
user-defined conversions. */
|
|
t = alloc_conversion (code);
|
|
t->type = type;
|
|
t->u.next = from;
|
|
|
|
switch (code)
|
|
{
|
|
case ck_ptr:
|
|
case ck_pmem:
|
|
case ck_base:
|
|
case ck_std:
|
|
if (rank < cr_std)
|
|
rank = cr_std;
|
|
break;
|
|
|
|
case ck_qual:
|
|
case ck_fnptr:
|
|
if (rank < cr_exact)
|
|
rank = cr_exact;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
t->rank = rank;
|
|
t->user_conv_p = (code == ck_user || from->user_conv_p);
|
|
t->bad_p = from->bad_p;
|
|
t->base_p = false;
|
|
return t;
|
|
}
|
|
|
|
/* Represent a conversion from CTOR, a braced-init-list, to TYPE, a
|
|
specialization of std::initializer_list<T>, if such a conversion is
|
|
possible. */
|
|
|
|
static conversion *
|
|
build_list_conv (tree type, tree ctor, int flags, tsubst_flags_t complain)
|
|
{
|
|
tree elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (type), 0);
|
|
unsigned len = CONSTRUCTOR_NELTS (ctor);
|
|
conversion **subconvs = alloc_conversions (len);
|
|
conversion *t;
|
|
unsigned i;
|
|
tree val;
|
|
|
|
/* Within a list-initialization we can have more user-defined
|
|
conversions. */
|
|
flags &= ~LOOKUP_NO_CONVERSION;
|
|
/* But no narrowing conversions. */
|
|
flags |= LOOKUP_NO_NARROWING;
|
|
|
|
/* Can't make an array of these types. */
|
|
if (TYPE_REF_P (elttype)
|
|
|| TREE_CODE (elttype) == FUNCTION_TYPE
|
|
|| VOID_TYPE_P (elttype))
|
|
return NULL;
|
|
|
|
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (ctor), i, val)
|
|
{
|
|
conversion *sub
|
|
= implicit_conversion (elttype, TREE_TYPE (val), val,
|
|
false, flags, complain);
|
|
if (sub == NULL)
|
|
return NULL;
|
|
|
|
subconvs[i] = sub;
|
|
}
|
|
|
|
t = alloc_conversion (ck_list);
|
|
t->type = type;
|
|
t->u.list = subconvs;
|
|
t->rank = cr_exact;
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
conversion *sub = subconvs[i];
|
|
if (sub->rank > t->rank)
|
|
t->rank = sub->rank;
|
|
if (sub->user_conv_p)
|
|
t->user_conv_p = true;
|
|
if (sub->bad_p)
|
|
t->bad_p = true;
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
/* Return the next conversion of the conversion chain (if applicable),
|
|
or NULL otherwise. Please use this function instead of directly
|
|
accessing fields of struct conversion. */
|
|
|
|
static conversion *
|
|
next_conversion (conversion *conv)
|
|
{
|
|
if (conv == NULL
|
|
|| !has_next (conv->kind))
|
|
return NULL;
|
|
return conv->u.next;
|
|
}
|
|
|
|
/* Strip to the first ck_user, ck_ambig, ck_list, ck_aggr or ck_identity
|
|
encountered. */
|
|
|
|
static conversion *
|
|
strip_standard_conversion (conversion *conv)
|
|
{
|
|
while (conv
|
|
&& conv->kind != ck_user
|
|
&& has_next (conv->kind))
|
|
conv = next_conversion (conv);
|
|
return conv;
|
|
}
|
|
|
|
/* Subroutine of build_aggr_conv: check whether FROM is a valid aggregate
|
|
initializer for array type ATYPE. */
|
|
|
|
static bool
|
|
can_convert_array (tree atype, tree from, int flags, tsubst_flags_t complain)
|
|
{
|
|
tree elttype = TREE_TYPE (atype);
|
|
unsigned i;
|
|
|
|
if (TREE_CODE (from) == CONSTRUCTOR)
|
|
{
|
|
for (i = 0; i < CONSTRUCTOR_NELTS (from); ++i)
|
|
{
|
|
tree val = CONSTRUCTOR_ELT (from, i)->value;
|
|
bool ok;
|
|
if (TREE_CODE (elttype) == ARRAY_TYPE)
|
|
ok = can_convert_array (elttype, val, flags, complain);
|
|
else
|
|
ok = can_convert_arg (elttype, TREE_TYPE (val), val, flags,
|
|
complain);
|
|
if (!ok)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (char_type_p (TYPE_MAIN_VARIANT (elttype))
|
|
&& TREE_CODE (tree_strip_any_location_wrapper (from)) == STRING_CST)
|
|
return array_string_literal_compatible_p (atype, from);
|
|
|
|
/* No other valid way to aggregate initialize an array. */
|
|
return false;
|
|
}
|
|
|
|
/* 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, true> &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. */
|
|
|
|
static conversion *
|
|
build_aggr_conv (tree type, tree ctor, int flags, tsubst_flags_t complain)
|
|
{
|
|
unsigned HOST_WIDE_INT i = 0;
|
|
conversion *c;
|
|
tree field = next_initializable_field (TYPE_FIELDS (type));
|
|
tree empty_ctor = NULL_TREE;
|
|
hash_set<tree, true> pset;
|
|
|
|
/* We already called reshape_init in implicit_conversion. */
|
|
|
|
/* The conversions within the init-list aren't affected by the enclosing
|
|
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)
|
|
ok = can_convert_array (ftype, val, flags, complain);
|
|
else
|
|
ok = can_convert_arg (ftype, TREE_TYPE (val), val, flags,
|
|
complain);
|
|
|
|
if (!ok)
|
|
return NULL;
|
|
/* For unions, there should be just one initializer. */
|
|
if (TREE_CODE (type) == UNION_TYPE)
|
|
{
|
|
field = NULL_TREE;
|
|
i = 1;
|
|
break;
|
|
}
|
|
pset.add (idx);
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
for (; field; field = next_initializable_field (DECL_CHAIN (field)))
|
|
{
|
|
tree ftype = TREE_TYPE (field);
|
|
tree val;
|
|
bool ok;
|
|
|
|
if (!pset.is_empty () && field_in_pset (pset, field))
|
|
continue;
|
|
if (i < CONSTRUCTOR_NELTS (ctor))
|
|
{
|
|
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;
|
|
else
|
|
{
|
|
if (empty_ctor == NULL_TREE)
|
|
empty_ctor = build_constructor (init_list_type_node, NULL);
|
|
val = empty_ctor;
|
|
}
|
|
|
|
if (TREE_CODE (ftype) == ARRAY_TYPE)
|
|
ok = can_convert_array (ftype, val, flags, complain);
|
|
else
|
|
ok = can_convert_arg (ftype, TREE_TYPE (val), val, flags,
|
|
complain);
|
|
|
|
if (!ok)
|
|
return NULL;
|
|
|
|
if (TREE_CODE (type) == UNION_TYPE)
|
|
break;
|
|
}
|
|
|
|
if (i < CONSTRUCTOR_NELTS (ctor))
|
|
return NULL;
|
|
|
|
c = alloc_conversion (ck_aggr);
|
|
c->type = type;
|
|
c->rank = cr_exact;
|
|
c->user_conv_p = true;
|
|
c->check_narrowing = true;
|
|
c->u.expr = ctor;
|
|
return c;
|
|
}
|
|
|
|
/* Represent a conversion from CTOR, a braced-init-list, to TYPE, an
|
|
array type, if such a conversion is possible. */
|
|
|
|
static conversion *
|
|
build_array_conv (tree type, tree ctor, int flags, tsubst_flags_t complain)
|
|
{
|
|
conversion *c;
|
|
unsigned HOST_WIDE_INT len = CONSTRUCTOR_NELTS (ctor);
|
|
tree elttype = TREE_TYPE (type);
|
|
bool bad = false;
|
|
bool user = false;
|
|
enum conversion_rank rank = cr_exact;
|
|
|
|
/* We might need to propagate the size from the element to the array. */
|
|
complete_type (type);
|
|
|
|
if (TYPE_DOMAIN (type)
|
|
&& !variably_modified_type_p (TYPE_DOMAIN (type), NULL_TREE))
|
|
{
|
|
unsigned HOST_WIDE_INT alen = tree_to_uhwi (array_type_nelts_top (type));
|
|
if (alen < len)
|
|
return NULL;
|
|
}
|
|
|
|
flags = LOOKUP_IMPLICIT|LOOKUP_NO_NARROWING;
|
|
|
|
for (auto &e: CONSTRUCTOR_ELTS (ctor))
|
|
{
|
|
conversion *sub
|
|
= implicit_conversion (elttype, TREE_TYPE (e.value), e.value,
|
|
false, flags, complain);
|
|
if (sub == NULL)
|
|
return NULL;
|
|
|
|
if (sub->rank > rank)
|
|
rank = sub->rank;
|
|
if (sub->user_conv_p)
|
|
user = true;
|
|
if (sub->bad_p)
|
|
bad = true;
|
|
}
|
|
|
|
c = alloc_conversion (ck_aggr);
|
|
c->type = type;
|
|
c->rank = rank;
|
|
c->user_conv_p = user;
|
|
c->bad_p = bad;
|
|
c->u.expr = ctor;
|
|
return c;
|
|
}
|
|
|
|
/* Represent a conversion from CTOR, a braced-init-list, to TYPE, a
|
|
complex type, if such a conversion is possible. */
|
|
|
|
static conversion *
|
|
build_complex_conv (tree type, tree ctor, int flags,
|
|
tsubst_flags_t complain)
|
|
{
|
|
conversion *c;
|
|
unsigned HOST_WIDE_INT len = CONSTRUCTOR_NELTS (ctor);
|
|
tree elttype = TREE_TYPE (type);
|
|
bool bad = false;
|
|
bool user = false;
|
|
enum conversion_rank rank = cr_exact;
|
|
|
|
if (len != 2)
|
|
return NULL;
|
|
|
|
flags = LOOKUP_IMPLICIT|LOOKUP_NO_NARROWING;
|
|
|
|
for (auto &e: CONSTRUCTOR_ELTS (ctor))
|
|
{
|
|
conversion *sub
|
|
= implicit_conversion (elttype, TREE_TYPE (e.value), e.value,
|
|
false, flags, complain);
|
|
if (sub == NULL)
|
|
return NULL;
|
|
|
|
if (sub->rank > rank)
|
|
rank = sub->rank;
|
|
if (sub->user_conv_p)
|
|
user = true;
|
|
if (sub->bad_p)
|
|
bad = true;
|
|
}
|
|
|
|
c = alloc_conversion (ck_aggr);
|
|
c->type = type;
|
|
c->rank = rank;
|
|
c->user_conv_p = user;
|
|
c->bad_p = bad;
|
|
c->u.expr = ctor;
|
|
return c;
|
|
}
|
|
|
|
/* Build a representation of the identity conversion from EXPR to
|
|
itself. The TYPE should match the type of EXPR, if EXPR is non-NULL. */
|
|
|
|
static conversion *
|
|
build_identity_conv (tree type, tree expr)
|
|
{
|
|
conversion *c;
|
|
|
|
c = alloc_conversion (ck_identity);
|
|
c->type = type;
|
|
c->u.expr = expr;
|
|
|
|
return c;
|
|
}
|
|
|
|
/* Converting from EXPR to TYPE was ambiguous in the sense that there
|
|
were multiple user-defined conversions to accomplish the job.
|
|
Build a conversion that indicates that ambiguity. */
|
|
|
|
static conversion *
|
|
build_ambiguous_conv (tree type, tree expr)
|
|
{
|
|
conversion *c;
|
|
|
|
c = alloc_conversion (ck_ambig);
|
|
c->type = type;
|
|
c->u.expr = expr;
|
|
|
|
return c;
|
|
}
|
|
|
|
tree
|
|
strip_top_quals (tree t)
|
|
{
|
|
if (TREE_CODE (t) == ARRAY_TYPE)
|
|
return t;
|
|
return cp_build_qualified_type (t, 0);
|
|
}
|
|
|
|
/* Returns the standard conversion path (see [conv]) from type FROM to type
|
|
TO, if any. For proper handling of null pointer constants, you must
|
|
also pass the expression EXPR to convert from. If C_CAST_P is true,
|
|
this conversion is coming from a C-style cast. */
|
|
|
|
static conversion *
|
|
standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
|
|
int flags, tsubst_flags_t complain)
|
|
{
|
|
enum tree_code fcode, tcode;
|
|
conversion *conv;
|
|
bool fromref = false;
|
|
tree qualified_to;
|
|
|
|
to = non_reference (to);
|
|
if (TYPE_REF_P (from))
|
|
{
|
|
fromref = true;
|
|
from = TREE_TYPE (from);
|
|
}
|
|
qualified_to = to;
|
|
to = strip_top_quals (to);
|
|
from = strip_top_quals (from);
|
|
|
|
if (expr && type_unknown_p (expr))
|
|
{
|
|
if (TYPE_PTRFN_P (to) || TYPE_PTRMEMFUNC_P (to))
|
|
{
|
|
tsubst_flags_t tflags = tf_conv;
|
|
expr = instantiate_type (to, expr, tflags);
|
|
if (expr == error_mark_node)
|
|
return NULL;
|
|
from = TREE_TYPE (expr);
|
|
}
|
|
else if (TREE_CODE (to) == BOOLEAN_TYPE)
|
|
{
|
|
/* Necessary for eg, TEMPLATE_ID_EXPRs (c++/50961). */
|
|
expr = resolve_nondeduced_context (expr, complain);
|
|
from = TREE_TYPE (expr);
|
|
}
|
|
}
|
|
|
|
fcode = TREE_CODE (from);
|
|
tcode = TREE_CODE (to);
|
|
|
|
conv = build_identity_conv (from, expr);
|
|
if (fcode == FUNCTION_TYPE || fcode == ARRAY_TYPE)
|
|
{
|
|
from = type_decays_to (from);
|
|
fcode = TREE_CODE (from);
|
|
/* Tell convert_like that we're using the address. */
|
|
conv->rvaluedness_matches_p = true;
|
|
conv = build_conv (ck_lvalue, from, conv);
|
|
}
|
|
/* Wrapping a ck_rvalue around a class prvalue (as a result of using
|
|
obvalue_p) seems odd, since it's already a prvalue, but that's how we
|
|
express the copy constructor call required by copy-initialization. */
|
|
else if (fromref || (expr && obvalue_p (expr)))
|
|
{
|
|
if (expr)
|
|
{
|
|
tree bitfield_type;
|
|
bitfield_type = is_bitfield_expr_with_lowered_type (expr);
|
|
if (bitfield_type)
|
|
{
|
|
from = strip_top_quals (bitfield_type);
|
|
fcode = TREE_CODE (from);
|
|
}
|
|
}
|
|
conv = build_conv (ck_rvalue, from, conv);
|
|
if (flags & LOOKUP_PREFER_RVALUE)
|
|
/* Tell convert_like to set LOOKUP_PREFER_RVALUE. */
|
|
conv->rvaluedness_matches_p = true;
|
|
/* If we're performing copy-initialization, remember to skip
|
|
explicit constructors. */
|
|
if (flags & LOOKUP_ONLYCONVERTING)
|
|
conv->copy_init_p = true;
|
|
}
|
|
|
|
/* Allow conversion between `__complex__' data types. */
|
|
if (tcode == COMPLEX_TYPE && fcode == COMPLEX_TYPE)
|
|
{
|
|
/* The standard conversion sequence to convert FROM to TO is
|
|
the standard conversion sequence to perform componentwise
|
|
conversion. */
|
|
conversion *part_conv = standard_conversion
|
|
(TREE_TYPE (to), TREE_TYPE (from), NULL_TREE, c_cast_p, flags,
|
|
complain);
|
|
|
|
if (!part_conv)
|
|
conv = NULL;
|
|
else if (part_conv->kind == ck_identity)
|
|
/* Leave conv alone. */;
|
|
else
|
|
{
|
|
conv = build_conv (part_conv->kind, to, conv);
|
|
conv->rank = part_conv->rank;
|
|
}
|
|
|
|
return conv;
|
|
}
|
|
|
|
if (same_type_p (from, to))
|
|
{
|
|
if (CLASS_TYPE_P (to) && conv->kind == ck_rvalue)
|
|
conv->type = qualified_to;
|
|
return conv;
|
|
}
|
|
|
|
/* [conv.ptr]
|
|
A null pointer constant can be converted to a pointer type; ... A
|
|
null pointer constant of integral type can be converted to an
|
|
rvalue of type std::nullptr_t. */
|
|
if ((tcode == POINTER_TYPE || TYPE_PTRMEM_P (to)
|
|
|| NULLPTR_TYPE_P (to))
|
|
&& ((expr && null_ptr_cst_p (expr))
|
|
|| NULLPTR_TYPE_P (from)))
|
|
conv = build_conv (ck_std, to, conv);
|
|
else if ((tcode == INTEGER_TYPE && fcode == POINTER_TYPE)
|
|
|| (tcode == POINTER_TYPE && fcode == INTEGER_TYPE))
|
|
{
|
|
/* For backwards brain damage compatibility, allow interconversion of
|
|
pointers and integers with a pedwarn. */
|
|
conv = build_conv (ck_std, to, conv);
|
|
conv->bad_p = true;
|
|
}
|
|
else if (UNSCOPED_ENUM_P (to) && fcode == INTEGER_TYPE)
|
|
{
|
|
/* For backwards brain damage compatibility, allow interconversion of
|
|
enums and integers with a pedwarn. */
|
|
conv = build_conv (ck_std, to, conv);
|
|
conv->bad_p = true;
|
|
}
|
|
else if ((tcode == POINTER_TYPE && fcode == POINTER_TYPE)
|
|
|| (TYPE_PTRDATAMEM_P (to) && TYPE_PTRDATAMEM_P (from)))
|
|
{
|
|
tree to_pointee;
|
|
tree from_pointee;
|
|
|
|
if (tcode == POINTER_TYPE)
|
|
{
|
|
to_pointee = TREE_TYPE (to);
|
|
from_pointee = TREE_TYPE (from);
|
|
|
|
/* Since this is the target of a pointer, it can't have function
|
|
qualifiers, so any TYPE_QUALS must be for attributes const or
|
|
noreturn. Strip them. */
|
|
if (TREE_CODE (to_pointee) == FUNCTION_TYPE
|
|
&& TYPE_QUALS (to_pointee))
|
|
to_pointee = build_qualified_type (to_pointee, TYPE_UNQUALIFIED);
|
|
if (TREE_CODE (from_pointee) == FUNCTION_TYPE
|
|
&& TYPE_QUALS (from_pointee))
|
|
from_pointee = build_qualified_type (from_pointee, TYPE_UNQUALIFIED);
|
|
}
|
|
else
|
|
{
|
|
to_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (to);
|
|
from_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (from);
|
|
}
|
|
|
|
if (tcode == POINTER_TYPE
|
|
&& same_type_ignoring_top_level_qualifiers_p (from_pointee,
|
|
to_pointee))
|
|
;
|
|
else if (VOID_TYPE_P (to_pointee)
|
|
&& !TYPE_PTRDATAMEM_P (from)
|
|
&& TREE_CODE (from_pointee) != FUNCTION_TYPE)
|
|
{
|
|
tree nfrom = TREE_TYPE (from);
|
|
/* Don't try to apply restrict to void. */
|
|
int quals = cp_type_quals (nfrom) & ~TYPE_QUAL_RESTRICT;
|
|
from_pointee = cp_build_qualified_type (void_type_node, quals);
|
|
from = build_pointer_type (from_pointee);
|
|
conv = build_conv (ck_ptr, from, conv);
|
|
}
|
|
else if (TYPE_PTRDATAMEM_P (from))
|
|
{
|
|
tree fbase = TYPE_PTRMEM_CLASS_TYPE (from);
|
|
tree tbase = TYPE_PTRMEM_CLASS_TYPE (to);
|
|
|
|
if (same_type_p (fbase, tbase))
|
|
/* No base conversion needed. */;
|
|
else if (DERIVED_FROM_P (fbase, tbase)
|
|
&& (same_type_ignoring_top_level_qualifiers_p
|
|
(from_pointee, to_pointee)))
|
|
{
|
|
from = build_ptrmem_type (tbase, from_pointee);
|
|
conv = build_conv (ck_pmem, from, conv);
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
else if (CLASS_TYPE_P (from_pointee)
|
|
&& CLASS_TYPE_P (to_pointee)
|
|
/* [conv.ptr]
|
|
|
|
An rvalue of type "pointer to cv D," where D is a
|
|
class type, can be converted to an rvalue of type
|
|
"pointer to cv B," where B is a base class (clause
|
|
_class.derived_) of D. If B is an inaccessible
|
|
(clause _class.access_) or ambiguous
|
|
(_class.member.lookup_) base class of D, a program
|
|
that necessitates this conversion is ill-formed.
|
|
Therefore, we use DERIVED_FROM_P, and do not check
|
|
access or uniqueness. */
|
|
&& DERIVED_FROM_P (to_pointee, from_pointee))
|
|
{
|
|
from_pointee
|
|
= cp_build_qualified_type (to_pointee,
|
|
cp_type_quals (from_pointee));
|
|
from = build_pointer_type (from_pointee);
|
|
conv = build_conv (ck_ptr, from, conv);
|
|
conv->base_p = true;
|
|
}
|
|
|
|
if (same_type_p (from, to))
|
|
/* OK */;
|
|
else if (c_cast_p && comp_ptr_ttypes_const (to, from, bounds_either))
|
|
/* In a C-style cast, we ignore CV-qualification because we
|
|
are allowed to perform a static_cast followed by a
|
|
const_cast. */
|
|
conv = build_conv (ck_qual, to, conv);
|
|
else if (!c_cast_p && comp_ptr_ttypes (to_pointee, from_pointee))
|
|
conv = build_conv (ck_qual, to, conv);
|
|
else if (expr && string_conv_p (to, expr, 0))
|
|
/* converting from string constant to char *. */
|
|
conv = build_conv (ck_qual, to, conv);
|
|
else if (fnptr_conv_p (to, from))
|
|
conv = build_conv (ck_fnptr, to, conv);
|
|
/* Allow conversions among compatible ObjC pointer types (base
|
|
conversions have been already handled above). */
|
|
else if (c_dialect_objc ()
|
|
&& objc_compare_types (to, from, -4, NULL_TREE))
|
|
conv = build_conv (ck_ptr, to, conv);
|
|
else if (ptr_reasonably_similar (to_pointee, from_pointee))
|
|
{
|
|
conv = build_conv (ck_ptr, to, conv);
|
|
conv->bad_p = true;
|
|
}
|
|
else
|
|
return NULL;
|
|
|
|
from = to;
|
|
}
|
|
else if (TYPE_PTRMEMFUNC_P (to) && TYPE_PTRMEMFUNC_P (from))
|
|
{
|
|
tree fromfn = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (from));
|
|
tree tofn = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (to));
|
|
tree fbase = class_of_this_parm (fromfn);
|
|
tree tbase = class_of_this_parm (tofn);
|
|
|
|
/* If FBASE and TBASE are equivalent but incomplete, DERIVED_FROM_P
|
|
yields false. But a pointer to member of incomplete class is OK. */
|
|
if (!same_type_p (fbase, tbase) && !DERIVED_FROM_P (fbase, tbase))
|
|
return NULL;
|
|
|
|
tree fstat = static_fn_type (fromfn);
|
|
tree tstat = static_fn_type (tofn);
|
|
if (same_type_p (tstat, fstat)
|
|
|| fnptr_conv_p (tstat, fstat))
|
|
/* OK */;
|
|
else
|
|
return NULL;
|
|
|
|
if (!same_type_p (fbase, tbase))
|
|
{
|
|
from = build_memfn_type (fstat,
|
|
tbase,
|
|
cp_type_quals (tbase),
|
|
type_memfn_rqual (tofn));
|
|
from = build_ptrmemfunc_type (build_pointer_type (from));
|
|
conv = build_conv (ck_pmem, from, conv);
|
|
conv->base_p = true;
|
|
}
|
|
if (fnptr_conv_p (tstat, fstat))
|
|
conv = build_conv (ck_fnptr, to, conv);
|
|
}
|
|
else if (tcode == BOOLEAN_TYPE)
|
|
{
|
|
/* [conv.bool]
|
|
|
|
A prvalue of arithmetic, unscoped enumeration, pointer, or pointer
|
|
to member type can be converted to a prvalue of type bool. ...
|
|
For direct-initialization (8.5 [dcl.init]), a prvalue of type
|
|
std::nullptr_t can be converted to a prvalue of type bool; */
|
|
if (ARITHMETIC_TYPE_P (from)
|
|
|| UNSCOPED_ENUM_P (from)
|
|
|| fcode == POINTER_TYPE
|
|
|| TYPE_PTRMEM_P (from)
|
|
|| NULLPTR_TYPE_P (from))
|
|
{
|
|
conv = build_conv (ck_std, to, conv);
|
|
if (fcode == POINTER_TYPE
|
|
|| TYPE_PTRDATAMEM_P (from)
|
|
|| (TYPE_PTRMEMFUNC_P (from)
|
|
&& conv->rank < cr_pbool)
|
|
|| NULLPTR_TYPE_P (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;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
/* We don't check for ENUMERAL_TYPE here because there are no standard
|
|
conversions to enum type. */
|
|
/* As an extension, allow conversion to complex type. */
|
|
else if (ARITHMETIC_TYPE_P (to))
|
|
{
|
|
if (! (INTEGRAL_CODE_P (fcode)
|
|
|| (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);
|
|
|
|
tree underlying_type = NULL_TREE;
|
|
if (TREE_CODE (from) == ENUMERAL_TYPE
|
|
&& ENUM_FIXED_UNDERLYING_TYPE_P (from))
|
|
underlying_type = ENUM_UNDERLYING_TYPE (from);
|
|
|
|
/* Give this a better rank if it's a promotion.
|
|
|
|
To handle CWG 1601, also bump the rank if we are converting
|
|
an enumeration with a fixed underlying type to the underlying
|
|
type. */
|
|
if ((same_type_p (to, type_promotes_to (from))
|
|
|| (underlying_type && same_type_p (to, underlying_type)))
|
|
&& next_conversion (conv)->rank <= cr_promotion)
|
|
conv->rank = cr_promotion;
|
|
}
|
|
else if (fcode == VECTOR_TYPE && tcode == VECTOR_TYPE
|
|
&& vector_types_convertible_p (from, to, false))
|
|
return build_conv (ck_std, to, conv);
|
|
else if (MAYBE_CLASS_TYPE_P (to) && MAYBE_CLASS_TYPE_P (from)
|
|
&& is_properly_derived_from (from, to))
|
|
{
|
|
if (conv->kind == ck_rvalue)
|
|
conv = next_conversion (conv);
|
|
conv = build_conv (ck_base, to, conv);
|
|
/* The derived-to-base conversion indicates the initialization
|
|
of a parameter with base type from an object of a derived
|
|
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 to set LOOKUP_PREFER_RVALUE. */
|
|
conv->rvaluedness_matches_p = true;
|
|
/* If we're performing copy-initialization, remember to skip
|
|
explicit constructors. */
|
|
if (flags & LOOKUP_ONLYCONVERTING)
|
|
conv->copy_init_p = true;
|
|
}
|
|
else
|
|
return NULL;
|
|
|
|
if (flags & LOOKUP_NO_NARROWING)
|
|
conv->check_narrowing = true;
|
|
|
|
return conv;
|
|
}
|
|
|
|
/* Returns nonzero if T1 is reference-related to T2. */
|
|
|
|
bool
|
|
reference_related_p (tree t1, tree t2)
|
|
{
|
|
if (t1 == error_mark_node || t2 == error_mark_node)
|
|
return false;
|
|
|
|
t1 = TYPE_MAIN_VARIANT (t1);
|
|
t2 = TYPE_MAIN_VARIANT (t2);
|
|
|
|
/* [dcl.init.ref]
|
|
|
|
Given types "cv1 T1" and "cv2 T2," "cv1 T1" is reference-related
|
|
to "cv2 T2" if T1 is similar to T2, or T1 is a base class of T2. */
|
|
return (similar_type_p (t1, t2)
|
|
|| (CLASS_TYPE_P (t1) && CLASS_TYPE_P (t2)
|
|
&& DERIVED_FROM_P (t1, t2)));
|
|
}
|
|
|
|
/* Returns nonzero if T1 is reference-compatible with T2. */
|
|
|
|
bool
|
|
reference_compatible_p (tree t1, tree t2)
|
|
{
|
|
/* [dcl.init.ref]
|
|
|
|
"cv1 T1" is reference compatible with "cv2 T2" if
|
|
a prvalue of type "pointer to cv2 T2" can be converted to the type
|
|
"pointer to cv1 T1" via a standard conversion sequence. */
|
|
tree ptype1 = build_pointer_type (t1);
|
|
tree ptype2 = build_pointer_type (t2);
|
|
conversion *conv = standard_conversion (ptype1, ptype2, NULL_TREE,
|
|
/*c_cast_p=*/false, 0, tf_none);
|
|
if (!conv || conv->bad_p)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/* Return true if converting FROM to TO would involve a qualification
|
|
conversion. */
|
|
|
|
static bool
|
|
involves_qualification_conversion_p (tree to, tree from)
|
|
{
|
|
/* If we're not convering a pointer to another one, we won't get
|
|
a qualification conversion. */
|
|
if (!((TYPE_PTR_P (to) && TYPE_PTR_P (from))
|
|
|| (TYPE_PTRDATAMEM_P (to) && TYPE_PTRDATAMEM_P (from))))
|
|
return false;
|
|
|
|
conversion *conv = standard_conversion (to, from, NULL_TREE,
|
|
/*c_cast_p=*/false, 0, tf_none);
|
|
for (conversion *t = conv; t; t = next_conversion (t))
|
|
if (t->kind == ck_qual)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/* A reference of the indicated TYPE is being bound directly to the
|
|
expression represented by the implicit conversion sequence CONV.
|
|
Return a conversion sequence for this binding. */
|
|
|
|
static conversion *
|
|
direct_reference_binding (tree type, conversion *conv)
|
|
{
|
|
tree t;
|
|
|
|
gcc_assert (TYPE_REF_P (type));
|
|
gcc_assert (!TYPE_REF_P (conv->type));
|
|
|
|
t = TREE_TYPE (type);
|
|
|
|
if (conv->kind == ck_identity)
|
|
/* Mark the identity conv as to not decay to rvalue. */
|
|
conv->rvaluedness_matches_p = true;
|
|
|
|
/* [over.ics.rank]
|
|
|
|
When a parameter of reference type binds directly
|
|
(_dcl.init.ref_) to an argument expression, the implicit
|
|
conversion sequence is the identity conversion, unless the
|
|
argument expression has a type that is a derived class of the
|
|
parameter type, in which case the implicit conversion sequence is
|
|
a derived-to-base Conversion.
|
|
|
|
If the parameter binds directly to the result of applying a
|
|
conversion function to the argument expression, the implicit
|
|
conversion sequence is a user-defined conversion sequence
|
|
(_over.ics.user_), with the second standard conversion sequence
|
|
either an identity conversion or, if the conversion function
|
|
returns an entity of a type that is a derived class of the
|
|
parameter type, a derived-to-base conversion. */
|
|
if (is_properly_derived_from (conv->type, t))
|
|
{
|
|
/* Represent the derived-to-base conversion. */
|
|
conv = build_conv (ck_base, t, conv);
|
|
/* We will actually be binding to the base-class subobject in
|
|
the derived class, so we mark this conversion appropriately.
|
|
That way, convert_like knows not to generate a temporary. */
|
|
conv->need_temporary_p = false;
|
|
}
|
|
else if (involves_qualification_conversion_p (t, conv->type))
|
|
/* Represent the qualification conversion. After DR 2352
|
|
#1 and #2 were indistinguishable conversion sequences:
|
|
|
|
void f(int*); // #1
|
|
void f(const int* const &); // #2
|
|
void g(int* p) { f(p); }
|
|
|
|
because the types "int *" and "const int *const" are
|
|
reference-related and we were binding both directly and they
|
|
had the same rank. To break it up, we add a ck_qual under the
|
|
ck_ref_bind so that conversion sequence ranking chooses #1.
|
|
|
|
We strip_top_quals here which is also what standard_conversion
|
|
does. Failure to do so would confuse comp_cv_qual_signature
|
|
into thinking that in
|
|
|
|
void f(const int * const &); // #1
|
|
void f(const int *); // #2
|
|
int *x;
|
|
f(x);
|
|
|
|
#2 is a better match than #1 even though they're ambiguous (97296). */
|
|
conv = build_conv (ck_qual, strip_top_quals (t), conv);
|
|
|
|
return build_conv (ck_ref_bind, type, conv);
|
|
}
|
|
|
|
/* Returns the conversion path from type FROM to reference type TO for
|
|
purposes of reference binding. For lvalue binding, either pass a
|
|
reference type to FROM or an lvalue expression to EXPR. If the
|
|
reference will be bound to a temporary, NEED_TEMPORARY_P is set for
|
|
the conversion returned. If C_CAST_P is true, this
|
|
conversion is coming from a C-style cast. */
|
|
|
|
static conversion *
|
|
reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
|
|
tsubst_flags_t complain)
|
|
{
|
|
conversion *conv = NULL;
|
|
tree to = TREE_TYPE (rto);
|
|
tree from = rfrom;
|
|
tree tfrom;
|
|
bool related_p;
|
|
bool compatible_p;
|
|
cp_lvalue_kind gl_kind;
|
|
bool is_lvalue;
|
|
|
|
if (TREE_CODE (to) == FUNCTION_TYPE && expr && type_unknown_p (expr))
|
|
{
|
|
expr = instantiate_type (to, expr, tf_none);
|
|
if (expr == error_mark_node)
|
|
return NULL;
|
|
from = TREE_TYPE (expr);
|
|
}
|
|
|
|
bool copy_list_init = false;
|
|
if (expr && BRACE_ENCLOSED_INITIALIZER_P (expr))
|
|
{
|
|
maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
|
|
/* DR 1288: Otherwise, if the initializer list has a single element
|
|
of type E and ... [T's] referenced type is reference-related to E,
|
|
the object or reference is initialized from that element...
|
|
|
|
??? With P0388R4, we should bind 't' directly to U{}:
|
|
using U = A[2];
|
|
A (&&t)[] = {U{}};
|
|
because A[] and A[2] are reference-related. But we don't do it
|
|
because grok_reference_init has deduced the array size (to 1), and
|
|
A[1] and A[2] aren't reference-related. */
|
|
if (CONSTRUCTOR_NELTS (expr) == 1
|
|
&& !CONSTRUCTOR_IS_DESIGNATED_INIT (expr))
|
|
{
|
|
tree elt = CONSTRUCTOR_ELT (expr, 0)->value;
|
|
if (error_operand_p (elt))
|
|
return NULL;
|
|
tree etype = TREE_TYPE (elt);
|
|
if (reference_related_p (to, etype))
|
|
{
|
|
expr = elt;
|
|
from = etype;
|
|
goto skip;
|
|
}
|
|
}
|
|
/* 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 (TYPE_REF_P (from))
|
|
{
|
|
from = TREE_TYPE (from);
|
|
if (!TYPE_REF_IS_RVALUE (rfrom)
|
|
|| TREE_CODE (from) == FUNCTION_TYPE)
|
|
gl_kind = clk_ordinary;
|
|
else
|
|
gl_kind = clk_rvalueref;
|
|
}
|
|
else if (expr)
|
|
gl_kind = lvalue_kind (expr);
|
|
else if (CLASS_TYPE_P (from)
|
|
|| TREE_CODE (from) == ARRAY_TYPE)
|
|
gl_kind = clk_class;
|
|
else
|
|
gl_kind = clk_none;
|
|
|
|
/* Don't allow a class prvalue when LOOKUP_NO_TEMP_BIND. */
|
|
if ((flags & LOOKUP_NO_TEMP_BIND)
|
|
&& (gl_kind & clk_class))
|
|
gl_kind = clk_none;
|
|
|
|
/* Same mask as real_lvalue_p. */
|
|
is_lvalue = gl_kind && !(gl_kind & (clk_rvalueref|clk_class));
|
|
|
|
tfrom = from;
|
|
if ((gl_kind & clk_bitfield) != 0)
|
|
tfrom = unlowered_expr_type (expr);
|
|
|
|
/* Figure out whether or not the types are reference-related and
|
|
reference compatible. We have to do this after stripping
|
|
references from FROM. */
|
|
related_p = reference_related_p (to, tfrom);
|
|
/* If this is a C cast, first convert to an appropriately qualified
|
|
type, so that we can later do a const_cast to the desired type. */
|
|
if (related_p && c_cast_p
|
|
&& !at_least_as_qualified_p (to, tfrom))
|
|
to = cp_build_qualified_type (to, cp_type_quals (tfrom));
|
|
compatible_p = reference_compatible_p (to, tfrom);
|
|
|
|
/* Directly bind reference when target expression's type is compatible with
|
|
the reference and expression is an lvalue. In DR391, the wording in
|
|
[8.5.3/5 dcl.init.ref] is changed to also require direct bindings for
|
|
const and rvalue references to rvalues of compatible class type.
|
|
We should also do direct bindings for non-class xvalues. */
|
|
if ((related_p || compatible_p) && gl_kind)
|
|
{
|
|
/* [dcl.init.ref]
|
|
|
|
If the initializer expression
|
|
|
|
-- is an lvalue (but not an lvalue for a bit-field), and "cv1 T1"
|
|
is reference-compatible with "cv2 T2,"
|
|
|
|
the reference is bound directly to the initializer expression
|
|
lvalue.
|
|
|
|
[...]
|
|
If the initializer expression is an rvalue, with T2 a class type,
|
|
and "cv1 T1" is reference-compatible with "cv2 T2", the reference
|
|
is bound to the object represented by the rvalue or to a sub-object
|
|
within that object. */
|
|
|
|
conv = build_identity_conv (tfrom, expr);
|
|
conv = direct_reference_binding (rto, conv);
|
|
|
|
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));
|
|
else
|
|
conv->rvaluedness_matches_p
|
|
= (TYPE_REF_IS_RVALUE (rto) == !is_lvalue);
|
|
|
|
if ((gl_kind & clk_bitfield) != 0
|
|
|| ((gl_kind & clk_packed) != 0 && !TYPE_PACKED (to)))
|
|
/* For the purposes of overload resolution, we ignore the fact
|
|
this expression is a bitfield or packed field. (In particular,
|
|
[over.ics.ref] says specifically that a function with a
|
|
non-const reference parameter is viable even if the
|
|
argument is a bitfield.)
|
|
|
|
However, when we actually call the function we must create
|
|
a temporary to which to bind the reference. If the
|
|
reference is volatile, or isn't const, then we cannot make
|
|
a temporary, so we just issue an error when the conversion
|
|
actually occurs. */
|
|
conv->need_temporary_p = true;
|
|
|
|
/* Don't allow binding of lvalues (other than function lvalues) to
|
|
rvalue references. */
|
|
if (is_lvalue && TYPE_REF_IS_RVALUE (rto)
|
|
&& TREE_CODE (to) != FUNCTION_TYPE)
|
|
conv->bad_p = true;
|
|
|
|
/* Nor the reverse. */
|
|
if (!is_lvalue && !TYPE_REF_IS_RVALUE (rto)
|
|
/* Unless it's really an lvalue. */
|
|
&& !(cxx_dialect >= cxx20
|
|
&& (gl_kind & clk_implicit_rval))
|
|
&& (!CP_TYPE_CONST_NON_VOLATILE_P (to)
|
|
|| (flags & LOOKUP_NO_RVAL_BIND))
|
|
&& TREE_CODE (to) != FUNCTION_TYPE)
|
|
conv->bad_p = true;
|
|
|
|
if (!compatible_p)
|
|
conv->bad_p = true;
|
|
|
|
return conv;
|
|
}
|
|
/* [class.conv.fct] A conversion function is never used to convert a
|
|
(possibly cv-qualified) object to the (possibly cv-qualified) same
|
|
object type (or a reference to it), to a (possibly cv-qualified) base
|
|
class of that type (or a reference to it).... */
|
|
else if (CLASS_TYPE_P (from) && !related_p
|
|
&& !(flags & LOOKUP_NO_CONVERSION))
|
|
{
|
|
/* [dcl.init.ref]
|
|
|
|
If the initializer expression
|
|
|
|
-- has a class type (i.e., T2 is a class type) can be
|
|
implicitly converted to an lvalue of type "cv3 T3," where
|
|
"cv1 T1" is reference-compatible with "cv3 T3". (this
|
|
conversion is selected by enumerating the applicable
|
|
conversion functions (_over.match.ref_) and choosing the
|
|
best one through overload resolution. (_over.match_).
|
|
|
|
the reference is bound to the lvalue result of the conversion
|
|
in the second case. */
|
|
z_candidate *cand = build_user_type_conversion_1 (rto, expr, flags,
|
|
complain);
|
|
if (cand)
|
|
return cand->second_conv;
|
|
}
|
|
|
|
/* From this point on, we conceptually need temporaries, even if we
|
|
elide them. Only the cases above are "direct bindings". */
|
|
if (flags & LOOKUP_NO_TEMP_BIND)
|
|
return NULL;
|
|
|
|
/* [over.ics.rank]
|
|
|
|
When a parameter of reference type is not bound directly to an
|
|
argument expression, the conversion sequence is the one required
|
|
to convert the argument expression to the underlying type of the
|
|
reference according to _over.best.ics_. Conceptually, this
|
|
conversion sequence corresponds to copy-initializing a temporary
|
|
of the underlying type with the argument expression. Any
|
|
difference in top-level cv-qualification is subsumed by the
|
|
initialization itself and does not constitute a conversion. */
|
|
|
|
/* [dcl.init.ref]
|
|
|
|
Otherwise, the reference shall be an lvalue reference to a
|
|
non-volatile const type, or the reference shall be an rvalue
|
|
reference.
|
|
|
|
We try below to treat this as a bad conversion to improve diagnostics,
|
|
but if TO is an incomplete class, we need to reject this conversion
|
|
now to avoid unnecessary instantiation. */
|
|
if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto)
|
|
&& !COMPLETE_TYPE_P (to))
|
|
return NULL;
|
|
|
|
/* We're generating a temporary now, but don't bind any more in the
|
|
conversion (specifically, don't slice the temporary returned by a
|
|
conversion operator). */
|
|
flags |= LOOKUP_NO_TEMP_BIND;
|
|
|
|
/* 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 don't set LOOKUP_ONLYCONVERTING in that case. */
|
|
if (!(flags & LOOKUP_COPY_PARM))
|
|
flags |= LOOKUP_ONLYCONVERTING;
|
|
|
|
if (!conv)
|
|
conv = implicit_conversion (to, from, expr, c_cast_p,
|
|
flags, complain);
|
|
if (!conv)
|
|
return NULL;
|
|
|
|
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 (t->kind == ck_user
|
|
&& DECL_CONV_FN_P (t->cand->fn))
|
|
{
|
|
tree ftype = TREE_TYPE (TREE_TYPE (t->cand->fn));
|
|
/* A prvalue of non-class type is cv-unqualified. */
|
|
if (!TYPE_REF_P (ftype) && !CLASS_TYPE_P (ftype))
|
|
ftype = cv_unqualified (ftype);
|
|
int sflags = (flags|LOOKUP_NO_CONVERSION)&~LOOKUP_NO_TEMP_BIND;
|
|
conversion *new_second
|
|
= reference_binding (rto, ftype, NULL_TREE, c_cast_p,
|
|
sflags, complain);
|
|
if (!new_second)
|
|
return NULL;
|
|
return merge_conversion_sequences (t, new_second);
|
|
}
|
|
}
|
|
|
|
conv = build_conv (ck_ref_bind, rto, conv);
|
|
/* This reference binding, unlike those above, requires the
|
|
creation of a temporary. */
|
|
conv->need_temporary_p = true;
|
|
conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto);
|
|
|
|
/* [dcl.init.ref]
|
|
|
|
Otherwise, the reference shall be an lvalue reference to a
|
|
non-volatile const type, or the reference shall be an rvalue
|
|
reference. */
|
|
if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto))
|
|
conv->bad_p = true;
|
|
|
|
/* [dcl.init.ref]
|
|
|
|
Otherwise, a temporary of type "cv1 T1" is created and
|
|
initialized from the initializer expression using the rules for a
|
|
non-reference copy initialization. If T1 is reference-related to
|
|
T2, cv1 must be the same cv-qualification as, or greater
|
|
cv-qualification than, cv2; otherwise, the program is ill-formed. */
|
|
if (related_p && !at_least_as_qualified_p (to, from))
|
|
conv->bad_p = true;
|
|
|
|
return conv;
|
|
}
|
|
|
|
/* Most of the implementation of implicit_conversion, with the same
|
|
parameters. */
|
|
|
|
static conversion *
|
|
implicit_conversion_1 (tree to, tree from, tree expr, bool c_cast_p,
|
|
int flags, tsubst_flags_t complain)
|
|
{
|
|
conversion *conv;
|
|
|
|
if (from == error_mark_node || to == error_mark_node
|
|
|| expr == error_mark_node)
|
|
return NULL;
|
|
|
|
/* Other flags only apply to the primary function in overload
|
|
resolution, or after we've chosen one. */
|
|
flags &= (LOOKUP_ONLYCONVERTING|LOOKUP_NO_CONVERSION|LOOKUP_COPY_PARM
|
|
|LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND|LOOKUP_PREFER_RVALUE
|
|
|LOOKUP_NO_NARROWING|LOOKUP_PROTECT|LOOKUP_NO_NON_INTEGRAL);
|
|
|
|
/* FIXME: actually we don't want warnings either, but we can't just
|
|
have 'complain &= ~(tf_warning|tf_error)' because it would cause
|
|
the regression of, eg, g++.old-deja/g++.benjamin/16077.C.
|
|
We really ought not to issue that warning until we've committed
|
|
to that conversion. */
|
|
complain &= ~tf_error;
|
|
|
|
/* Call reshape_init early to remove redundant braces. */
|
|
if (expr && BRACE_ENCLOSED_INITIALIZER_P (expr)
|
|
&& CLASS_TYPE_P (to)
|
|
&& COMPLETE_TYPE_P (complete_type (to))
|
|
&& !CLASSTYPE_NON_AGGREGATE (to))
|
|
{
|
|
expr = reshape_init (to, expr, complain);
|
|
if (expr == error_mark_node)
|
|
return NULL;
|
|
from = TREE_TYPE (expr);
|
|
}
|
|
|
|
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 (conv)
|
|
return conv;
|
|
|
|
if (expr && BRACE_ENCLOSED_INITIALIZER_P (expr))
|
|
{
|
|
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
|
|
&& !CONSTRUCTOR_IS_DESIGNATED_INIT (expr))
|
|
{
|
|
conv = build_complex_conv (to, expr, flags, complain);
|
|
if (conv)
|
|
return conv;
|
|
}
|
|
|
|
/* Allow conversion from an initializer-list with one element to a
|
|
scalar type. */
|
|
if (SCALAR_TYPE_P (to))
|
|
{
|
|
int nelts = CONSTRUCTOR_NELTS (expr);
|
|
tree elt;
|
|
|
|
if (nelts == 0)
|
|
elt = build_value_init (to, tf_none);
|
|
else if (nelts == 1 && !CONSTRUCTOR_IS_DESIGNATED_INIT (expr))
|
|
elt = CONSTRUCTOR_ELT (expr, 0)->value;
|
|
else
|
|
elt = error_mark_node;
|
|
|
|
conv = implicit_conversion (to, TREE_TYPE (elt), elt,
|
|
c_cast_p, flags, complain);
|
|
if (conv)
|
|
{
|
|
conv->check_narrowing = true;
|
|
if (BRACE_ENCLOSED_INITIALIZER_P (elt))
|
|
/* Too many levels of braces, i.e. '{{1}}'. */
|
|
conv->bad_p = true;
|
|
return conv;
|
|
}
|
|
}
|
|
else if (TREE_CODE (to) == ARRAY_TYPE)
|
|
return build_array_conv (to, expr, flags, complain);
|
|
}
|
|
|
|
if (expr != NULL_TREE
|
|
&& (MAYBE_CLASS_TYPE_P (from)
|
|
|| MAYBE_CLASS_TYPE_P (to))
|
|
&& (flags & LOOKUP_NO_CONVERSION) == 0)
|
|
{
|
|
struct z_candidate *cand;
|
|
|
|
if (CLASS_TYPE_P (to)
|
|
&& BRACE_ENCLOSED_INITIALIZER_P (expr)
|
|
&& !CLASSTYPE_NON_AGGREGATE (complete_type (to)))
|
|
return build_aggr_conv (to, expr, flags, complain);
|
|
|
|
cand = build_user_type_conversion_1 (to, expr, flags, complain);
|
|
if (cand)
|
|
{
|
|
if (BRACE_ENCLOSED_INITIALIZER_P (expr)
|
|
&& CONSTRUCTOR_NELTS (expr) == 1
|
|
&& !CONSTRUCTOR_IS_DESIGNATED_INIT (expr)
|
|
&& !is_list_ctor (cand->fn))
|
|
{
|
|
/* "If C is not an initializer-list constructor and the
|
|
initializer list has a single element of type cv U, where U is
|
|
X or a class derived from X, the implicit conversion sequence
|
|
has Exact Match rank if U is X, or Conversion rank if U is
|
|
derived from X." */
|
|
tree elt = CONSTRUCTOR_ELT (expr, 0)->value;
|
|
tree elttype = TREE_TYPE (elt);
|
|
if (reference_related_p (to, elttype))
|
|
return implicit_conversion (to, elttype, elt,
|
|
c_cast_p, flags, complain);
|
|
}
|
|
conv = cand->second_conv;
|
|
}
|
|
|
|
/* We used to try to bind a reference to a temporary here, but that
|
|
is now handled after the recursive call to this function at the end
|
|
of reference_binding. */
|
|
return conv;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Returns the implicit conversion sequence (see [over.ics]) from type
|
|
FROM to type TO. The optional expression EXPR may affect the
|
|
conversion. FLAGS are the usual overloading flags. If C_CAST_P is
|
|
true, this conversion is coming from a C-style cast. */
|
|
|
|
static conversion *
|
|
implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
|
|
int flags, tsubst_flags_t complain)
|
|
{
|
|
conversion *conv = implicit_conversion_1 (to, from, expr, c_cast_p,
|
|
flags, complain);
|
|
if (!conv || conv->bad_p)
|
|
return conv;
|
|
if (conv_is_prvalue (conv)
|
|
&& CLASS_TYPE_P (conv->type)
|
|
&& CLASSTYPE_PURE_VIRTUALS (conv->type))
|
|
conv->bad_p = true;
|
|
return conv;
|
|
}
|
|
|
|
/* 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. */
|
|
|
|
static struct z_candidate *
|
|
add_candidate (struct z_candidate **candidates,
|
|
tree fn, tree first_arg, const vec<tree, va_gc> *args,
|
|
size_t num_convs, conversion **convs,
|
|
tree access_path, tree conversion_path,
|
|
int viable, struct rejection_reason *reason,
|
|
int flags)
|
|
{
|
|
struct z_candidate *cand = (struct z_candidate *)
|
|
conversion_obstack_alloc (sizeof (struct z_candidate));
|
|
|
|
cand->fn = fn;
|
|
cand->first_arg = first_arg;
|
|
cand->args = args;
|
|
cand->convs = convs;
|
|
cand->num_convs = num_convs;
|
|
cand->access_path = access_path;
|
|
cand->conversion_path = conversion_path;
|
|
cand->viable = viable;
|
|
cand->reason = reason;
|
|
cand->next = *candidates;
|
|
cand->flags = flags;
|
|
*candidates = cand;
|
|
|
|
if (convs && cand->reversed ())
|
|
/* Swap the conversions for comparison in joust; we'll swap them back
|
|
before build_over_call. */
|
|
std::swap (convs[0], convs[1]);
|
|
|
|
return cand;
|
|
}
|
|
|
|
/* Return the number of remaining arguments in the parameter list
|
|
beginning with ARG. */
|
|
|
|
int
|
|
remaining_arguments (tree arg)
|
|
{
|
|
int n;
|
|
|
|
for (n = 0; arg != NULL_TREE && arg != void_list_node;
|
|
arg = TREE_CHAIN (arg))
|
|
n++;
|
|
|
|
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;
|
|
}
|
|
|
|
/* Build an appropriate 'this' conversion for the method FN and class
|
|
type CTYPE from the value ARG (having type ARGTYPE) to the type PARMTYPE.
|
|
This function modifies PARMTYPE, ARGTYPE and ARG. */
|
|
|
|
static conversion *
|
|
build_this_conversion (tree fn, tree ctype,
|
|
tree& parmtype, tree& argtype, tree& arg,
|
|
int flags, tsubst_flags_t complain)
|
|
{
|
|
gcc_assert (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
|
|
&& !DECL_CONSTRUCTOR_P (fn));
|
|
|
|
/* The type of the implicit object parameter ('this') for
|
|
overload resolution is not always the same as for the
|
|
function itself; conversion functions are considered to
|
|
be members of the class being converted, and functions
|
|
introduced by a using-declaration are considered to be
|
|
members of the class that uses them.
|
|
|
|
Since build_over_call ignores the ICS for the `this'
|
|
parameter, we can just change the parm type. */
|
|
parmtype = cp_build_qualified_type (ctype,
|
|
cp_type_quals (TREE_TYPE (parmtype)));
|
|
bool this_p = true;
|
|
if (FUNCTION_REF_QUALIFIED (TREE_TYPE (fn)))
|
|
{
|
|
/* If the function has a ref-qualifier, the implicit
|
|
object parameter has reference type. */
|
|
bool rv = FUNCTION_RVALUE_QUALIFIED (TREE_TYPE (fn));
|
|
parmtype = cp_build_reference_type (parmtype, rv);
|
|
/* The special handling of 'this' conversions in compare_ics
|
|
does not apply if there is a ref-qualifier. */
|
|
this_p = false;
|
|
}
|
|
else
|
|
{
|
|
parmtype = build_pointer_type (parmtype);
|
|
/* We don't use build_this here because we don't want to
|
|
capture the object argument until we've chosen a
|
|
non-static member function. */
|
|
arg = build_address (arg);
|
|
argtype = lvalue_type (arg);
|
|
}
|
|
flags |= LOOKUP_ONLYCONVERTING;
|
|
conversion *t = implicit_conversion (parmtype, argtype, arg,
|
|
/*c_cast_p=*/false, flags, complain);
|
|
t->this_p = this_p;
|
|
return t;
|
|
}
|
|
|
|
/* 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.
|
|
|
|
This does not change ARGS.
|
|
|
|
CTYPE, if non-NULL, is the type we want to pretend this function
|
|
comes from for purposes of overload resolution.
|
|
|
|
SHORTCUT_BAD_CONVS controls how we handle "bad" argument conversions.
|
|
If true, we stop computing conversions upon seeing the first bad
|
|
conversion. This is used by add_candidates to avoid computing
|
|
more conversions than necessary in the presence of a strictly viable
|
|
candidate, while preserving the defacto behavior of overload resolution
|
|
when it turns out there are only non-strictly viable candidates. */
|
|
|
|
static struct z_candidate *
|
|
add_function_candidate (struct z_candidate **candidates,
|
|
tree fn, tree ctype, tree first_arg,
|
|
const vec<tree, va_gc> *args, tree access_path,
|
|
tree conversion_path, int flags,
|
|
conversion **convs,
|
|
bool shortcut_bad_convs,
|
|
tsubst_flags_t complain)
|
|
{
|
|
tree parmlist = TYPE_ARG_TYPES (TREE_TYPE (fn));
|
|
int i, len;
|
|
tree parmnode;
|
|
tree orig_first_arg = first_arg;
|
|
int skip;
|
|
int viable = 1;
|
|
struct rejection_reason *reason = NULL;
|
|
|
|
/* The `this', `in_chrg' and VTT arguments to constructors are not
|
|
considered in overload resolution. */
|
|
if (DECL_CONSTRUCTOR_P (fn))
|
|
{
|
|
if (ctor_omit_inherited_parms (fn))
|
|
/* Bring back parameters omitted from an inherited ctor. */
|
|
parmlist = FUNCTION_FIRST_USER_PARMTYPE (DECL_ORIGIN (fn));
|
|
else
|
|
parmlist = skip_artificial_parms_for (fn, parmlist);
|
|
skip = num_artificial_parms_for (fn);
|
|
if (skip > 0 && first_arg != NULL_TREE)
|
|
{
|
|
--skip;
|
|
first_arg = NULL_TREE;
|
|
}
|
|
}
|
|
else
|
|
skip = 0;
|
|
|
|
len = vec_safe_length (args) - skip + (first_arg != NULL_TREE ? 1 : 0);
|
|
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
|
|
parameters to agree in number with the arguments in the list.
|
|
|
|
We need to check this first; otherwise, checking the ICSes might cause
|
|
us to produce an ill-formed template instantiation. */
|
|
|
|
parmnode = parmlist;
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
if (parmnode == NULL_TREE || parmnode == void_list_node)
|
|
break;
|
|
parmnode = TREE_CHAIN (parmnode);
|
|
}
|
|
|
|
if ((i < len && parmnode)
|
|
|| !sufficient_parms_p (parmnode))
|
|
{
|
|
int remaining = remaining_arguments (parmnode);
|
|
viable = 0;
|
|
reason = arity_rejection (first_arg, i + remaining, len);
|
|
}
|
|
|
|
/* An inherited constructor (12.6.3 [class.inhctor.init]) that has a first
|
|
parameter of type "reference to cv C" (including such a constructor
|
|
instantiated from a template) is excluded from the set of candidate
|
|
functions when used to construct an object of type D with an argument list
|
|
containing a single argument if C is reference-related to D. */
|
|
if (viable && len == 1 && parmlist && DECL_CONSTRUCTOR_P (fn)
|
|
&& flag_new_inheriting_ctors
|
|
&& DECL_INHERITED_CTOR (fn))
|
|
{
|
|
tree ptype = non_reference (TREE_VALUE (parmlist));
|
|
tree dtype = DECL_CONTEXT (fn);
|
|
tree btype = DECL_INHERITED_CTOR_BASE (fn);
|
|
if (reference_related_p (ptype, dtype)
|
|
&& reference_related_p (btype, ptype))
|
|
{
|
|
viable = false;
|
|
reason = inherited_ctor_rejection ();
|
|
}
|
|
}
|
|
|
|
/* Second, for a function to be viable, its constraints must be
|
|
satisfied. */
|
|
if (flag_concepts && viable && !constraints_satisfied_p (fn))
|
|
{
|
|
reason = constraint_failure ();
|
|
viable = false;
|
|
}
|
|
|
|
/* When looking for a function from a subobject from an implicit
|
|
copy/move constructor/operator=, don't consider anything that takes (a
|
|
reference to) an unrelated type. See c++/44909 and core 1092. */
|
|
if (viable && parmlist && (flags & LOOKUP_DEFAULTED))
|
|
{
|
|
if (DECL_CONSTRUCTOR_P (fn))
|
|
i = 1;
|
|
else if (DECL_ASSIGNMENT_OPERATOR_P (fn)
|
|
&& DECL_OVERLOADED_OPERATOR_IS (fn, NOP_EXPR))
|
|
i = 2;
|
|
else
|
|
i = 0;
|
|
if (i && len == i)
|
|
{
|
|
parmnode = chain_index (i-1, parmlist);
|
|
if (!reference_related_p (non_reference (TREE_VALUE (parmnode)),
|
|
ctype))
|
|
viable = 0;
|
|
}
|
|
|
|
/* This only applies at the top level. */
|
|
flags &= ~LOOKUP_DEFAULTED;
|
|
}
|
|
|
|
if (! viable)
|
|
goto out;
|
|
|
|
/* Third, for F to be a viable function, there shall exist for each
|
|
argument an implicit conversion sequence that converts that argument
|
|
to the corresponding parameter of F. */
|
|
|
|
parmnode = parmlist;
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
tree argtype, to_type;
|
|
tree arg;
|
|
|
|
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
|
|
arg = CONST_CAST_TREE (
|
|
(*args)[i + skip - (first_arg != NULL_TREE ? 1 : 0)]);
|
|
argtype = lvalue_type (arg);
|
|
|
|
conversion *t;
|
|
if (parmnode)
|
|
{
|
|
tree parmtype = TREE_VALUE (parmnode);
|
|
if (i == 0
|
|
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
|
|
&& !DECL_CONSTRUCTOR_P (fn))
|
|
t = build_this_conversion (fn, ctype, parmtype, argtype, arg,
|
|
flags, complain);
|
|
else
|
|
{
|
|
int lflags = conv_flags (i, len-skip, fn, arg, flags);
|
|
t = implicit_conversion (parmtype, argtype, arg,
|
|
/*c_cast_p=*/false, lflags, complain);
|
|
}
|
|
to_type = parmtype;
|
|
parmnode = TREE_CHAIN (parmnode);
|
|
}
|
|
else
|
|
{
|
|
t = build_identity_conv (argtype, arg);
|
|
t->ellipsis_p = true;
|
|
to_type = argtype;
|
|
}
|
|
|
|
convs[i] = t;
|
|
if (! t)
|
|
{
|
|
viable = 0;
|
|
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,
|
|
EXPR_LOCATION (arg));
|
|
if (shortcut_bad_convs)
|
|
break;
|
|
}
|
|
}
|
|
|
|
out:
|
|
return add_candidate (candidates, fn, orig_first_arg, args, len, convs,
|
|
access_path, conversion_path, viable, reason, flags);
|
|
}
|
|
|
|
/* Create an overload candidate for the conversion function FN which will
|
|
be invoked for expression OBJ, producing a pointer-to-function which
|
|
will in turn be called with the argument list FIRST_ARG/ARGLIST,
|
|
and add it to CANDIDATES. This does not change ARGLIST. FLAGS is
|
|
passed on to implicit_conversion.
|
|
|
|
Actually, we don't really care about FN; we care about the type it
|
|
converts to. There may be multiple conversion functions that will
|
|
convert to that type, and we rely on build_user_type_conversion_1 to
|
|
choose the best one; so when we create our candidate, we record the type
|
|
instead of the function. */
|
|
|
|
static struct z_candidate *
|
|
add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
|
|
const vec<tree, va_gc> *arglist,
|
|
tree access_path, tree conversion_path,
|
|
tsubst_flags_t complain)
|
|
{
|
|
tree totype = TREE_TYPE (TREE_TYPE (fn));
|
|
int i, len, viable, flags;
|
|
tree parmlist, parmnode;
|
|
conversion **convs;
|
|
struct rejection_reason *reason;
|
|
|
|
for (parmlist = totype; TREE_CODE (parmlist) != FUNCTION_TYPE; )
|
|
parmlist = TREE_TYPE (parmlist);
|
|
parmlist = TYPE_ARG_TYPES (parmlist);
|
|
|
|
len = vec_safe_length (arglist) + 1;
|
|
convs = alloc_conversions (len);
|
|
parmnode = parmlist;
|
|
viable = 1;
|
|
flags = LOOKUP_IMPLICIT;
|
|
reason = NULL;
|
|
|
|
/* Don't bother looking up the same type twice. */
|
|
if (*candidates && (*candidates)->fn == totype)
|
|
return NULL;
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
tree arg, argtype, convert_type = NULL_TREE;
|
|
conversion *t;
|
|
|
|
if (i == 0)
|
|
arg = obj;
|
|
else
|
|
arg = (*arglist)[i - 1];
|
|
argtype = lvalue_type (arg);
|
|
|
|
if (i == 0)
|
|
{
|
|
t = build_identity_conv (argtype, NULL_TREE);
|
|
t = build_conv (ck_user, totype, t);
|
|
/* Leave the 'cand' field null; we'll figure out the conversion in
|
|
convert_like if this candidate is chosen. */
|
|
convert_type = totype;
|
|
}
|
|
else if (parmnode == void_list_node)
|
|
break;
|
|
else if (parmnode)
|
|
{
|
|
t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg,
|
|
/*c_cast_p=*/false, flags, complain);
|
|
convert_type = TREE_VALUE (parmnode);
|
|
}
|
|
else
|
|
{
|
|
t = build_identity_conv (argtype, arg);
|
|
t->ellipsis_p = true;
|
|
convert_type = argtype;
|
|
}
|
|
|
|
convs[i] = t;
|
|
if (! t)
|
|
break;
|
|
|
|
if (t->bad_p)
|
|
{
|
|
viable = -1;
|
|
reason = bad_arg_conversion_rejection (NULL_TREE, i, arg, convert_type,
|
|
EXPR_LOCATION (arg));
|
|
}
|
|
|
|
if (i == 0)
|
|
continue;
|
|
|
|
if (parmnode)
|
|
parmnode = TREE_CHAIN (parmnode);
|
|
}
|
|
|
|
if (i < len
|
|
|| ! sufficient_parms_p (parmnode))
|
|
{
|
|
int remaining = remaining_arguments (parmnode);
|
|
viable = 0;
|
|
reason = arity_rejection (NULL_TREE, i + remaining, len);
|
|
}
|
|
|
|
return add_candidate (candidates, totype, obj, arglist, len, convs,
|
|
access_path, conversion_path, viable, reason, flags);
|
|
}
|
|
|
|
static void
|
|
build_builtin_candidate (struct z_candidate **candidates, tree fnname,
|
|
tree type1, tree type2, const vec<tree,va_gc> &args,
|
|
tree *argtypes, int flags, tsubst_flags_t complain)
|
|
{
|
|
conversion *t;
|
|
conversion **convs;
|
|
size_t num_convs;
|
|
int viable = 1;
|
|
tree types[2];
|
|
struct rejection_reason *reason = NULL;
|
|
|
|
types[0] = type1;
|
|
types[1] = type2;
|
|
|
|
num_convs = args.length ();
|
|
convs = alloc_conversions (num_convs);
|
|
|
|
/* TRUTH_*_EXPR do "contextual conversion to bool", which means explicit
|
|
conversion ops are allowed. We handle that here by just checking for
|
|
boolean_type_node because other operators don't ask for it. COND_EXPR
|
|
also does contextual conversion to bool for the first operand, but we
|
|
handle that in build_conditional_expr, and type1 here is operand 2. */
|
|
if (type1 != boolean_type_node)
|
|
flags |= LOOKUP_ONLYCONVERTING;
|
|
|
|
for (unsigned i = 0; i < 2 && i < num_convs; ++i)
|
|
{
|
|
t = implicit_conversion (types[i], argtypes[i], args[i],
|
|
/*c_cast_p=*/false, flags, complain);
|
|
if (! t)
|
|
{
|
|
viable = 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], EXPR_LOCATION (args[i]));
|
|
}
|
|
else if (t->bad_p)
|
|
{
|
|
viable = 0;
|
|
reason = bad_arg_conversion_rejection (NULL_TREE, i, args[i],
|
|
types[i],
|
|
EXPR_LOCATION (args[i]));
|
|
}
|
|
convs[i] = t;
|
|
}
|
|
|
|
/* For COND_EXPR we rearranged the arguments; undo that now. */
|
|
if (num_convs == 3)
|
|
{
|
|
convs[2] = convs[1];
|
|
convs[1] = convs[0];
|
|
t = implicit_conversion (boolean_type_node, argtypes[2], args[2],
|
|
/*c_cast_p=*/false, flags,
|
|
complain);
|
|
if (t)
|
|
convs[0] = t;
|
|
else
|
|
{
|
|
viable = 0;
|
|
reason = arg_conversion_rejection (NULL_TREE, 0, argtypes[2],
|
|
boolean_type_node,
|
|
EXPR_LOCATION (args[2]));
|
|
}
|
|
}
|
|
|
|
add_candidate (candidates, fnname, /*first_arg=*/NULL_TREE, /*args=*/NULL,
|
|
num_convs, convs,
|
|
/*access_path=*/NULL_TREE,
|
|
/*conversion_path=*/NULL_TREE,
|
|
viable, reason, flags);
|
|
}
|
|
|
|
static bool
|
|
is_complete (tree t)
|
|
{
|
|
return COMPLETE_TYPE_P (complete_type (t));
|
|
}
|
|
|
|
/* Returns nonzero if TYPE is a promoted arithmetic type. */
|
|
|
|
static bool
|
|
promoted_arithmetic_type_p (tree type)
|
|
{
|
|
/* [over.built]
|
|
|
|
In this section, the term promoted integral type is used to refer
|
|
to those integral types which are preserved by integral promotion
|
|
(including e.g. int and long but excluding e.g. char).
|
|
Similarly, the term promoted arithmetic type refers to promoted
|
|
integral types plus floating types. */
|
|
return ((CP_INTEGRAL_TYPE_P (type)
|
|
&& same_type_p (type_promotes_to (type), type))
|
|
|| TREE_CODE (type) == REAL_TYPE);
|
|
}
|
|
|
|
/* Create any builtin operator overload candidates for the operator in
|
|
question given the converted operand types TYPE1 and TYPE2. The other
|
|
args are passed through from add_builtin_candidates to
|
|
build_builtin_candidate.
|
|
|
|
TYPE1 and TYPE2 may not be permissible, and we must filter them.
|
|
If CODE is requires candidates operands of the same type of the kind
|
|
of which TYPE1 and TYPE2 are, we add both candidates
|
|
CODE (TYPE1, TYPE1) and CODE (TYPE2, TYPE2). */
|
|
|
|
static void
|
|
add_builtin_candidate (struct z_candidate **candidates, enum tree_code code,
|
|
enum tree_code code2, tree fnname, tree type1,
|
|
tree type2, vec<tree,va_gc> &args, tree *argtypes,
|
|
int flags, tsubst_flags_t complain)
|
|
{
|
|
switch (code)
|
|
{
|
|
case POSTINCREMENT_EXPR:
|
|
case POSTDECREMENT_EXPR:
|
|
args[1] = integer_zero_node;
|
|
type2 = integer_type_node;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (code)
|
|
{
|
|
|
|
/* 4 For every pair (T, VQ), where T is an arithmetic type other than bool,
|
|
and VQ is either volatile or empty, there exist candidate operator
|
|
functions of the form
|
|
VQ T& operator++(VQ T&);
|
|
T operator++(VQ T&, int);
|
|
5 For every pair (T, VQ), where T is an arithmetic type other than bool,
|
|
and VQ is either volatile or empty, there exist candidate operator
|
|
functions of the form
|
|
VQ T& operator--(VQ T&);
|
|
T operator--(VQ T&, int);
|
|
6 For every pair (T, VQ), where T is a cv-qualified or cv-unqualified object
|
|
type, and VQ is either volatile or empty, there exist candidate operator
|
|
functions of the form
|
|
T*VQ& operator++(T*VQ&);
|
|
T*VQ& operator--(T*VQ&);
|
|
T* operator++(T*VQ&, int);
|
|
T* operator--(T*VQ&, int); */
|
|
|
|
case POSTDECREMENT_EXPR:
|
|
case PREDECREMENT_EXPR:
|
|
if (TREE_CODE (type1) == BOOLEAN_TYPE)
|
|
return;
|
|
/* FALLTHRU */
|
|
case POSTINCREMENT_EXPR:
|
|
case PREINCREMENT_EXPR:
|
|
/* P0002R1, Remove deprecated operator++(bool) added "other than bool"
|
|
to p4. */
|
|
if (TREE_CODE (type1) == BOOLEAN_TYPE && cxx_dialect >= cxx17)
|
|
return;
|
|
if (ARITHMETIC_TYPE_P (type1) || TYPE_PTROB_P (type1))
|
|
{
|
|
type1 = build_reference_type (type1);
|
|
break;
|
|
}
|
|
return;
|
|
|
|
/* 7 For every cv-qualified or cv-unqualified object type T, there
|
|
exist candidate operator functions of the form
|
|
|
|
T& operator*(T*);
|
|
|
|
|
|
8 For every function type T that does not have cv-qualifiers or
|
|
a ref-qualifier, there exist candidate operator functions of the form
|
|
T& operator*(T*); */
|
|
|
|
case INDIRECT_REF:
|
|
if (TYPE_PTR_P (type1)
|
|
&& (TYPE_PTROB_P (type1)
|
|
|| TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE))
|
|
break;
|
|
return;
|
|
|
|
/* 9 For every type T, there exist candidate operator functions of the form
|
|
T* operator+(T*);
|
|
|
|
10 For every floating-point or promoted integral type T, there exist
|
|
candidate operator functions of the form
|
|
T operator+(T);
|
|
T operator-(T); */
|
|
|
|
case UNARY_PLUS_EXPR: /* unary + */
|
|
if (TYPE_PTR_P (type1))
|
|
break;
|
|
/* FALLTHRU */
|
|
case NEGATE_EXPR:
|
|
if (ARITHMETIC_TYPE_P (type1))
|
|
break;
|
|
return;
|
|
|
|
/* 11 For every promoted integral type T, there exist candidate operator
|
|
functions of the form
|
|
T operator~(T); */
|
|
|
|
case BIT_NOT_EXPR:
|
|
if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type1))
|
|
break;
|
|
return;
|
|
|
|
/* 12 For every quintuple (C1, C2, T, CV1, CV2), where C2 is a class type, C1
|
|
is the same type as C2 or is a derived class of C2, and T is an object
|
|
type or a function type there exist candidate operator functions of the
|
|
form
|
|
CV12 T& operator->*(CV1 C1*, CV2 T C2::*);
|
|
where CV12 is the union of CV1 and CV2. */
|
|
|
|
case MEMBER_REF:
|
|
if (TYPE_PTR_P (type1) && TYPE_PTRMEM_P (type2))
|
|
{
|
|
tree c1 = TREE_TYPE (type1);
|
|
tree c2 = TYPE_PTRMEM_CLASS_TYPE (type2);
|
|
|
|
if (CLASS_TYPE_P (c1) && DERIVED_FROM_P (c2, c1)
|
|
&& (TYPE_PTRMEMFUNC_P (type2)
|
|
|| is_complete (TYPE_PTRMEM_POINTED_TO_TYPE (type2))))
|
|
break;
|
|
}
|
|
return;
|
|
|
|
/* 13 For every pair of types L and R, where each of L and R is a floating-point
|
|
or promoted integral type, there exist candidate operator functions of the
|
|
form
|
|
LR operator*(L, R);
|
|
LR operator/(L, R);
|
|
LR operator+(L, R);
|
|
LR operator-(L, R);
|
|
bool operator<(L, R);
|
|
bool operator>(L, R);
|
|
bool operator<=(L, R);
|
|
bool operator>=(L, R);
|
|
bool operator==(L, R);
|
|
bool operator!=(L, R);
|
|
where LR is the result of the usual arithmetic conversions between
|
|
types L and R.
|
|
|
|
14 For every integral type T there exists a candidate operator function of
|
|
the form
|
|
|
|
std::strong_ordering operator<=>(T, T);
|
|
|
|
15 For every pair of floating-point types L and R, there exists a candidate
|
|
operator function of the form
|
|
|
|
std::partial_ordering operator<=>(L, R);
|
|
|
|
16 For every cv-qualified or cv-unqualified object type T there exist
|
|
candidate operator functions of the form
|
|
T* operator+(T*, std::ptrdiff_t);
|
|
T& operator[](T*, std::ptrdiff_t);
|
|
T* operator-(T*, std::ptrdiff_t);
|
|
T* operator+(std::ptrdiff_t, T*);
|
|
T& operator[](std::ptrdiff_t, T*);
|
|
|
|
17 For every T, where T is a pointer to object type, there exist candidate
|
|
operator functions of the form
|
|
std::ptrdiff_t operator-(T, T);
|
|
|
|
18 For every T, where T is an enumeration type or a pointer type, there
|
|
exist candidate operator functions of the form
|
|
bool operator<(T, T);
|
|
bool operator>(T, T);
|
|
bool operator<=(T, T);
|
|
bool operator>=(T, T);
|
|
bool operator==(T, T);
|
|
bool operator!=(T, T);
|
|
R operator<=>(T, T);
|
|
|
|
where R is the result type specified in [expr.spaceship].
|
|
|
|
19 For every T, where T is a pointer-to-member type or std::nullptr_t,
|
|
there exist candidate operator functions of the form
|
|
bool operator==(T, T);
|
|
bool operator!=(T, T); */
|
|
|
|
case MINUS_EXPR:
|
|
if (TYPE_PTROB_P (type1) && TYPE_PTROB_P (type2))
|
|
break;
|
|
if (TYPE_PTROB_P (type1)
|
|
&& INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type2))
|
|
{
|
|
type2 = ptrdiff_type_node;
|
|
break;
|
|
}
|
|
/* FALLTHRU */
|
|
case MULT_EXPR:
|
|
case TRUNC_DIV_EXPR:
|
|
if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
|
|
break;
|
|
return;
|
|
|
|
/* This isn't exactly what's specified above for operator<=>, but it's
|
|
close enough. In particular, we don't care about the return type
|
|
specified above; it doesn't participate in overload resolution and it
|
|
doesn't affect the semantics of the built-in operator. */
|
|
case SPACESHIP_EXPR:
|
|
case EQ_EXPR:
|
|
case NE_EXPR:
|
|
if ((TYPE_PTRMEMFUNC_P (type1) && TYPE_PTRMEMFUNC_P (type2))
|
|
|| (TYPE_PTRDATAMEM_P (type1) && TYPE_PTRDATAMEM_P (type2)))
|
|
break;
|
|
if (NULLPTR_TYPE_P (type1) && NULLPTR_TYPE_P (type2))
|
|
break;
|
|
if (TYPE_PTRMEM_P (type1) && null_ptr_cst_p (args[1]))
|
|
{
|
|
type2 = type1;
|
|
break;
|
|
}
|
|
if (TYPE_PTRMEM_P (type2) && null_ptr_cst_p (args[0]))
|
|
{
|
|
type1 = type2;
|
|
break;
|
|
}
|
|
/* Fall through. */
|
|
case LT_EXPR:
|
|
case GT_EXPR:
|
|
case LE_EXPR:
|
|
case GE_EXPR:
|
|
case MAX_EXPR:
|
|
case MIN_EXPR:
|
|
if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
|
|
break;
|
|
if (TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
|
|
break;
|
|
if (TREE_CODE (type1) == ENUMERAL_TYPE
|
|
&& TREE_CODE (type2) == ENUMERAL_TYPE)
|
|
break;
|
|
if (TYPE_PTR_P (type1)
|
|
&& null_ptr_cst_p (args[1]))
|
|
{
|
|
type2 = type1;
|
|
break;
|
|
}
|
|
if (null_ptr_cst_p (args[0])
|
|
&& TYPE_PTR_P (type2))
|
|
{
|
|
type1 = type2;
|
|
break;
|
|
}
|
|
return;
|
|
|
|
case PLUS_EXPR:
|
|
if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
|
|
break;
|
|
/* FALLTHRU */
|
|
case ARRAY_REF:
|
|
if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type1) && TYPE_PTROB_P (type2))
|
|
{
|
|
type1 = ptrdiff_type_node;
|
|
break;
|
|
}
|
|
if (TYPE_PTROB_P (type1) && INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type2))
|
|
{
|
|
type2 = ptrdiff_type_node;
|
|
break;
|
|
}
|
|
return;
|
|
|
|
/* 18For every pair of promoted integral types L and R, there exist candi-
|
|
date operator functions of the form
|
|
LR operator%(L, R);
|
|
LR operator&(L, R);
|
|
LR operator^(L, R);
|
|
LR operator|(L, R);
|
|
L operator<<(L, R);
|
|
L operator>>(L, R);
|
|
where LR is the result of the usual arithmetic conversions between
|
|
types L and R. */
|
|
|
|
case TRUNC_MOD_EXPR:
|
|
case BIT_AND_EXPR:
|
|
case BIT_IOR_EXPR:
|
|
case BIT_XOR_EXPR:
|
|
case LSHIFT_EXPR:
|
|
case RSHIFT_EXPR:
|
|
if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type1) && INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type2))
|
|
break;
|
|
return;
|
|
|
|
/* 19For every triple L, VQ, R), where L is an arithmetic or enumeration
|
|
type, VQ is either volatile or empty, and R is a promoted arithmetic
|
|
type, there exist candidate operator functions of the form
|
|
VQ L& operator=(VQ L&, R);
|
|
VQ L& operator*=(VQ L&, R);
|
|
VQ L& operator/=(VQ L&, R);
|
|
VQ L& operator+=(VQ L&, R);
|
|
VQ L& operator-=(VQ L&, R);
|
|
|
|
20For every pair T, VQ), where T is any type and VQ is either volatile
|
|
or empty, there exist candidate operator functions of the form
|
|
T*VQ& operator=(T*VQ&, T*);
|
|
|
|
21For every pair T, VQ), where T is a pointer to member type and VQ is
|
|
either volatile or empty, there exist candidate operator functions of
|
|
the form
|
|
VQ T& operator=(VQ T&, T);
|
|
|
|
22For every triple T, VQ, I), where T is a cv-qualified or cv-
|
|
unqualified complete object type, VQ is either volatile or empty, and
|
|
I is a promoted integral type, there exist candidate operator func-
|
|
tions of the form
|
|
T*VQ& operator+=(T*VQ&, I);
|
|
T*VQ& operator-=(T*VQ&, I);
|
|
|
|
23For every triple L, VQ, R), where L is an integral or enumeration
|
|
type, VQ is either volatile or empty, and R is a promoted integral
|
|
type, there exist candidate operator functions of the form
|
|
|
|
VQ L& operator%=(VQ L&, R);
|
|
VQ L& operator<<=(VQ L&, R);
|
|
VQ L& operator>>=(VQ L&, R);
|
|
VQ L& operator&=(VQ L&, R);
|
|
VQ L& operator^=(VQ L&, R);
|
|
VQ L& operator|=(VQ L&, R); */
|
|
|
|
case MODIFY_EXPR:
|
|
switch (code2)
|
|
{
|
|
case PLUS_EXPR:
|
|
case MINUS_EXPR:
|
|
if (TYPE_PTROB_P (type1) && INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type2))
|
|
{
|
|
type2 = ptrdiff_type_node;
|
|
break;
|
|
}
|
|
/* FALLTHRU */
|
|
case MULT_EXPR:
|
|
case TRUNC_DIV_EXPR:
|
|
if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
|
|
break;
|
|
return;
|
|
|
|
case TRUNC_MOD_EXPR:
|
|
case BIT_AND_EXPR:
|
|
case BIT_IOR_EXPR:
|
|
case BIT_XOR_EXPR:
|
|
case LSHIFT_EXPR:
|
|
case RSHIFT_EXPR:
|
|
if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type1) && INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type2))
|
|
break;
|
|
return;
|
|
|
|
case NOP_EXPR:
|
|
if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
|
|
break;
|
|
if ((TYPE_PTRMEMFUNC_P (type1) && TYPE_PTRMEMFUNC_P (type2))
|
|
|| (TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
|
|
|| (TYPE_PTRDATAMEM_P (type1) && TYPE_PTRDATAMEM_P (type2))
|
|
|| ((TYPE_PTRMEMFUNC_P (type1)
|
|
|| TYPE_PTR_P (type1))
|
|
&& null_ptr_cst_p (args[1])))
|
|
{
|
|
type2 = type1;
|
|
break;
|
|
}
|
|
return;
|
|
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
type1 = build_reference_type (type1);
|
|
break;
|
|
|
|
case COND_EXPR:
|
|
/* [over.built]
|
|
|
|
For every pair of promoted arithmetic types L and R, there
|
|
exist candidate operator functions of the form
|
|
|
|
LR operator?(bool, L, R);
|
|
|
|
where LR is the result of the usual arithmetic conversions
|
|
between types L and R.
|
|
|
|
For every type T, where T is a pointer or pointer-to-member
|
|
type, there exist candidate operator functions of the form T
|
|
operator?(bool, T, T); */
|
|
|
|
if (promoted_arithmetic_type_p (type1)
|
|
&& promoted_arithmetic_type_p (type2))
|
|
/* That's OK. */
|
|
break;
|
|
|
|
/* Otherwise, the types should be pointers. */
|
|
if (!TYPE_PTR_OR_PTRMEM_P (type1) || !TYPE_PTR_OR_PTRMEM_P (type2))
|
|
return;
|
|
|
|
/* We don't check that the two types are the same; the logic
|
|
below will actually create two candidates; one in which both
|
|
parameter types are TYPE1, and one in which both parameter
|
|
types are TYPE2. */
|
|
break;
|
|
|
|
case REALPART_EXPR:
|
|
case IMAGPART_EXPR:
|
|
if (ARITHMETIC_TYPE_P (type1))
|
|
break;
|
|
return;
|
|
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
|
|
/* Make sure we don't create builtin candidates with dependent types. */
|
|
bool u1 = uses_template_parms (type1);
|
|
bool u2 = type2 ? uses_template_parms (type2) : false;
|
|
if (u1 || u2)
|
|
{
|
|
/* Try to recover if one of the types is non-dependent. But if
|
|
there's only one type, there's nothing we can do. */
|
|
if (!type2)
|
|
return;
|
|
/* And we lose if both are dependent. */
|
|
if (u1 && u2)
|
|
return;
|
|
/* Or if they have different forms. */
|
|
if (TREE_CODE (type1) != TREE_CODE (type2))
|
|
return;
|
|
|
|
if (u1 && !u2)
|
|
type1 = type2;
|
|
else if (u2 && !u1)
|
|
type2 = type1;
|
|
}
|
|
|
|
/* If we're dealing with two pointer types or two enumeral types,
|
|
we need candidates for both of them. */
|
|
if (type2 && !same_type_p (type1, type2)
|
|
&& TREE_CODE (type1) == TREE_CODE (type2)
|
|
&& (TYPE_REF_P (type1)
|
|
|| (TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
|
|
|| (TYPE_PTRDATAMEM_P (type1) && TYPE_PTRDATAMEM_P (type2))
|
|
|| TYPE_PTRMEMFUNC_P (type1)
|
|
|| MAYBE_CLASS_TYPE_P (type1)
|
|
|| TREE_CODE (type1) == ENUMERAL_TYPE))
|
|
{
|
|
if (TYPE_PTR_OR_PTRMEM_P (type1))
|
|
{
|
|
tree cptype = composite_pointer_type (input_location,
|
|
type1, type2,
|
|
error_mark_node,
|
|
error_mark_node,
|
|
CPO_CONVERSION,
|
|
tf_none);
|
|
if (cptype != error_mark_node)
|
|
{
|
|
build_builtin_candidate
|
|
(candidates, fnname, cptype, cptype, args, argtypes,
|
|
flags, complain);
|
|
return;
|
|
}
|
|
}
|
|
|
|
build_builtin_candidate
|
|
(candidates, fnname, type1, type1, args, argtypes, flags, complain);
|
|
build_builtin_candidate
|
|
(candidates, fnname, type2, type2, args, argtypes, flags, complain);
|
|
return;
|
|
}
|
|
|
|
build_builtin_candidate
|
|
(candidates, fnname, type1, type2, args, argtypes, flags, complain);
|
|
}
|
|
|
|
tree
|
|
type_decays_to (tree type)
|
|
{
|
|
if (TREE_CODE (type) == ARRAY_TYPE)
|
|
return build_pointer_type (TREE_TYPE (type));
|
|
if (TREE_CODE (type) == FUNCTION_TYPE)
|
|
return build_pointer_type (type);
|
|
return type;
|
|
}
|
|
|
|
/* There are three conditions of builtin candidates:
|
|
|
|
1) bool-taking candidates. These are the same regardless of the input.
|
|
2) pointer-pair taking candidates. These are generated for each type
|
|
one of the input types converts to.
|
|
3) arithmetic candidates. According to the standard, we should generate
|
|
all of these, but I'm trying not to...
|
|
|
|
Here we generate a superset of the possible candidates for this particular
|
|
case. That is a subset of the full set the standard defines, plus some
|
|
other cases which the standard disallows. add_builtin_candidate will
|
|
filter out the invalid set. */
|
|
|
|
static void
|
|
add_builtin_candidates (struct z_candidate **candidates, enum tree_code code,
|
|
enum tree_code code2, tree fnname,
|
|
vec<tree, va_gc> *argv,
|
|
int flags, tsubst_flags_t complain)
|
|
{
|
|
int ref1;
|
|
int enum_p = 0;
|
|
tree type, argtypes[3], t;
|
|
/* TYPES[i] is the set of possible builtin-operator parameter types
|
|
we will consider for the Ith argument. */
|
|
vec<tree, va_gc> *types[2];
|
|
unsigned ix;
|
|
vec<tree, va_gc> &args = *argv;
|
|
unsigned len = args.length ();
|
|
|
|
for (unsigned i = 0; i < len; ++i)
|
|
{
|
|
if (args[i])
|
|
argtypes[i] = unlowered_expr_type (args[i]);
|
|
else
|
|
argtypes[i] = NULL_TREE;
|
|
}
|
|
|
|
switch (code)
|
|
{
|
|
/* 4 For every pair T, VQ), where T is an arithmetic or enumeration type,
|
|
and VQ is either volatile or empty, there exist candidate operator
|
|
functions of the form
|
|
VQ T& operator++(VQ T&); */
|
|
|
|
case POSTINCREMENT_EXPR:
|
|
case PREINCREMENT_EXPR:
|
|
case POSTDECREMENT_EXPR:
|
|
case PREDECREMENT_EXPR:
|
|
case MODIFY_EXPR:
|
|
ref1 = 1;
|
|
break;
|
|
|
|
/* 24There also exist candidate operator functions of the form
|
|
bool operator!(bool);
|
|
bool operator&&(bool, bool);
|
|
bool operator||(bool, bool); */
|
|
|
|
case TRUTH_NOT_EXPR:
|
|
build_builtin_candidate
|
|
(candidates, fnname, boolean_type_node,
|
|
NULL_TREE, args, argtypes, flags, complain);
|
|
return;
|
|
|
|
case TRUTH_ORIF_EXPR:
|
|
case TRUTH_ANDIF_EXPR:
|
|
build_builtin_candidate
|
|
(candidates, fnname, boolean_type_node,
|
|
boolean_type_node, args, argtypes, flags, complain);
|
|
return;
|
|
|
|
case ADDR_EXPR:
|
|
case COMPOUND_EXPR:
|
|
case COMPONENT_REF:
|
|
case CO_AWAIT_EXPR:
|
|
return;
|
|
|
|
case COND_EXPR:
|
|
case EQ_EXPR:
|
|
case NE_EXPR:
|
|
case LT_EXPR:
|
|
case LE_EXPR:
|
|
case GT_EXPR:
|
|
case GE_EXPR:
|
|
case SPACESHIP_EXPR:
|
|
enum_p = 1;
|
|
/* Fall through. */
|
|
|
|
default:
|
|
ref1 = 0;
|
|
}
|
|
|
|
types[0] = make_tree_vector ();
|
|
types[1] = make_tree_vector ();
|
|
|
|
if (len == 3)
|
|
len = 2;
|
|
for (unsigned i = 0; i < len; ++i)
|
|
{
|
|
if (MAYBE_CLASS_TYPE_P (argtypes[i]))
|
|
{
|
|
tree convs;
|
|
|
|
if (i == 0 && code == MODIFY_EXPR && code2 == NOP_EXPR)
|
|
return;
|
|
|
|
convs = lookup_conversions (argtypes[i]);
|
|
|
|
if (code == COND_EXPR)
|
|
{
|
|
if (lvalue_p (args[i]))
|
|
vec_safe_push (types[i], build_reference_type (argtypes[i]));
|
|
|
|
vec_safe_push (types[i], TYPE_MAIN_VARIANT (argtypes[i]));
|
|
}
|
|
|
|
else if (! convs)
|
|
return;
|
|
|
|
for (; convs; convs = TREE_CHAIN (convs))
|
|
{
|
|
type = TREE_TYPE (convs);
|
|
|
|
if (i == 0 && ref1
|
|
&& (!TYPE_REF_P (type)
|
|
|| CP_TYPE_CONST_P (TREE_TYPE (type))))
|
|
continue;
|
|
|
|
if (code == COND_EXPR && TYPE_REF_P (type))
|
|
vec_safe_push (types[i], type);
|
|
|
|
type = non_reference (type);
|
|
if (i != 0 || ! ref1)
|
|
{
|
|
type = cv_unqualified (type_decays_to (type));
|
|
if (enum_p && TREE_CODE (type) == ENUMERAL_TYPE)
|
|
vec_safe_push (types[i], type);
|
|
if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type))
|
|
type = type_promotes_to (type);
|
|
}
|
|
|
|
if (! vec_member (type, types[i]))
|
|
vec_safe_push (types[i], type);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (code == COND_EXPR && lvalue_p (args[i]))
|
|
vec_safe_push (types[i], build_reference_type (argtypes[i]));
|
|
type = non_reference (argtypes[i]);
|
|
if (i != 0 || ! ref1)
|
|
{
|
|
type = cv_unqualified (type_decays_to (type));
|
|
if (enum_p && UNSCOPED_ENUM_P (type))
|
|
vec_safe_push (types[i], type);
|
|
if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type))
|
|
type = type_promotes_to (type);
|
|
}
|
|
vec_safe_push (types[i], type);
|
|
}
|
|
}
|
|
|
|
/* Run through the possible parameter types of both arguments,
|
|
creating candidates with those parameter types. */
|
|
FOR_EACH_VEC_ELT_REVERSE (*(types[0]), ix, t)
|
|
{
|
|
unsigned jx;
|
|
tree u;
|
|
|
|
if (!types[1]->is_empty ())
|
|
FOR_EACH_VEC_ELT_REVERSE (*(types[1]), jx, u)
|
|
add_builtin_candidate
|
|
(candidates, code, code2, fnname, t,
|
|
u, args, argtypes, flags, complain);
|
|
else
|
|
add_builtin_candidate
|
|
(candidates, code, code2, fnname, t,
|
|
NULL_TREE, args, argtypes, flags, complain);
|
|
}
|
|
|
|
release_tree_vector (types[0]);
|
|
release_tree_vector (types[1]);
|
|
}
|
|
|
|
|
|
/* If TMPL can be successfully instantiated as indicated by
|
|
EXPLICIT_TARGS and ARGLIST, adds the instantiation to CANDIDATES.
|
|
|
|
TMPL is the template. EXPLICIT_TARGS are any explicit template
|
|
arguments. ARGLIST is the arguments provided at the call-site.
|
|
This does not change ARGLIST. The RETURN_TYPE is the desired type
|
|
for conversion operators. If OBJ is NULL_TREE, FLAGS and CTYPE are
|
|
as for add_function_candidate. If an OBJ is supplied, FLAGS and
|
|
CTYPE are ignored, and OBJ is as for add_conv_candidate.
|
|
|
|
SHORTCUT_BAD_CONVS is as in add_function_candidate. */
|
|
|
|
static struct z_candidate*
|
|
add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
|
|
tree ctype, tree explicit_targs, tree first_arg,
|
|
const vec<tree, va_gc> *arglist, tree return_type,
|
|
tree access_path, tree conversion_path,
|
|
int flags, tree obj, unification_kind_t strict,
|
|
bool shortcut_bad_convs, tsubst_flags_t complain)
|
|
{
|
|
int ntparms = DECL_NTPARMS (tmpl);
|
|
tree targs = make_tree_vec (ntparms);
|
|
unsigned int len = vec_safe_length (arglist);
|
|
unsigned int nargs = (first_arg == NULL_TREE ? 0 : 1) + len;
|
|
unsigned int skip_without_in_chrg = 0;
|
|
tree first_arg_without_in_chrg = first_arg;
|
|
tree *args_without_in_chrg;
|
|
unsigned int nargs_without_in_chrg;
|
|
unsigned int ia, ix;
|
|
tree arg;
|
|
struct z_candidate *cand;
|
|
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'. */
|
|
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tmpl))
|
|
{
|
|
if (first_arg_without_in_chrg != NULL_TREE)
|
|
first_arg_without_in_chrg = NULL_TREE;
|
|
else if (return_type && strict == DEDUCE_CALL)
|
|
/* We're deducing for a call to the result of a template conversion
|
|
function, so the args don't contain 'this'; leave them alone. */;
|
|
else
|
|
++skip_without_in_chrg;
|
|
}
|
|
|
|
if ((DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (tmpl)
|
|
|| DECL_BASE_CONSTRUCTOR_P (tmpl))
|
|
&& CLASSTYPE_VBASECLASSES (DECL_CONTEXT (tmpl)))
|
|
{
|
|
if (first_arg_without_in_chrg != NULL_TREE)
|
|
first_arg_without_in_chrg = NULL_TREE;
|
|
else
|
|
++skip_without_in_chrg;
|
|
}
|
|
|
|
if (len < skip_without_in_chrg)
|
|
return NULL;
|
|
|
|
if (DECL_CONSTRUCTOR_P (tmpl) && nargs == 2
|
|
&& same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (first_arg),
|
|
TREE_TYPE ((*arglist)[0])))
|
|
{
|
|
/* 12.8/6 says, "A declaration of a constructor for a class X is
|
|
ill-formed if its first parameter is of type (optionally cv-qualified)
|
|
X and either there are no other parameters or else all other
|
|
parameters have default arguments. A member function template is never
|
|
instantiated to produce such a constructor signature."
|
|
|
|
So if we're trying to copy an object of the containing class, don't
|
|
consider a template constructor that has a first parameter type that
|
|
is just a template parameter, as we would deduce a signature that we
|
|
would then reject in the code below. */
|
|
if (tree firstparm = FUNCTION_FIRST_USER_PARMTYPE (tmpl))
|
|
{
|
|
firstparm = TREE_VALUE (firstparm);
|
|
if (PACK_EXPANSION_P (firstparm))
|
|
firstparm = PACK_EXPANSION_PATTERN (firstparm);
|
|
if (TREE_CODE (firstparm) == TEMPLATE_TYPE_PARM)
|
|
{
|
|
gcc_assert (!explicit_targs);
|
|
reason = invalid_copy_with_fn_template_rejection ();
|
|
goto fail;
|
|
}
|
|
}
|
|
}
|
|
|
|
nargs_without_in_chrg = ((first_arg_without_in_chrg != NULL_TREE ? 1 : 0)
|
|
+ (len - skip_without_in_chrg));
|
|
args_without_in_chrg = XALLOCAVEC (tree, nargs_without_in_chrg);
|
|
ia = 0;
|
|
if (first_arg_without_in_chrg != NULL_TREE)
|
|
{
|
|
args_without_in_chrg[ia] = first_arg_without_in_chrg;
|
|
++ia;
|
|
}
|
|
for (ix = skip_without_in_chrg;
|
|
vec_safe_iterate (arglist, ix, &arg);
|
|
++ix)
|
|
{
|
|
args_without_in_chrg[ia] = arg;
|
|
++ia;
|
|
}
|
|
gcc_assert (ia == nargs_without_in_chrg);
|
|
|
|
if (!obj && explicit_targs)
|
|
{
|
|
/* Check that there's no obvious arity mismatch before proceeding with
|
|
deduction. This avoids substituting explicit template arguments
|
|
into the template (which could result in an error outside the
|
|
immediate context) when the resulting candidate would be unviable
|
|
anyway. */
|
|
int min_arity = 0, max_arity = 0;
|
|
tree parms = TYPE_ARG_TYPES (TREE_TYPE (tmpl));
|
|
parms = skip_artificial_parms_for (tmpl, parms);
|
|
for (; parms != void_list_node; parms = TREE_CHAIN (parms))
|
|
{
|
|
if (!parms || PACK_EXPANSION_P (TREE_VALUE (parms)))
|
|
{
|
|
max_arity = -1;
|
|
break;
|
|
}
|
|
if (TREE_PURPOSE (parms))
|
|
/* A parameter with a default argument. */
|
|
++max_arity;
|
|
else
|
|
++min_arity, ++max_arity;
|
|
}
|
|
if (ia < (unsigned)min_arity)
|
|
{
|
|
/* Too few arguments. */
|
|
reason = arity_rejection (NULL_TREE, min_arity, ia,
|
|
/*least_p=*/(max_arity == -1));
|
|
goto fail;
|
|
}
|
|
else if (max_arity != -1 && ia > (unsigned)max_arity)
|
|
{
|
|
/* Too many arguments. */
|
|
reason = arity_rejection (NULL_TREE, max_arity, ia);
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
errs = errorcount+sorrycount;
|
|
if (!obj)
|
|
{
|
|
convs = alloc_conversions (nargs);
|
|
|
|
if (shortcut_bad_convs
|
|
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (tmpl)
|
|
&& !DECL_CONSTRUCTOR_P (tmpl))
|
|
{
|
|
/* Check the 'this' conversion before proceeding with deduction.
|
|
This is effectively an extension of the DR 1391 resolution
|
|
that we perform in check_non_deducible_conversions, though it's
|
|
convenient to do this extra check here instead of there. */
|
|
tree parmtype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (tmpl)));
|
|
tree argtype = lvalue_type (first_arg);
|
|
tree arg = first_arg;
|
|
conversion *t = build_this_conversion (tmpl, ctype,
|
|
parmtype, argtype, arg,
|
|
flags, complain);
|
|
convs[0] = t;
|
|
if (t->bad_p)
|
|
{
|
|
reason = bad_arg_conversion_rejection (first_arg, 0,
|
|
arg, parmtype,
|
|
EXPR_LOCATION (arg));
|
|
goto fail;
|
|
}
|
|
}
|
|
}
|
|
fn = fn_type_unification (tmpl, explicit_targs, targs,
|
|
args_without_in_chrg,
|
|
nargs_without_in_chrg,
|
|
return_type, strict, flags, convs,
|
|
false, complain & tf_decltype);
|
|
|
|
if (fn == error_mark_node)
|
|
{
|
|
/* Don't repeat unification later if it already resulted in errors. */
|
|
if (errorcount+sorrycount == errs)
|
|
reason = template_unification_rejection (tmpl, explicit_targs,
|
|
targs, args_without_in_chrg,
|
|
nargs_without_in_chrg,
|
|
return_type, strict, flags);
|
|
else
|
|
reason = template_unification_error_rejection ();
|
|
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);
|
|
if (arg_types && same_type_p (TYPE_MAIN_VARIANT (TREE_VALUE (arg_types)),
|
|
ctype))
|
|
{
|
|
/* We're trying to produce a constructor with a prohibited signature,
|
|
as discussed above; handle here any cases we didn't catch then,
|
|
such as X(X<T>). */
|
|
reason = invalid_copy_with_fn_template_rejection ();
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
if (obj != NULL_TREE)
|
|
/* Aha, this is a conversion function. */
|
|
cand = add_conv_candidate (candidates, fn, obj, arglist,
|
|
access_path, conversion_path, complain);
|
|
else
|
|
cand = add_function_candidate (candidates, fn, ctype,
|
|
first_arg, arglist, access_path,
|
|
conversion_path, flags, convs,
|
|
shortcut_bad_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
|
|
an instantiation of the specialization, in which case the
|
|
DECL_TI_TEMPLATE field will point at the original
|
|
specialization. For example:
|
|
|
|
template <class T> struct S { template <class U> void f(U);
|
|
template <> void f(int) {}; };
|
|
S<double> sd;
|
|
sd.f(3);
|
|
|
|
Here, TMPL will be template <class U> S<double>::f(U).
|
|
And, instantiate template will give us the specialization
|
|
template <> S<double>::f(int). But, the DECL_TI_TEMPLATE field
|
|
for this will point at template <class T> template <> S<T>::f(int),
|
|
so that we can find the definition. For the purposes of
|
|
overload resolution, however, we want the original TMPL. */
|
|
cand->template_decl = build_template_info (tmpl, targs);
|
|
else
|
|
cand->template_decl = DECL_TEMPLATE_INFO (fn);
|
|
cand->explicit_targs = explicit_targs;
|
|
|
|
return cand;
|
|
fail:
|
|
int viable = (reason->code == rr_bad_arg_conversion ? -1 : 0);
|
|
return add_candidate (candidates, tmpl, first_arg, arglist, nargs, convs,
|
|
access_path, conversion_path, viable, reason, flags);
|
|
}
|
|
|
|
|
|
static struct z_candidate *
|
|
add_template_candidate (struct z_candidate **candidates, tree tmpl, tree ctype,
|
|
tree explicit_targs, tree first_arg,
|
|
const vec<tree, va_gc> *arglist, tree return_type,
|
|
tree access_path, tree conversion_path, int flags,
|
|
unification_kind_t strict, bool shortcut_bad_convs,
|
|
tsubst_flags_t complain)
|
|
{
|
|
return
|
|
add_template_candidate_real (candidates, tmpl, ctype,
|
|
explicit_targs, first_arg, arglist,
|
|
return_type, access_path, conversion_path,
|
|
flags, NULL_TREE, strict, shortcut_bad_convs,
|
|
complain);
|
|
}
|
|
|
|
/* Create an overload candidate for the conversion function template TMPL,
|
|
returning RETURN_TYPE, which will be invoked for expression OBJ to produce a
|
|
pointer-to-function which will in turn be called with the argument list
|
|
ARGLIST, and add it to CANDIDATES. This does not change ARGLIST. FLAGS is
|
|
passed on to implicit_conversion. */
|
|
|
|
static struct z_candidate *
|
|
add_template_conv_candidate (struct z_candidate **candidates, tree tmpl,
|
|
tree obj,
|
|
const vec<tree, va_gc> *arglist,
|
|
tree return_type, tree access_path,
|
|
tree conversion_path, tsubst_flags_t complain)
|
|
{
|
|
/* Making this work broke PR 71117 and 85118, so until the committee resolves
|
|
core issue 2189, let's disable this candidate if there are any call
|
|
operators. */
|
|
if (*candidates)
|
|
return NULL;
|
|
|
|
return
|
|
add_template_candidate_real (candidates, tmpl, NULL_TREE, NULL_TREE,
|
|
NULL_TREE, arglist, return_type, access_path,
|
|
conversion_path, 0, obj, DEDUCE_CALL,
|
|
/*shortcut_bad_convs=*/false, complain);
|
|
}
|
|
|
|
/* The CANDS are the set of candidates that were considered for
|
|
overload resolution. Return the set of viable candidates, or CANDS
|
|
if none are viable. If any of the candidates were viable, set
|
|
*ANY_VIABLE_P to true. STRICT_P is true if a candidate should be
|
|
considered viable only if it is strictly viable. */
|
|
|
|
static struct z_candidate*
|
|
splice_viable (struct z_candidate *cands,
|
|
bool strict_p,
|
|
bool *any_viable_p)
|
|
{
|
|
struct z_candidate *viable;
|
|
struct z_candidate **last_viable;
|
|
struct z_candidate **cand;
|
|
bool found_strictly_viable = false;
|
|
|
|
/* Be strict inside templates, since build_over_call won't actually
|
|
do the conversions to get pedwarns. */
|
|
if (processing_template_decl)
|
|
strict_p = true;
|
|
|
|
viable = NULL;
|
|
last_viable = &viable;
|
|
*any_viable_p = false;
|
|
|
|
cand = &cands;
|
|
while (*cand)
|
|
{
|
|
struct z_candidate *c = *cand;
|
|
if (!strict_p
|
|
&& (c->viable == 1 || TREE_CODE (c->fn) == TEMPLATE_DECL))
|
|
{
|
|
/* Be strict in the presence of a viable candidate. Also if
|
|
there are template candidates, so that we get deduction errors
|
|
for them instead of silently preferring a bad conversion. */
|
|
strict_p = true;
|
|
if (viable && !found_strictly_viable)
|
|
{
|
|
/* Put any spliced near matches back onto the main list so
|
|
that we see them if there is no strict match. */
|
|
*any_viable_p = false;
|
|
*last_viable = cands;
|
|
cands = viable;
|
|
viable = NULL;
|
|
last_viable = &viable;
|
|
}
|
|
}
|
|
|
|
if (strict_p ? c->viable == 1 : c->viable)
|
|
{
|
|
*last_viable = c;
|
|
*cand = c->next;
|
|
c->next = NULL;
|
|
last_viable = &c->next;
|
|
*any_viable_p = true;
|
|
if (c->viable == 1)
|
|
found_strictly_viable = true;
|
|
}
|
|
else
|
|
cand = &c->next;
|
|
}
|
|
|
|
return viable ? viable : cands;
|
|
}
|
|
|
|
static bool
|
|
any_strictly_viable (struct z_candidate *cands)
|
|
{
|
|
for (; cands; cands = cands->next)
|
|
if (cands->viable == 1)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/* OBJ is being used in an expression like "OBJ.f (...)". In other
|
|
words, it is about to become the "this" pointer for a member
|
|
function call. Take the address of the object. */
|
|
|
|
static tree
|
|
build_this (tree obj)
|
|
{
|
|
/* In a template, we are only concerned about the type of the
|
|
expression, so we can take a shortcut. */
|
|
if (processing_template_decl)
|
|
return build_address (obj);
|
|
|
|
return cp_build_addr_expr (obj, tf_warning_or_error);
|
|
}
|
|
|
|
/* Returns true iff functions are equivalent. Equivalent functions are
|
|
not '==' only if one is a function-local extern function or if
|
|
both are extern "C". */
|
|
|
|
static inline int
|
|
equal_functions (tree fn1, tree fn2)
|
|
{
|
|
if (TREE_CODE (fn1) != TREE_CODE (fn2))
|
|
return 0;
|
|
if (TREE_CODE (fn1) == TEMPLATE_DECL)
|
|
return fn1 == fn2;
|
|
if (DECL_LOCAL_DECL_P (fn1) || DECL_LOCAL_DECL_P (fn2)
|
|
|| DECL_EXTERN_C_FUNCTION_P (fn1))
|
|
return decls_match (fn1, fn2);
|
|
return fn1 == fn2;
|
|
}
|
|
|
|
/* Print information about a candidate FN being rejected due to INFO. */
|
|
|
|
static void
|
|
print_conversion_rejection (location_t loc, struct conversion_info *info,
|
|
tree fn)
|
|
{
|
|
tree from = info->from;
|
|
if (!TYPE_P (from))
|
|
from = lvalue_type (from);
|
|
if (info->n_arg == -1)
|
|
{
|
|
/* Conversion of implicit `this' argument failed. */
|
|
if (!TYPE_P (info->from))
|
|
/* A bad conversion for 'this' must be discarding cv-quals. */
|
|
inform (loc, " passing %qT as %<this%> "
|
|
"argument discards qualifiers",
|
|
from);
|
|
else
|
|
inform (loc, " no known conversion for implicit "
|
|
"%<this%> parameter from %qH to %qI",
|
|
from, info->to_type);
|
|
}
|
|
else if (!TYPE_P (info->from))
|
|
{
|
|
if (info->n_arg >= 0)
|
|
inform (loc, " conversion of argument %d would be ill-formed:",
|
|
info->n_arg + 1);
|
|
perform_implicit_conversion (info->to_type, info->from,
|
|
tf_warning_or_error);
|
|
}
|
|
else if (info->n_arg == -2)
|
|
/* Conversion of conversion function return value failed. */
|
|
inform (loc, " no known conversion from %qH to %qI",
|
|
from, info->to_type);
|
|
else
|
|
{
|
|
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
|
|
HAVE. */
|
|
|
|
static void
|
|
print_arity_information (location_t loc, unsigned int have, unsigned int want,
|
|
bool least_p)
|
|
{
|
|
if (least_p)
|
|
inform_n (loc, want,
|
|
" candidate expects at least %d argument, %d provided",
|
|
" candidate expects at least %d arguments, %d provided",
|
|
want, have);
|
|
else
|
|
inform_n (loc, want,
|
|
" candidate expects %d argument, %d provided",
|
|
" candidate expects %d arguments, %d provided",
|
|
want, have);
|
|
}
|
|
|
|
/* Print information about one overload candidate CANDIDATE. MSGSTR
|
|
is the text to print before the candidate itself.
|
|
|
|
NOTE: Unlike most diagnostic functions in GCC, MSGSTR is expected
|
|
to have been run through gettext by the caller. This wart makes
|
|
life simpler in print_z_candidates and for the translators. */
|
|
|
|
static void
|
|
print_z_candidate (location_t loc, const char *msgstr,
|
|
struct z_candidate *candidate)
|
|
{
|
|
const char *msg = (msgstr == NULL
|
|
? ""
|
|
: ACONCAT ((_(msgstr), " ", NULL)));
|
|
tree fn = candidate->fn;
|
|
if (flag_new_inheriting_ctors)
|
|
fn = strip_inheriting_ctors (fn);
|
|
location_t cloc = location_of (fn);
|
|
|
|
if (identifier_p (fn))
|
|
{
|
|
cloc = loc;
|
|
if (candidate->num_convs == 3)
|
|
inform (cloc, "%s%<%D(%T, %T, %T)%> (built-in)", msg, fn,
|
|
candidate->convs[0]->type,
|
|
candidate->convs[1]->type,
|
|
candidate->convs[2]->type);
|
|
else if (candidate->num_convs == 2)
|
|
inform (cloc, "%s%<%D(%T, %T)%> (built-in)", msg, fn,
|
|
candidate->convs[0]->type,
|
|
candidate->convs[1]->type);
|
|
else
|
|
inform (cloc, "%s%<%D(%T)%> (built-in)", msg, fn,
|
|
candidate->convs[0]->type);
|
|
}
|
|
else if (TYPE_P (fn))
|
|
inform (cloc, "%s%qT (conversion)", msg, fn);
|
|
else if (candidate->viable == -1)
|
|
inform (cloc, "%s%#qD (near match)", msg, fn);
|
|
else if (DECL_DELETED_FN (fn))
|
|
inform (cloc, "%s%#qD (deleted)", msg, fn);
|
|
else if (candidate->reversed ())
|
|
inform (cloc, "%s%#qD (reversed)", msg, fn);
|
|
else if (candidate->rewritten ())
|
|
inform (cloc, "%s%#qD (rewritten)", msg, fn);
|
|
else
|
|
inform (cloc, "%s%#qD", msg, fn);
|
|
if (fn != candidate->fn)
|
|
{
|
|
cloc = location_of (candidate->fn);
|
|
inform (cloc, " inherited here");
|
|
}
|
|
/* Give the user some information about why this candidate failed. */
|
|
if (candidate->reason != NULL)
|
|
{
|
|
struct rejection_reason *r = candidate->reason;
|
|
|
|
switch (r->code)
|
|
{
|
|
case rr_arity:
|
|
print_arity_information (cloc, r->u.arity.actual,
|
|
r->u.arity.expected,
|
|
r->u.arity.least_p);
|
|
break;
|
|
case rr_arg_conversion:
|
|
print_conversion_rejection (cloc, &r->u.conversion, fn);
|
|
break;
|
|
case rr_bad_arg_conversion:
|
|
print_conversion_rejection (cloc, &r->u.bad_conversion, fn);
|
|
break;
|
|
case rr_explicit_conversion:
|
|
inform (cloc, " return type %qT of explicit conversion function "
|
|
"cannot be converted to %qT with a qualification "
|
|
"conversion", r->u.conversion.from,
|
|
r->u.conversion.to_type);
|
|
break;
|
|
case rr_template_conversion:
|
|
inform (cloc, " conversion from return type %qT of template "
|
|
"conversion function specialization to %qT is not an "
|
|
"exact match", r->u.conversion.from,
|
|
r->u.conversion.to_type);
|
|
break;
|
|
case rr_template_unification:
|
|
/* We use template_unification_error_rejection if unification caused
|
|
actual non-SFINAE errors, in which case we don't need to repeat
|
|
them here. */
|
|
if (r->u.template_unification.tmpl == NULL_TREE)
|
|
{
|
|
inform (cloc, " substitution of deduced template arguments "
|
|
"resulted in errors seen above");
|
|
break;
|
|
}
|
|
/* Re-run template unification with diagnostics. */
|
|
inform (cloc, " template argument deduction/substitution failed:");
|
|
fn_type_unification (r->u.template_unification.tmpl,
|
|
r->u.template_unification.explicit_targs,
|
|
(make_tree_vec
|
|
(r->u.template_unification.num_targs)),
|
|
r->u.template_unification.args,
|
|
r->u.template_unification.nargs,
|
|
r->u.template_unification.return_type,
|
|
r->u.template_unification.strict,
|
|
r->u.template_unification.flags,
|
|
NULL, true, false);
|
|
break;
|
|
case rr_invalid_copy:
|
|
inform (cloc,
|
|
" a constructor taking a single argument of its own "
|
|
"class type is invalid");
|
|
break;
|
|
case rr_constraint_failure:
|
|
diagnose_constraints (cloc, fn, NULL_TREE);
|
|
break;
|
|
case rr_inherited_ctor:
|
|
inform (cloc, " an inherited constructor is not a candidate for "
|
|
"initialization from an expression of the same or derived "
|
|
"type");
|
|
break;
|
|
case rr_none:
|
|
default:
|
|
/* This candidate didn't have any issues or we failed to
|
|
handle a particular code. Either way... */
|
|
gcc_unreachable ();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
print_z_candidates (location_t loc, struct z_candidate *candidates)
|
|
{
|
|
struct z_candidate *cand1;
|
|
struct z_candidate **cand2;
|
|
|
|
if (!candidates)
|
|
return;
|
|
|
|
/* Remove non-viable deleted candidates. */
|
|
cand1 = candidates;
|
|
for (cand2 = &cand1; *cand2; )
|
|
{
|
|
if (TREE_CODE ((*cand2)->fn) == FUNCTION_DECL
|
|
&& !(*cand2)->viable
|
|
&& DECL_DELETED_FN ((*cand2)->fn))
|
|
*cand2 = (*cand2)->next;
|
|
else
|
|
cand2 = &(*cand2)->next;
|
|
}
|
|
/* ...if there are any non-deleted ones. */
|
|
if (cand1)
|
|
candidates = cand1;
|
|
|
|
/* There may be duplicates in the set of candidates. We put off
|
|
checking this condition as long as possible, since we have no way
|
|
to eliminate duplicates from a set of functions in less than n^2
|
|
time. Now we are about to emit an error message, so it is more
|
|
permissible to go slowly. */
|
|
for (cand1 = candidates; cand1; cand1 = cand1->next)
|
|
{
|
|
tree fn = cand1->fn;
|
|
/* Skip builtin candidates and conversion functions. */
|
|
if (!DECL_P (fn))
|
|
continue;
|
|
cand2 = &cand1->next;
|
|
while (*cand2)
|
|
{
|
|
if (DECL_P ((*cand2)->fn)
|
|
&& equal_functions (fn, (*cand2)->fn))
|
|
*cand2 = (*cand2)->next;
|
|
else
|
|
cand2 = &(*cand2)->next;
|
|
}
|
|
}
|
|
|
|
for (; candidates; candidates = candidates->next)
|
|
print_z_candidate (loc, N_("candidate:"), candidates);
|
|
}
|
|
|
|
/* USER_SEQ is a user-defined conversion sequence, beginning with a
|
|
USER_CONV. STD_SEQ is the standard conversion sequence applied to
|
|
the result of the conversion function to convert it to the final
|
|
desired type. Merge the two sequences into a single sequence,
|
|
and return the merged sequence. */
|
|
|
|
static conversion *
|
|
merge_conversion_sequences (conversion *user_seq, conversion *std_seq)
|
|
{
|
|
conversion **t;
|
|
bool bad = user_seq->bad_p;
|
|
|
|
gcc_assert (user_seq->kind == ck_user);
|
|
|
|
/* Find the end of the second conversion sequence. */
|
|
for (t = &std_seq; (*t)->kind != ck_identity; t = &((*t)->u.next))
|
|
{
|
|
/* The entire sequence is a user-conversion sequence. */
|
|
(*t)->user_conv_p = true;
|
|
if (bad)
|
|
(*t)->bad_p = true;
|
|
}
|
|
|
|
if ((*t)->rvaluedness_matches_p)
|
|
/* We're binding a reference directly to the result of the conversion.
|
|
build_user_type_conversion_1 stripped the REFERENCE_TYPE from the return
|
|
type, but we want it back. */
|
|
user_seq->type = TREE_TYPE (TREE_TYPE (user_seq->cand->fn));
|
|
|
|
/* Replace the identity conversion with the user conversion
|
|
sequence. */
|
|
*t = user_seq;
|
|
|
|
return std_seq;
|
|
}
|
|
|
|
/* Handle overload resolution for initializing an object of class type from
|
|
an initializer list. First we look for a suitable constructor that
|
|
takes a std::initializer_list; if we don't find one, we then look for a
|
|
non-list constructor.
|
|
|
|
Parameters are as for add_candidates, except that the arguments are in
|
|
the form of a CONSTRUCTOR (the initializer list) rather than a vector, and
|
|
the RETURN_TYPE parameter is replaced by TOTYPE, the desired type. */
|
|
|
|
static void
|
|
add_list_candidates (tree fns, tree first_arg,
|
|
const vec<tree, va_gc> *args, tree totype,
|
|
tree explicit_targs, bool template_only,
|
|
tree conversion_path, tree access_path,
|
|
int flags,
|
|
struct z_candidate **candidates,
|
|
tsubst_flags_t complain)
|
|
{
|
|
gcc_assert (*candidates == NULL);
|
|
|
|
/* We're looking for a ctor for list-initialization. */
|
|
flags |= LOOKUP_LIST_INIT_CTOR;
|
|
/* And we don't allow narrowing conversions. We also use this flag to
|
|
avoid the copy constructor call for copy-list-initialization. */
|
|
flags |= LOOKUP_NO_NARROWING;
|
|
|
|
unsigned nart = num_artificial_parms_for (OVL_FIRST (fns)) - 1;
|
|
tree init_list = (*args)[nart];
|
|
|
|
/* Always use the default constructor if the list is empty (DR 990). */
|
|
if (CONSTRUCTOR_NELTS (init_list) == 0
|
|
&& TYPE_HAS_DEFAULT_CONSTRUCTOR (totype))
|
|
;
|
|
/* If the class has a list ctor, try passing the list as a single
|
|
argument first, but only consider list ctors. */
|
|
else if (TYPE_HAS_LIST_CTOR (totype))
|
|
{
|
|
flags |= LOOKUP_LIST_ONLY;
|
|
add_candidates (fns, first_arg, args, NULL_TREE,
|
|
explicit_targs, template_only, conversion_path,
|
|
access_path, flags, candidates, complain);
|
|
if (any_strictly_viable (*candidates))
|
|
return;
|
|
}
|
|
else if (CONSTRUCTOR_IS_DESIGNATED_INIT (init_list)
|
|
&& !CP_AGGREGATE_TYPE_P (totype))
|
|
{
|
|
if (complain & tf_error)
|
|
error ("designated initializers cannot be used with a "
|
|
"non-aggregate type %qT", totype);
|
|
return;
|
|
}
|
|
|
|
/* Expand the CONSTRUCTOR into a new argument vec. */
|
|
vec<tree, va_gc> *new_args;
|
|
vec_alloc (new_args, nart + CONSTRUCTOR_NELTS (init_list));
|
|
for (unsigned i = 0; i < nart; ++i)
|
|
new_args->quick_push ((*args)[i]);
|
|
for (unsigned i = 0; i < CONSTRUCTOR_NELTS (init_list); ++i)
|
|
new_args->quick_push (CONSTRUCTOR_ELT (init_list, i)->value);
|
|
|
|
/* We aren't looking for list-ctors anymore. */
|
|
flags &= ~LOOKUP_LIST_ONLY;
|
|
/* We allow more user-defined conversions within an init-list. */
|
|
flags &= ~LOOKUP_NO_CONVERSION;
|
|
|
|
add_candidates (fns, first_arg, new_args, NULL_TREE,
|
|
explicit_targs, template_only, conversion_path,
|
|
access_path, flags, candidates, complain);
|
|
}
|
|
|
|
/* Returns the best overload candidate to perform the requested
|
|
conversion. This function is used for three the overloading situations
|
|
described in [over.match.copy], [over.match.conv], and [over.match.ref].
|
|
If TOTYPE is a REFERENCE_TYPE, we're trying to find a direct binding as
|
|
per [dcl.init.ref], so we ignore temporary bindings. */
|
|
|
|
static struct z_candidate *
|
|
build_user_type_conversion_1 (tree totype, tree expr, int flags,
|
|
tsubst_flags_t complain)
|
|
{
|
|
struct z_candidate *candidates, *cand;
|
|
tree fromtype;
|
|
tree ctors = NULL_TREE;
|
|
tree conv_fns = NULL_TREE;
|
|
conversion *conv = NULL;
|
|
tree first_arg = NULL_TREE;
|
|
vec<tree, va_gc> *args = NULL;
|
|
bool any_viable_p;
|
|
int convflags;
|
|
|
|
if (!expr)
|
|
return NULL;
|
|
|
|
fromtype = TREE_TYPE (expr);
|
|
|
|
/* We represent conversion within a hierarchy using RVALUE_CONV and
|
|
BASE_CONV, as specified by [over.best.ics]; these become plain
|
|
constructor calls, as specified in [dcl.init]. */
|
|
gcc_assert (!MAYBE_CLASS_TYPE_P (fromtype) || !MAYBE_CLASS_TYPE_P (totype)
|
|
|| !DERIVED_FROM_P (totype, fromtype));
|
|
|
|
if (CLASS_TYPE_P (totype))
|
|
/* Use lookup_fnfields_slot instead of lookup_fnfields to avoid
|
|
creating a garbage BASELINK; constructors can't be inherited. */
|
|
ctors = get_class_binding (totype, complete_ctor_identifier);
|
|
|
|
tree to_nonref = non_reference (totype);
|
|
if (MAYBE_CLASS_TYPE_P (fromtype))
|
|
{
|
|
if (same_type_ignoring_top_level_qualifiers_p (to_nonref, fromtype) ||
|
|
(CLASS_TYPE_P (to_nonref) && CLASS_TYPE_P (fromtype)
|
|
&& DERIVED_FROM_P (to_nonref, fromtype)))
|
|
{
|
|
/* [class.conv.fct] A conversion function is never used to
|
|
convert a (possibly cv-qualified) object to the (possibly
|
|
cv-qualified) same object type (or a reference to it), to a
|
|
(possibly cv-qualified) base class of that type (or a
|
|
reference to it)... */
|
|
}
|
|
else
|
|
conv_fns = lookup_conversions (fromtype);
|
|
}
|
|
|
|
candidates = 0;
|
|
flags |= LOOKUP_NO_CONVERSION;
|
|
if (BRACE_ENCLOSED_INITIALIZER_P (expr))
|
|
flags |= LOOKUP_NO_NARROWING;
|
|
/* Prevent add_candidates from treating a non-strictly viable candidate
|
|
as unviable. */
|
|
complain |= tf_conv;
|
|
|
|
/* It's OK to bind a temporary for converting constructor arguments, but
|
|
not in converting the return value of a conversion operator. */
|
|
convflags = ((flags & LOOKUP_NO_TEMP_BIND) | LOOKUP_NO_CONVERSION
|
|
| (flags & LOOKUP_NO_NARROWING));
|
|
flags &= ~LOOKUP_NO_TEMP_BIND;
|
|
|
|
if (ctors)
|
|
{
|
|
int ctorflags = flags;
|
|
|
|
first_arg = build_dummy_object (totype);
|
|
|
|
/* We should never try to call the abstract or base constructor
|
|
from here. */
|
|
gcc_assert (!DECL_HAS_IN_CHARGE_PARM_P (OVL_FIRST (ctors))
|
|
&& !DECL_HAS_VTT_PARM_P (OVL_FIRST (ctors)));
|
|
|
|
args = make_tree_vector_single (expr);
|
|
if (BRACE_ENCLOSED_INITIALIZER_P (expr))
|
|
{
|
|
/* List-initialization. */
|
|
add_list_candidates (ctors, first_arg, args, totype, NULL_TREE,
|
|
false, TYPE_BINFO (totype), TYPE_BINFO (totype),
|
|
ctorflags, &candidates, complain);
|
|
}
|
|
else
|
|
{
|
|
add_candidates (ctors, first_arg, args, NULL_TREE, NULL_TREE, false,
|
|
TYPE_BINFO (totype), TYPE_BINFO (totype),
|
|
ctorflags, &candidates, complain);
|
|
}
|
|
|
|
for (cand = candidates; cand; cand = cand->next)
|
|
{
|
|
cand->second_conv = build_identity_conv (totype, NULL_TREE);
|
|
|
|
/* If totype isn't a reference, and LOOKUP_ONLYCONVERTING is
|
|
set, then this is copy-initialization. In that case, "The
|
|
result of the call is then used to direct-initialize the
|
|
object that is the destination of the copy-initialization."
|
|
[dcl.init]
|
|
|
|
We represent this in the conversion sequence with an
|
|
rvalue conversion, which means a constructor call. */
|
|
if (!TYPE_REF_P (totype)
|
|
&& cxx_dialect < cxx17
|
|
&& (flags & LOOKUP_ONLYCONVERTING)
|
|
&& !(convflags & LOOKUP_NO_TEMP_BIND))
|
|
cand->second_conv
|
|
= build_conv (ck_rvalue, totype, cand->second_conv);
|
|
}
|
|
}
|
|
|
|
if (conv_fns)
|
|
{
|
|
if (BRACE_ENCLOSED_INITIALIZER_P (expr))
|
|
first_arg = CONSTRUCTOR_ELT (expr, 0)->value;
|
|
else
|
|
first_arg = expr;
|
|
}
|
|
|
|
for (; conv_fns; conv_fns = TREE_CHAIN (conv_fns))
|
|
{
|
|
tree conversion_path = TREE_PURPOSE (conv_fns);
|
|
struct z_candidate *old_candidates;
|
|
|
|
/* If LOOKUP_NO_CONVERSION, don't consider a conversion function that
|
|
would need an addional user-defined conversion, i.e. if the return
|
|
type differs in class-ness from the desired type. So we avoid
|
|
considering operator bool when calling a copy constructor.
|
|
|
|
This optimization avoids the failure in PR97600, and is allowed by
|
|
[temp.inst]/9: "If the function selected by overload resolution can be
|
|
determined without instantiating a class template definition, it is
|
|
unspecified whether that instantiation actually takes place." */
|
|
tree convtype = non_reference (TREE_TYPE (conv_fns));
|
|
if ((flags & LOOKUP_NO_CONVERSION)
|
|
&& !WILDCARD_TYPE_P (convtype)
|
|
&& (CLASS_TYPE_P (to_nonref)
|
|
!= CLASS_TYPE_P (convtype)))
|
|
continue;
|
|
|
|
/* If we are called to convert to a reference type, we are trying to
|
|
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 (TYPE_REF_P (totype))
|
|
convflags |= LOOKUP_NO_TEMP_BIND;
|
|
|
|
old_candidates = candidates;
|
|
add_candidates (TREE_VALUE (conv_fns), first_arg, NULL, totype,
|
|
NULL_TREE, false,
|
|
conversion_path, TYPE_BINFO (fromtype),
|
|
flags, &candidates, complain);
|
|
|
|
for (cand = candidates; cand != old_candidates; cand = cand->next)
|
|
{
|
|
if (cand->viable == 0)
|
|
/* Already rejected, don't change to -1. */
|
|
continue;
|
|
|
|
tree rettype = TREE_TYPE (TREE_TYPE (cand->fn));
|
|
conversion *ics
|
|
= implicit_conversion (totype,
|
|
rettype,
|
|
0,
|
|
/*c_cast_p=*/false, convflags,
|
|
complain);
|
|
|
|
/* If LOOKUP_NO_TEMP_BIND isn't set, then this is
|
|
copy-initialization. In that case, "The result of the
|
|
call is then used to direct-initialize the object that is
|
|
the destination of the copy-initialization." [dcl.init]
|
|
|
|
We represent this in the conversion sequence with an
|
|
rvalue conversion, which means a constructor call. But
|
|
don't add a second rvalue conversion if there's already
|
|
one there. Which there really shouldn't be, but it's
|
|
harmless since we'd add it here anyway. */
|
|
if (ics && MAYBE_CLASS_TYPE_P (totype) && ics->kind != ck_rvalue
|
|
&& !(convflags & LOOKUP_NO_TEMP_BIND))
|
|
ics = build_conv (ck_rvalue, totype, ics);
|
|
|
|
cand->second_conv = ics;
|
|
|
|
if (!ics)
|
|
{
|
|
cand->viable = 0;
|
|
cand->reason = arg_conversion_rejection (NULL_TREE, -2,
|
|
rettype, totype,
|
|
EXPR_LOCATION (expr));
|
|
}
|
|
else if (TYPE_REF_P (totype) && !ics->rvaluedness_matches_p
|
|
/* Limit this to non-templates for now (PR90546). */
|
|
&& !cand->template_decl
|
|
&& TREE_CODE (TREE_TYPE (totype)) != FUNCTION_TYPE)
|
|
{
|
|
/* If we are called to convert to a reference type, we are trying
|
|
to find a direct binding per [over.match.ref], so rvaluedness
|
|
must match for non-functions. */
|
|
cand->viable = 0;
|
|
}
|
|
else if (DECL_NONCONVERTING_P (cand->fn)
|
|
&& ics->rank > cr_exact)
|
|
{
|
|
/* 13.3.1.5: For direct-initialization, those explicit
|
|
conversion functions that are not hidden within S and
|
|
yield type T or a type that can be converted to type T
|
|
with a qualification conversion (4.4) are also candidate
|
|
functions. */
|
|
/* 13.3.1.6 doesn't have a parallel restriction, but it should;
|
|
I've raised this issue with the committee. --jason 9/2011 */
|
|
cand->viable = -1;
|
|
cand->reason = explicit_conversion_rejection (rettype, totype);
|
|
}
|
|
else if (cand->viable == 1 && ics->bad_p)
|
|
{
|
|
cand->viable = -1;
|
|
cand->reason
|
|
= bad_arg_conversion_rejection (NULL_TREE, -2,
|
|
rettype, totype,
|
|
EXPR_LOCATION (expr));
|
|
}
|
|
else if (primary_template_specialization_p (cand->fn)
|
|
&& ics->rank > cr_exact)
|
|
{
|
|
/* 13.3.3.1.2: If the user-defined conversion is specified by
|
|
a specialization of a conversion function template, the
|
|
second standard conversion sequence shall have exact match
|
|
rank. */
|
|
cand->viable = -1;
|
|
cand->reason = template_conversion_rejection (rettype, totype);
|
|
}
|
|
}
|
|
}
|
|
|
|
candidates = splice_viable (candidates, false, &any_viable_p);
|
|
if (!any_viable_p)
|
|
{
|
|
if (args)
|
|
release_tree_vector (args);
|
|
return NULL;
|
|
}
|
|
|
|
cand = tourney (candidates, complain);
|
|
if (cand == NULL)
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
auto_diagnostic_group d;
|
|
error_at (cp_expr_loc_or_input_loc (expr),
|
|
"conversion from %qH to %qI is ambiguous",
|
|
fromtype, totype);
|
|
print_z_candidates (location_of (expr), candidates);
|
|
}
|
|
|
|
cand = candidates; /* any one will do */
|
|
cand->second_conv = build_ambiguous_conv (totype, expr);
|
|
cand->second_conv->user_conv_p = true;
|
|
if (!any_strictly_viable (candidates))
|
|
cand->second_conv->bad_p = true;
|
|
if (flags & LOOKUP_ONLYCONVERTING)
|
|
cand->second_conv->need_temporary_p = true;
|
|
/* If there are viable candidates, don't set ICS_BAD_FLAG; an
|
|
ambiguous conversion is no worse than another user-defined
|
|
conversion. */
|
|
|
|
return cand;
|
|
}
|
|
|
|
tree convtype;
|
|
if (!DECL_CONSTRUCTOR_P (cand->fn))
|
|
convtype = non_reference (TREE_TYPE (TREE_TYPE (cand->fn)));
|
|
else if (cand->second_conv->kind == ck_rvalue)
|
|
/* DR 5: [in the first step of copy-initialization]...if the function
|
|
is a constructor, the call initializes a temporary of the
|
|
cv-unqualified version of the destination type. */
|
|
convtype = cv_unqualified (totype);
|
|
else
|
|
convtype = totype;
|
|
/* Build the user conversion sequence. */
|
|
conv = build_conv
|
|
(ck_user,
|
|
convtype,
|
|
build_identity_conv (TREE_TYPE (expr), expr));
|
|
conv->cand = cand;
|
|
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;
|
|
|
|
/* Combine it with the second conversion sequence. */
|
|
cand->second_conv = merge_conversion_sequences (conv,
|
|
cand->second_conv);
|
|
|
|
return cand;
|
|
}
|
|
|
|
/* Wrapper for above. */
|
|
|
|
tree
|
|
build_user_type_conversion (tree totype, tree expr, int flags,
|
|
tsubst_flags_t complain)
|
|
{
|
|
struct z_candidate *cand;
|
|
tree ret;
|
|
|
|
auto_cond_timevar tv (TV_OVERLOAD);
|
|
cand = build_user_type_conversion_1 (totype, expr, flags, complain);
|
|
|
|
if (cand)
|
|
{
|
|
if (cand->second_conv->kind == ck_ambig)
|
|
ret = error_mark_node;
|
|
else
|
|
{
|
|
expr = convert_like (cand->second_conv, expr, complain);
|
|
ret = convert_from_reference (expr);
|
|
}
|
|
}
|
|
else
|
|
ret = NULL_TREE;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Give a helpful diagnostic when implicit_conversion fails. */
|
|
|
|
static void
|
|
implicit_conversion_error (location_t loc, tree type, tree expr)
|
|
{
|
|
tsubst_flags_t complain = tf_warning_or_error;
|
|
|
|
/* If expr has unknown type, then it is an overloaded function.
|
|
Call instantiate_type to get good error messages. */
|
|
if (TREE_TYPE (expr) == unknown_type_node)
|
|
instantiate_type (type, expr, complain);
|
|
else if (invalid_nonstatic_memfn_p (loc, expr, complain))
|
|
/* We gave an error. */;
|
|
else if (BRACE_ENCLOSED_INITIALIZER_P (expr)
|
|
&& CONSTRUCTOR_IS_DESIGNATED_INIT (expr)
|
|
&& !CP_AGGREGATE_TYPE_P (type))
|
|
error_at (loc, "designated initializers cannot be used with a "
|
|
"non-aggregate type %qT", type);
|
|
else
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
/* Worker for build_converted_constant_expr. */
|
|
|
|
static tree
|
|
build_converted_constant_expr_internal (tree type, tree expr,
|
|
int flags, tsubst_flags_t complain)
|
|
{
|
|
conversion *conv;
|
|
void *p;
|
|
tree t;
|
|
location_t loc = cp_expr_loc_or_input_loc (expr);
|
|
|
|
if (error_operand_p (expr))
|
|
return error_mark_node;
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
p = conversion_obstack_alloc (0);
|
|
|
|
conv = implicit_conversion (type, TREE_TYPE (expr), expr,
|
|
/*c_cast_p=*/false, flags, complain);
|
|
|
|
/* A converted constant expression of type T is an expression, implicitly
|
|
converted to type T, where the converted expression is a constant
|
|
expression and the implicit conversion sequence contains only
|
|
|
|
* user-defined conversions,
|
|
* lvalue-to-rvalue conversions (7.1),
|
|
* array-to-pointer conversions (7.2),
|
|
* function-to-pointer conversions (7.3),
|
|
* qualification conversions (7.5),
|
|
* integral promotions (7.6),
|
|
* integral conversions (7.8) other than narrowing conversions (11.6.4),
|
|
* null pointer conversions (7.11) from std::nullptr_t,
|
|
* null member pointer conversions (7.12) from std::nullptr_t, and
|
|
* function pointer conversions (7.13),
|
|
|
|
and where the reference binding (if any) binds directly. */
|
|
|
|
for (conversion *c = conv;
|
|
c && c->kind != ck_identity;
|
|
c = next_conversion (c))
|
|
{
|
|
switch (c->kind)
|
|
{
|
|
/* A conversion function is OK. If it isn't constexpr, we'll
|
|
complain later that the argument isn't constant. */
|
|
case ck_user:
|
|
/* List-initialization is OK. */
|
|
case ck_aggr:
|
|
/* The lvalue-to-rvalue conversion is OK. */
|
|
case ck_rvalue:
|
|
/* Array-to-pointer and function-to-pointer. */
|
|
case ck_lvalue:
|
|
/* Function pointer conversions. */
|
|
case ck_fnptr:
|
|
/* Qualification conversions. */
|
|
case ck_qual:
|
|
break;
|
|
|
|
case ck_ref_bind:
|
|
if (c->need_temporary_p)
|
|
{
|
|
if (complain & tf_error)
|
|
error_at (loc, "initializing %qH with %qI in converted "
|
|
"constant expression does not bind directly",
|
|
type, next_conversion (c)->type);
|
|
conv = NULL;
|
|
}
|
|
break;
|
|
|
|
case ck_base:
|
|
case ck_pmem:
|
|
case ck_ptr:
|
|
case ck_std:
|
|
t = next_conversion (c)->type;
|
|
if (INTEGRAL_OR_ENUMERATION_TYPE_P (t)
|
|
&& INTEGRAL_OR_ENUMERATION_TYPE_P (type))
|
|
/* Integral promotion or conversion. */
|
|
break;
|
|
if (NULLPTR_TYPE_P (t))
|
|
/* Conversion from nullptr to pointer or pointer-to-member. */
|
|
break;
|
|
|
|
if (complain & tf_error)
|
|
error_at (loc, "conversion from %qH to %qI in a "
|
|
"converted constant expression", t, type);
|
|
/* fall through. */
|
|
|
|
default:
|
|
conv = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Avoid confusing convert_nontype_argument by introducing
|
|
a redundant conversion to the same reference type. */
|
|
if (conv && conv->kind == ck_ref_bind
|
|
&& REFERENCE_REF_P (expr))
|
|
{
|
|
tree ref = TREE_OPERAND (expr, 0);
|
|
if (same_type_p (type, TREE_TYPE (ref)))
|
|
return ref;
|
|
}
|
|
|
|
if (conv)
|
|
{
|
|
/* Don't copy a class in a template. */
|
|
if (CLASS_TYPE_P (type) && conv->kind == ck_rvalue
|
|
&& processing_template_decl)
|
|
conv = next_conversion (conv);
|
|
|
|
/* Issuing conversion warnings for value-dependent expressions is
|
|
likely too noisy. */
|
|
warning_sentinel w (warn_conversion);
|
|
conv->check_narrowing = true;
|
|
conv->check_narrowing_const_only = true;
|
|
expr = convert_like (conv, expr, complain);
|
|
}
|
|
else
|
|
{
|
|
if (complain & tf_error)
|
|
implicit_conversion_error (loc, type, expr);
|
|
expr = error_mark_node;
|
|
}
|
|
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
return expr;
|
|
}
|
|
|
|
/* Subroutine of convert_nontype_argument.
|
|
|
|
EXPR is an expression used in a context that requires a converted
|
|
constant-expression, such as a template non-type parameter. Do any
|
|
necessary conversions (that are permitted for converted
|
|
constant-expressions) to convert it to the desired type.
|
|
|
|
This function doesn't consider explicit conversion functions. If
|
|
you mean to use "a contextually converted constant expression of type
|
|
bool", use build_converted_constant_bool_expr.
|
|
|
|
If conversion is successful, returns the converted expression;
|
|
otherwise, returns error_mark_node. */
|
|
|
|
tree
|
|
build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
|
|
{
|
|
return build_converted_constant_expr_internal (type, expr, LOOKUP_IMPLICIT,
|
|
complain);
|
|
}
|
|
|
|
/* Used to create "a contextually converted constant expression of type
|
|
bool". This differs from build_converted_constant_expr in that it
|
|
also considers explicit conversion functions. */
|
|
|
|
tree
|
|
build_converted_constant_bool_expr (tree expr, tsubst_flags_t complain)
|
|
{
|
|
return build_converted_constant_expr_internal (boolean_type_node, expr,
|
|
LOOKUP_NORMAL, complain);
|
|
}
|
|
|
|
/* Do any initial processing on the arguments to a function call. */
|
|
|
|
vec<tree, va_gc> *
|
|
resolve_args (vec<tree, va_gc> *args, tsubst_flags_t complain)
|
|
{
|
|
unsigned int ix;
|
|
tree arg;
|
|
|
|
FOR_EACH_VEC_SAFE_ELT (args, ix, arg)
|
|
{
|
|
if (error_operand_p (arg))
|
|
return NULL;
|
|
else if (VOID_TYPE_P (TREE_TYPE (arg)))
|
|
{
|
|
if (complain & tf_error)
|
|
error_at (cp_expr_loc_or_input_loc (arg),
|
|
"invalid use of void expression");
|
|
return NULL;
|
|
}
|
|
else if (invalid_nonstatic_memfn_p (EXPR_LOCATION (arg), arg, complain))
|
|
return NULL;
|
|
|
|
/* Force auto deduction now. Omit tf_warning to avoid redundant
|
|
deprecated warning on deprecated-14.C. */
|
|
if (!mark_single_function (arg, complain & ~tf_warning))
|
|
return NULL;
|
|
}
|
|
return args;
|
|
}
|
|
|
|
/* Perform overload resolution on FN, which is called with the ARGS.
|
|
|
|
Return the candidate function selected by overload resolution, or
|
|
NULL if the event that overload resolution failed. In the case
|
|
that overload resolution fails, *CANDIDATES will be the set of
|
|
candidates considered, and ANY_VIABLE_P will be set to true or
|
|
false to indicate whether or not any of the candidates were
|
|
viable.
|
|
|
|
The ARGS should already have gone through RESOLVE_ARGS before this
|
|
function is called. */
|
|
|
|
static struct z_candidate *
|
|
perform_overload_resolution (tree fn,
|
|
const vec<tree, va_gc> *args,
|
|
struct z_candidate **candidates,
|
|
bool *any_viable_p, tsubst_flags_t complain)
|
|
{
|
|
struct z_candidate *cand;
|
|
tree explicit_targs;
|
|
int template_only;
|
|
|
|
auto_cond_timevar tv (TV_OVERLOAD);
|
|
|
|
explicit_targs = NULL_TREE;
|
|
template_only = 0;
|
|
|
|
*candidates = NULL;
|
|
*any_viable_p = true;
|
|
|
|
/* Check FN. */
|
|
gcc_assert (OVL_P (fn) || TREE_CODE (fn) == TEMPLATE_ID_EXPR);
|
|
|
|
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
|
|
{
|
|
explicit_targs = TREE_OPERAND (fn, 1);
|
|
fn = TREE_OPERAND (fn, 0);
|
|
template_only = 1;
|
|
}
|
|
|
|
/* Add the various candidate functions. */
|
|
add_candidates (fn, NULL_TREE, args, NULL_TREE,
|
|
explicit_targs, template_only,
|
|
/*conversion_path=*/NULL_TREE,
|
|
/*access_path=*/NULL_TREE,
|
|
LOOKUP_NORMAL,
|
|
candidates, complain);
|
|
|
|
*candidates = splice_viable (*candidates, false, any_viable_p);
|
|
if (*any_viable_p)
|
|
cand = tourney (*candidates, complain);
|
|
else
|
|
cand = NULL;
|
|
|
|
return cand;
|
|
}
|
|
|
|
/* Print an error message about being unable to build a call to FN with
|
|
ARGS. ANY_VIABLE_P indicates whether any candidate functions could
|
|
be located; CANDIDATES is a possibly empty list of such
|
|
functions. */
|
|
|
|
static void
|
|
print_error_for_call_failure (tree fn, const vec<tree, va_gc> *args,
|
|
struct z_candidate *candidates)
|
|
{
|
|
tree targs = NULL_TREE;
|
|
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
|
|
{
|
|
targs = TREE_OPERAND (fn, 1);
|
|
fn = TREE_OPERAND (fn, 0);
|
|
}
|
|
tree name = OVL_NAME (fn);
|
|
location_t loc = location_of (name);
|
|
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));
|
|
else
|
|
error_at (loc, "call of overloaded %<%D(%A)%> is ambiguous",
|
|
name, build_tree_list_vec (args));
|
|
if (candidates)
|
|
print_z_candidates (loc, candidates);
|
|
}
|
|
|
|
/* Perform overload resolution on the set of deduction guides DGUIDES
|
|
using ARGS. Returns the selected deduction guide, or error_mark_node
|
|
if overload resolution fails. */
|
|
|
|
tree
|
|
perform_dguide_overload_resolution (tree dguides, const vec<tree, va_gc> *args,
|
|
tsubst_flags_t complain)
|
|
{
|
|
z_candidate *candidates;
|
|
bool any_viable_p;
|
|
tree result;
|
|
|
|
gcc_assert (deduction_guide_p (OVL_FIRST (dguides)));
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
void *p = conversion_obstack_alloc (0);
|
|
|
|
z_candidate *cand = perform_overload_resolution (dguides, args, &candidates,
|
|
&any_viable_p, complain);
|
|
if (!cand)
|
|
{
|
|
if (complain & tf_error)
|
|
print_error_for_call_failure (dguides, args, candidates);
|
|
result = error_mark_node;
|
|
}
|
|
else
|
|
result = cand->fn;
|
|
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
return result;
|
|
}
|
|
|
|
/* Return an expression for a call to FN (a namespace-scope function,
|
|
or a static member function) with the ARGS. This may change
|
|
ARGS. */
|
|
|
|
tree
|
|
build_new_function_call (tree fn, vec<tree, va_gc> **args,
|
|
tsubst_flags_t complain)
|
|
{
|
|
struct z_candidate *candidates, *cand;
|
|
bool any_viable_p;
|
|
void *p;
|
|
tree result;
|
|
|
|
if (args != NULL && *args != NULL)
|
|
{
|
|
*args = resolve_args (*args, complain);
|
|
if (*args == NULL)
|
|
return error_mark_node;
|
|
}
|
|
|
|
if (flag_tm)
|
|
tm_malloc_replacement (fn);
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
p = conversion_obstack_alloc (0);
|
|
|
|
cand = perform_overload_resolution (fn, *args, &candidates, &any_viable_p,
|
|
complain);
|
|
|
|
if (!cand)
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
// If there is a single (non-viable) function candidate,
|
|
// let the error be diagnosed by cp_build_function_call_vec.
|
|
if (!any_viable_p && candidates && ! candidates->next
|
|
&& (TREE_CODE (candidates->fn) == FUNCTION_DECL))
|
|
return cp_build_function_call_vec (candidates->fn, args, complain);
|
|
|
|
// Otherwise, emit notes for non-viable candidates.
|
|
print_error_for_call_failure (fn, *args, candidates);
|
|
}
|
|
result = error_mark_node;
|
|
}
|
|
else
|
|
{
|
|
result = build_over_call (cand, LOOKUP_NORMAL, complain);
|
|
}
|
|
|
|
if (flag_coroutines
|
|
&& result
|
|
&& TREE_CODE (result) == CALL_EXPR
|
|
&& DECL_BUILT_IN_CLASS (TREE_OPERAND (CALL_EXPR_FN (result), 0))
|
|
== BUILT_IN_NORMAL)
|
|
result = coro_validate_builtin_call (result);
|
|
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
return result;
|
|
}
|
|
|
|
/* Build a call to a global operator new. FNNAME is the name of the
|
|
operator (either "operator new" or "operator new[]") and ARGS are
|
|
the arguments provided. This may change ARGS. *SIZE points to the
|
|
total number of bytes required by the allocation, and is updated if
|
|
that is changed here. *COOKIE_SIZE is non-NULL if a cookie should
|
|
be used. If this function determines that no cookie should be
|
|
used, after all, *COOKIE_SIZE is set to NULL_TREE. If SIZE_CHECK
|
|
is not NULL_TREE, it is evaluated before calculating the final
|
|
array size, and if it fails, the array size is replaced with
|
|
(size_t)-1 (usually triggering a std::bad_alloc exception). If FN
|
|
is non-NULL, it will be set, upon return, to the allocation
|
|
function called. */
|
|
|
|
tree
|
|
build_operator_new_call (tree fnname, vec<tree, va_gc> **args,
|
|
tree *size, tree *cookie_size,
|
|
tree align_arg, tree size_check,
|
|
tree *fn, tsubst_flags_t complain)
|
|
{
|
|
tree original_size = *size;
|
|
tree fns;
|
|
struct z_candidate *candidates;
|
|
struct z_candidate *cand = NULL;
|
|
bool any_viable_p;
|
|
|
|
if (fn)
|
|
*fn = NULL_TREE;
|
|
/* Set to (size_t)-1 if the size check fails. */
|
|
if (size_check != NULL_TREE)
|
|
{
|
|
tree errval = TYPE_MAX_VALUE (sizetype);
|
|
if (cxx_dialect >= cxx11 && flag_exceptions)
|
|
errval = throw_bad_array_new_length ();
|
|
*size = fold_build3 (COND_EXPR, sizetype, size_check,
|
|
original_size, errval);
|
|
}
|
|
vec_safe_insert (*args, 0, *size);
|
|
*args = resolve_args (*args, complain);
|
|
if (*args == NULL)
|
|
return error_mark_node;
|
|
|
|
/* Based on:
|
|
|
|
[expr.new]
|
|
|
|
If this lookup fails to find the name, or if the allocated type
|
|
is not a class type, the allocation function's name is looked
|
|
up in the global scope.
|
|
|
|
we disregard block-scope declarations of "operator new". */
|
|
fns = lookup_qualified_name (global_namespace, fnname);
|
|
|
|
if (align_arg)
|
|
{
|
|
vec<tree, va_gc>* align_args
|
|
= vec_copy_and_insert (*args, align_arg, 1);
|
|
cand = perform_overload_resolution (fns, align_args, &candidates,
|
|
&any_viable_p, tf_none);
|
|
if (cand)
|
|
*args = align_args;
|
|
/* If no aligned allocation function matches, try again without the
|
|
alignment. */
|
|
}
|
|
|
|
/* Figure out what function is being called. */
|
|
if (!cand)
|
|
cand = perform_overload_resolution (fns, *args, &candidates, &any_viable_p,
|
|
complain);
|
|
|
|
/* If no suitable function could be found, issue an error message
|
|
and give up. */
|
|
if (!cand)
|
|
{
|
|
if (complain & tf_error)
|
|
print_error_for_call_failure (fns, *args, candidates);
|
|
return error_mark_node;
|
|
}
|
|
|
|
/* If a cookie is required, add some extra space. Whether
|
|
or not a cookie is required cannot be determined until
|
|
after we know which function was called. */
|
|
if (*cookie_size)
|
|
{
|
|
bool use_cookie = true;
|
|
tree arg_types;
|
|
|
|
arg_types = TYPE_ARG_TYPES (TREE_TYPE (cand->fn));
|
|
/* Skip the size_t parameter. */
|
|
arg_types = TREE_CHAIN (arg_types);
|
|
/* Check the remaining parameters (if any). */
|
|
if (arg_types
|
|
&& TREE_CHAIN (arg_types) == void_list_node
|
|
&& same_type_p (TREE_VALUE (arg_types),
|
|
ptr_type_node))
|
|
use_cookie = false;
|
|
/* If we need a cookie, adjust the number of bytes allocated. */
|
|
if (use_cookie)
|
|
{
|
|
/* Update the total size. */
|
|
*size = size_binop (PLUS_EXPR, original_size, *cookie_size);
|
|
if (size_check)
|
|
{
|
|
/* Set to (size_t)-1 if the size check fails. */
|
|
gcc_assert (size_check != NULL_TREE);
|
|
*size = fold_build3 (COND_EXPR, sizetype, size_check,
|
|
*size, TYPE_MAX_VALUE (sizetype));
|
|
}
|
|
/* Update the argument list to reflect the adjusted size. */
|
|
(**args)[0] = *size;
|
|
}
|
|
else
|
|
*cookie_size = NULL_TREE;
|
|
}
|
|
|
|
/* Tell our caller which function we decided to call. */
|
|
if (fn)
|
|
*fn = cand->fn;
|
|
|
|
/* Build the CALL_EXPR. */
|
|
tree ret = build_over_call (cand, LOOKUP_NORMAL, complain);
|
|
|
|
/* Set this flag for all callers of this function. In addition to
|
|
new-expressions, this is called for allocating coroutine state; treat
|
|
that as an implicit new-expression. */
|
|
tree call = extract_call_expr (ret);
|
|
if (TREE_CODE (call) == CALL_EXPR)
|
|
CALL_FROM_NEW_OR_DELETE_P (call) = 1;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Build a new call to operator(). This may change ARGS. */
|
|
|
|
tree
|
|
build_op_call (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
|
|
{
|
|
struct z_candidate *candidates = 0, *cand;
|
|
tree fns, convs, first_mem_arg = NULL_TREE;
|
|
bool any_viable_p;
|
|
tree result = NULL_TREE;
|
|
void *p;
|
|
|
|
auto_cond_timevar tv (TV_OVERLOAD);
|
|
|
|
obj = mark_lvalue_use (obj);
|
|
|
|
if (error_operand_p (obj))
|
|
return error_mark_node;
|
|
|
|
tree type = TREE_TYPE (obj);
|
|
|
|
obj = prep_operand (obj);
|
|
|
|
if (TYPE_PTRMEMFUNC_P (type))
|
|
{
|
|
if (complain & tf_error)
|
|
/* It's no good looking for an overloaded operator() on a
|
|
pointer-to-member-function. */
|
|
error ("pointer-to-member function %qE cannot be called without "
|
|
"an object; consider using %<.*%> or %<->*%>", obj);
|
|
return error_mark_node;
|
|
}
|
|
|
|
if (TYPE_BINFO (type))
|
|
{
|
|
fns = lookup_fnfields (TYPE_BINFO (type), call_op_identifier, 1, complain);
|
|
if (fns == error_mark_node)
|
|
return error_mark_node;
|
|
}
|
|
else
|
|
fns = NULL_TREE;
|
|
|
|
if (args != NULL && *args != NULL)
|
|
{
|
|
*args = resolve_args (*args, complain);
|
|
if (*args == NULL)
|
|
return error_mark_node;
|
|
}
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
p = conversion_obstack_alloc (0);
|
|
|
|
if (fns)
|
|
{
|
|
first_mem_arg = obj;
|
|
|
|
add_candidates (BASELINK_FUNCTIONS (fns),
|
|
first_mem_arg, *args, NULL_TREE,
|
|
NULL_TREE, false,
|
|
BASELINK_BINFO (fns), BASELINK_ACCESS_BINFO (fns),
|
|
LOOKUP_NORMAL, &candidates, complain);
|
|
}
|
|
|
|
convs = lookup_conversions (type);
|
|
|
|
for (; convs; convs = TREE_CHAIN (convs))
|
|
{
|
|
tree totype = TREE_TYPE (convs);
|
|
|
|
if (TYPE_PTRFN_P (totype)
|
|
|| TYPE_REFFN_P (totype)
|
|
|| (TYPE_REF_P (totype)
|
|
&& TYPE_PTRFN_P (TREE_TYPE (totype))))
|
|
for (tree fn : ovl_range (TREE_VALUE (convs)))
|
|
{
|
|
if (DECL_NONCONVERTING_P (fn))
|
|
continue;
|
|
|
|
if (TREE_CODE (fn) == TEMPLATE_DECL)
|
|
add_template_conv_candidate
|
|
(&candidates, fn, obj, *args, totype,
|
|
/*access_path=*/NULL_TREE,
|
|
/*conversion_path=*/NULL_TREE, complain);
|
|
else
|
|
add_conv_candidate (&candidates, fn, obj,
|
|
*args, /*conversion_path=*/NULL_TREE,
|
|
/*access_path=*/NULL_TREE, complain);
|
|
}
|
|
}
|
|
|
|
/* Be strict here because if we choose a bad conversion candidate, the
|
|
errors we get won't mention the call context. */
|
|
candidates = splice_viable (candidates, true, &any_viable_p);
|
|
if (!any_viable_p)
|
|
{
|
|
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);
|
|
}
|
|
result = error_mark_node;
|
|
}
|
|
else
|
|
{
|
|
cand = tourney (candidates, complain);
|
|
if (cand == 0)
|
|
{
|
|
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);
|
|
}
|
|
result = error_mark_node;
|
|
}
|
|
else if (TREE_CODE (cand->fn) == FUNCTION_DECL
|
|
&& DECL_OVERLOADED_OPERATOR_P (cand->fn)
|
|
&& DECL_OVERLOADED_OPERATOR_IS (cand->fn, CALL_EXPR))
|
|
result = build_over_call (cand, LOOKUP_NORMAL, complain);
|
|
else
|
|
{
|
|
if (TREE_CODE (cand->fn) == FUNCTION_DECL)
|
|
obj = convert_like_with_context (cand->convs[0], obj, cand->fn,
|
|
-1, complain);
|
|
else
|
|
{
|
|
gcc_checking_assert (TYPE_P (cand->fn));
|
|
obj = convert_like (cand->convs[0], obj, complain);
|
|
}
|
|
obj = convert_from_reference (obj);
|
|
result = cp_build_function_call_vec (obj, args, complain);
|
|
}
|
|
}
|
|
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
return result;
|
|
}
|
|
|
|
/* Called by op_error to prepare format strings suitable for the error
|
|
function. It concatenates a prefix (controlled by MATCH), ERRMSG,
|
|
and a suffix (controlled by NTYPES). */
|
|
|
|
static const char *
|
|
op_error_string (const char *errmsg, int ntypes, bool match)
|
|
{
|
|
const char *msg;
|
|
|
|
const char *msgp = concat (match ? G_("ambiguous overload for ")
|
|
: G_("no match for "), errmsg, NULL);
|
|
|
|
if (ntypes == 3)
|
|
msg = concat (msgp, G_(" (operand types are %qT, %qT, and %qT)"), NULL);
|
|
else if (ntypes == 2)
|
|
msg = concat (msgp, G_(" (operand types are %qT and %qT)"), NULL);
|
|
else
|
|
msg = concat (msgp, G_(" (operand type is %qT)"), NULL);
|
|
|
|
return msg;
|
|
}
|
|
|
|
static void
|
|
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;
|
|
const char *opname = OVL_OP_INFO (assop, assop ? code2 : code)->name;
|
|
|
|
switch (code)
|
|
{
|
|
case COND_EXPR:
|
|
if (flag_diagnostics_show_caret)
|
|
error_at (loc, op_error_string (G_("ternary %<operator?:%>"),
|
|
3, match),
|
|
TREE_TYPE (arg1), TREE_TYPE (arg2), TREE_TYPE (arg3));
|
|
else
|
|
error_at (loc, op_error_string (G_("ternary %<operator?:%> "
|
|
"in %<%E ? %E : %E%>"), 3, match),
|
|
arg1, arg2, arg3,
|
|
TREE_TYPE (arg1), TREE_TYPE (arg2), TREE_TYPE (arg3));
|
|
break;
|
|
|
|
case POSTINCREMENT_EXPR:
|
|
case POSTDECREMENT_EXPR:
|
|
if (flag_diagnostics_show_caret)
|
|
error_at (loc, op_error_string (G_("%<operator%s%>"), 1, match),
|
|
opname, TREE_TYPE (arg1));
|
|
else
|
|
error_at (loc, op_error_string (G_("%<operator%s%> in %<%E%s%>"),
|
|
1, match),
|
|
opname, arg1, opname, TREE_TYPE (arg1));
|
|
break;
|
|
|
|
case ARRAY_REF:
|
|
if (flag_diagnostics_show_caret)
|
|
error_at (loc, op_error_string (G_("%<operator[]%>"), 2, match),
|
|
TREE_TYPE (arg1), TREE_TYPE (arg2));
|
|
else
|
|
error_at (loc, op_error_string (G_("%<operator[]%> in %<%E[%E]%>"),
|
|
2, match),
|
|
arg1, arg2, TREE_TYPE (arg1), TREE_TYPE (arg2));
|
|
break;
|
|
|
|
case REALPART_EXPR:
|
|
case IMAGPART_EXPR:
|
|
if (flag_diagnostics_show_caret)
|
|
error_at (loc, op_error_string (G_("%qs"), 1, match),
|
|
opname, TREE_TYPE (arg1));
|
|
else
|
|
error_at (loc, op_error_string (G_("%qs in %<%s %E%>"), 1, match),
|
|
opname, opname, arg1, TREE_TYPE (arg1));
|
|
break;
|
|
|
|
case CO_AWAIT_EXPR:
|
|
if (flag_diagnostics_show_caret)
|
|
error_at (loc, op_error_string (G_("%<operator %s%>"), 1, match),
|
|
opname, TREE_TYPE (arg1));
|
|
else
|
|
error_at (loc, op_error_string (G_("%<operator %s%> in %<%s%E%>"),
|
|
1, match),
|
|
opname, opname, arg1, TREE_TYPE (arg1));
|
|
break;
|
|
|
|
default:
|
|
if (arg2)
|
|
if (flag_diagnostics_show_caret)
|
|
{
|
|
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),
|
|
opname, arg1, opname, arg2,
|
|
TREE_TYPE (arg1), TREE_TYPE (arg2));
|
|
else
|
|
if (flag_diagnostics_show_caret)
|
|
error_at (loc, op_error_string (G_("%<operator%s%>"), 1, match),
|
|
opname, TREE_TYPE (arg1));
|
|
else
|
|
error_at (loc, op_error_string (G_("%<operator%s%> in %<%s%E%>"),
|
|
1, match),
|
|
opname, opname, arg1, TREE_TYPE (arg1));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Return the implicit conversion sequence that could be used to
|
|
convert E1 to E2 in [expr.cond]. */
|
|
|
|
static conversion *
|
|
conditional_conversion (tree e1, tree e2, tsubst_flags_t complain)
|
|
{
|
|
tree t1 = non_reference (TREE_TYPE (e1));
|
|
tree t2 = non_reference (TREE_TYPE (e2));
|
|
conversion *conv;
|
|
bool good_base;
|
|
|
|
/* [expr.cond]
|
|
|
|
If E2 is an lvalue: E1 can be converted to match E2 if E1 can be
|
|
implicitly converted (clause _conv_) to the type "lvalue reference to
|
|
T2", subject to the constraint that in the conversion the
|
|
reference must bind directly (_dcl.init.ref_) to an lvalue.
|
|
|
|
If E2 is an xvalue: E1 can be converted to match E2 if E1 can be
|
|
implicitly converted to the type "rvalue reference to T2", subject to
|
|
the constraint that the reference must bind directly. */
|
|
if (glvalue_p (e2))
|
|
{
|
|
tree rtype = cp_build_reference_type (t2, !lvalue_p (e2));
|
|
conv = implicit_conversion (rtype,
|
|
t1,
|
|
e1,
|
|
/*c_cast_p=*/false,
|
|
LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND
|
|
|LOOKUP_ONLYCONVERTING,
|
|
complain);
|
|
if (conv && !conv->bad_p)
|
|
return conv;
|
|
}
|
|
|
|
/* If E2 is a prvalue or if neither of the conversions above can be done
|
|
and at least one of the operands has (possibly cv-qualified) class
|
|
type: */
|
|
if (!CLASS_TYPE_P (t1) && !CLASS_TYPE_P (t2))
|
|
return NULL;
|
|
|
|
/* [expr.cond]
|
|
|
|
If E1 and E2 have class type, and the underlying class types are
|
|
the same or one is a base class of the other: E1 can be converted
|
|
to match E2 if the class of T2 is the same type as, or a base
|
|
class of, the class of T1, and the cv-qualification of T2 is the
|
|
same cv-qualification as, or a greater cv-qualification than, the
|
|
cv-qualification of T1. If the conversion is applied, E1 is
|
|
changed to an rvalue of type T2 that still refers to the original
|
|
source class object (or the appropriate subobject thereof). */
|
|
if (CLASS_TYPE_P (t1) && CLASS_TYPE_P (t2)
|
|
&& ((good_base = DERIVED_FROM_P (t2, t1)) || DERIVED_FROM_P (t1, t2)))
|
|
{
|
|
if (good_base && at_least_as_qualified_p (t2, t1))
|
|
{
|
|
conv = build_identity_conv (t1, e1);
|
|
if (!same_type_p (TYPE_MAIN_VARIANT (t1),
|
|
TYPE_MAIN_VARIANT (t2)))
|
|
conv = build_conv (ck_base, t2, conv);
|
|
else
|
|
conv = build_conv (ck_rvalue, t2, conv);
|
|
return conv;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
else
|
|
/* [expr.cond]
|
|
|
|
Otherwise: E1 can be converted to match E2 if E1 can be implicitly
|
|
converted to the type that expression E2 would have if E2 were
|
|
converted to an rvalue (or the type it has, if E2 is an rvalue). */
|
|
return implicit_conversion (t2, t1, e1, /*c_cast_p=*/false,
|
|
LOOKUP_IMPLICIT, complain);
|
|
}
|
|
|
|
/* Implement [expr.cond]. ARG1, ARG2, and ARG3 are the three
|
|
arguments to the conditional expression. */
|
|
|
|
tree
|
|
build_conditional_expr (const op_location_t &loc,
|
|
tree arg1, tree arg2, tree arg3,
|
|
tsubst_flags_t complain)
|
|
{
|
|
tree arg2_type;
|
|
tree arg3_type;
|
|
tree result = NULL_TREE;
|
|
tree result_type = NULL_TREE;
|
|
bool is_glvalue = true;
|
|
struct z_candidate *candidates = 0;
|
|
struct z_candidate *cand;
|
|
void *p;
|
|
tree orig_arg2, orig_arg3;
|
|
|
|
auto_cond_timevar tv (TV_OVERLOAD);
|
|
|
|
/* As a G++ extension, the second argument to the conditional can be
|
|
omitted. (So that `a ? : c' is roughly equivalent to `a ? a :
|
|
c'.) If the second operand is omitted, make sure it is
|
|
calculated only once. */
|
|
if (!arg2)
|
|
{
|
|
if (complain & tf_error)
|
|
pedwarn (loc, OPT_Wpedantic,
|
|
"ISO C++ forbids omitting the middle term of "
|
|
"a %<?:%> expression");
|
|
|
|
if ((complain & tf_warning) && !truth_value_p (TREE_CODE (arg1)))
|
|
warn_for_omitted_condop (loc, arg1);
|
|
|
|
/* Make sure that lvalues remain lvalues. See g++.oliva/ext1.C. */
|
|
if (glvalue_p (arg1))
|
|
{
|
|
arg1 = cp_stabilize_reference (arg1);
|
|
arg2 = arg1 = prevent_lifetime_extension (arg1);
|
|
}
|
|
else
|
|
arg2 = arg1 = cp_save_expr (arg1);
|
|
}
|
|
|
|
/* If something has already gone wrong, just pass that fact up the
|
|
tree. */
|
|
if (error_operand_p (arg1)
|
|
|| error_operand_p (arg2)
|
|
|| error_operand_p (arg3))
|
|
return error_mark_node;
|
|
|
|
orig_arg2 = arg2;
|
|
orig_arg3 = arg3;
|
|
|
|
if (gnu_vector_type_p (TREE_TYPE (arg1))
|
|
&& VECTOR_INTEGER_TYPE_P (TREE_TYPE (arg1)))
|
|
{
|
|
tree arg1_type = TREE_TYPE (arg1);
|
|
|
|
/* If arg1 is another cond_expr choosing between -1 and 0,
|
|
then we can use its comparison. It may help to avoid
|
|
additional comparison, produce more accurate diagnostics
|
|
and enables folding. */
|
|
if (TREE_CODE (arg1) == VEC_COND_EXPR
|
|
&& integer_minus_onep (TREE_OPERAND (arg1, 1))
|
|
&& integer_zerop (TREE_OPERAND (arg1, 2)))
|
|
arg1 = TREE_OPERAND (arg1, 0);
|
|
|
|
arg1 = force_rvalue (arg1, complain);
|
|
arg2 = force_rvalue (arg2, complain);
|
|
arg3 = force_rvalue (arg3, complain);
|
|
|
|
/* force_rvalue can return error_mark on valid arguments. */
|
|
if (error_operand_p (arg1)
|
|
|| error_operand_p (arg2)
|
|
|| error_operand_p (arg3))
|
|
return error_mark_node;
|
|
|
|
arg2_type = TREE_TYPE (arg2);
|
|
arg3_type = TREE_TYPE (arg3);
|
|
|
|
if (!VECTOR_TYPE_P (arg2_type)
|
|
&& !VECTOR_TYPE_P (arg3_type))
|
|
{
|
|
/* Rely on the error messages of the scalar version. */
|
|
tree scal = build_conditional_expr (loc, integer_one_node,
|
|
orig_arg2, orig_arg3, complain);
|
|
if (scal == error_mark_node)
|
|
return error_mark_node;
|
|
tree stype = TREE_TYPE (scal);
|
|
tree ctype = TREE_TYPE (arg1_type);
|
|
if (TYPE_SIZE (stype) != TYPE_SIZE (ctype)
|
|
|| (!INTEGRAL_TYPE_P (stype) && !SCALAR_FLOAT_TYPE_P (stype)))
|
|
{
|
|
if (complain & tf_error)
|
|
error_at (loc, "inferred scalar type %qT is not an integer or "
|
|
"floating-point type of the same size as %qT", stype,
|
|
COMPARISON_CLASS_P (arg1)
|
|
? TREE_TYPE (TREE_TYPE (TREE_OPERAND (arg1, 0)))
|
|
: ctype);
|
|
return error_mark_node;
|
|
}
|
|
|
|
tree vtype = build_opaque_vector_type (stype,
|
|
TYPE_VECTOR_SUBPARTS (arg1_type));
|
|
/* We could pass complain & tf_warning to unsafe_conversion_p,
|
|
but the warnings (like Wsign-conversion) have already been
|
|
given by the scalar build_conditional_expr_1. We still check
|
|
unsafe_conversion_p to forbid truncating long long -> float. */
|
|
if (unsafe_conversion_p (stype, arg2, NULL_TREE, false))
|
|
{
|
|
if (complain & tf_error)
|
|
error_at (loc, "conversion of scalar %qH to vector %qI "
|
|
"involves truncation", arg2_type, vtype);
|
|
return error_mark_node;
|
|
}
|
|
if (unsafe_conversion_p (stype, arg3, NULL_TREE, false))
|
|
{
|
|
if (complain & tf_error)
|
|
error_at (loc, "conversion of scalar %qH to vector %qI "
|
|
"involves truncation", arg3_type, vtype);
|
|
return error_mark_node;
|
|
}
|
|
|
|
arg2 = cp_convert (stype, arg2, complain);
|
|
arg2 = save_expr (arg2);
|
|
arg2 = build_vector_from_val (vtype, arg2);
|
|
arg2_type = vtype;
|
|
arg3 = cp_convert (stype, arg3, complain);
|
|
arg3 = save_expr (arg3);
|
|
arg3 = build_vector_from_val (vtype, arg3);
|
|
arg3_type = vtype;
|
|
}
|
|
|
|
if ((gnu_vector_type_p (arg2_type) && !VECTOR_TYPE_P (arg3_type))
|
|
|| (gnu_vector_type_p (arg3_type) && !VECTOR_TYPE_P (arg2_type)))
|
|
{
|
|
enum stv_conv convert_flag =
|
|
scalar_to_vector (loc, VEC_COND_EXPR, arg2, arg3,
|
|
complain & tf_error);
|
|
|
|
switch (convert_flag)
|
|
{
|
|
case stv_error:
|
|
return error_mark_node;
|
|
case stv_firstarg:
|
|
{
|
|
arg2 = save_expr (arg2);
|
|
arg2 = convert (TREE_TYPE (arg3_type), arg2);
|
|
arg2 = build_vector_from_val (arg3_type, arg2);
|
|
arg2_type = TREE_TYPE (arg2);
|
|
break;
|
|
}
|
|
case stv_secondarg:
|
|
{
|
|
arg3 = save_expr (arg3);
|
|
arg3 = convert (TREE_TYPE (arg2_type), arg3);
|
|
arg3 = build_vector_from_val (arg2_type, arg3);
|
|
arg3_type = TREE_TYPE (arg3);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!gnu_vector_type_p (arg2_type)
|
|
|| !gnu_vector_type_p (arg3_type)
|
|
|| !same_type_p (arg2_type, arg3_type)
|
|
|| maybe_ne (TYPE_VECTOR_SUBPARTS (arg1_type),
|
|
TYPE_VECTOR_SUBPARTS (arg2_type))
|
|
|| TYPE_SIZE (arg1_type) != TYPE_SIZE (arg2_type))
|
|
{
|
|
if (complain & tf_error)
|
|
error_at (loc,
|
|
"incompatible vector types in conditional expression: "
|
|
"%qT, %qT and %qT", TREE_TYPE (arg1),
|
|
TREE_TYPE (orig_arg2), TREE_TYPE (orig_arg3));
|
|
return error_mark_node;
|
|
}
|
|
|
|
if (!COMPARISON_CLASS_P (arg1))
|
|
{
|
|
tree cmp_type = truth_type_for (arg1_type);
|
|
arg1 = build2 (NE_EXPR, cmp_type, arg1, build_zero_cst (arg1_type));
|
|
}
|
|
return build3_loc (loc, VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
|
|
}
|
|
|
|
/* [expr.cond]
|
|
|
|
The first expression is implicitly converted to bool (clause
|
|
_conv_). */
|
|
arg1 = perform_implicit_conversion_flags (boolean_type_node, arg1, complain,
|
|
LOOKUP_NORMAL);
|
|
if (error_operand_p (arg1))
|
|
return error_mark_node;
|
|
|
|
/* [expr.cond]
|
|
|
|
If either the second or the third operand has type (possibly
|
|
cv-qualified) void, then the lvalue-to-rvalue (_conv.lval_),
|
|
array-to-pointer (_conv.array_), and function-to-pointer
|
|
(_conv.func_) standard conversions are performed on the second
|
|
and third operands. */
|
|
arg2_type = unlowered_expr_type (arg2);
|
|
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:
|
|
|
|
--The second or the third operand (but not both) is a
|
|
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 a prvalue. */
|
|
if (TREE_CODE (arg2) == THROW_EXPR
|
|
&& TREE_CODE (arg3) != THROW_EXPR)
|
|
{
|
|
result_type = arg3_type;
|
|
is_glvalue = glvalue_p (arg3);
|
|
}
|
|
else if (TREE_CODE (arg2) != THROW_EXPR
|
|
&& TREE_CODE (arg3) == THROW_EXPR)
|
|
{
|
|
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;
|
|
is_glvalue = false;
|
|
}
|
|
else
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
if (VOID_TYPE_P (arg2_type))
|
|
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 (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;
|
|
}
|
|
|
|
goto valid_operands;
|
|
}
|
|
/* [expr.cond]
|
|
|
|
Otherwise, if the second and third operand have different types,
|
|
and either has (possibly cv-qualified) class type, or if both are
|
|
glvalues of the same value category and the same type except for
|
|
cv-qualification, an attempt is made to convert each of those operands
|
|
to the type of the other. */
|
|
else if (!same_type_p (arg2_type, arg3_type)
|
|
&& (CLASS_TYPE_P (arg2_type) || CLASS_TYPE_P (arg3_type)
|
|
|| (same_type_ignoring_top_level_qualifiers_p (arg2_type,
|
|
arg3_type)
|
|
&& glvalue_p (arg2) && glvalue_p (arg3)
|
|
&& lvalue_p (arg2) == lvalue_p (arg3))))
|
|
{
|
|
conversion *conv2;
|
|
conversion *conv3;
|
|
bool converted = false;
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
p = conversion_obstack_alloc (0);
|
|
|
|
conv2 = conditional_conversion (arg2, arg3, complain);
|
|
conv3 = conditional_conversion (arg3, arg2, complain);
|
|
|
|
/* [expr.cond]
|
|
|
|
If both can be converted, or one can be converted but the
|
|
conversion is ambiguous, the program is ill-formed. If
|
|
neither can be converted, the operands are left unchanged and
|
|
further checking is performed as described below. If exactly
|
|
one conversion is possible, that conversion is applied to the
|
|
chosen operand and the converted operand is used in place of
|
|
the original operand for the remainder of this section. */
|
|
if ((conv2 && !conv2->bad_p
|
|
&& conv3 && !conv3->bad_p)
|
|
|| (conv2 && conv2->kind == ck_ambig)
|
|
|| (conv3 && conv3->kind == ck_ambig))
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
error_at (loc, "operands to %<?:%> have different types "
|
|
"%qT and %qT",
|
|
arg2_type, arg3_type);
|
|
if (conv2 && !conv2->bad_p && conv3 && !conv3->bad_p)
|
|
inform (loc, " and each type can be converted to the other");
|
|
else if (conv2 && conv2->kind == ck_ambig)
|
|
convert_like (conv2, arg2, complain);
|
|
else
|
|
convert_like (conv3, arg3, complain);
|
|
}
|
|
result = error_mark_node;
|
|
}
|
|
else if (conv2 && !conv2->bad_p)
|
|
{
|
|
arg2 = convert_like (conv2, arg2, complain);
|
|
arg2 = convert_from_reference (arg2);
|
|
arg2_type = TREE_TYPE (arg2);
|
|
/* Even if CONV2 is a valid conversion, the result of the
|
|
conversion may be invalid. For example, if ARG3 has type
|
|
"volatile X", and X does not have a copy constructor
|
|
accepting a "volatile X&", then even if ARG2 can be
|
|
converted to X, the conversion will fail. */
|
|
if (error_operand_p (arg2))
|
|
result = error_mark_node;
|
|
converted = true;
|
|
}
|
|
else if (conv3 && !conv3->bad_p)
|
|
{
|
|
arg3 = convert_like (conv3, arg3, complain);
|
|
arg3 = convert_from_reference (arg3);
|
|
arg3_type = TREE_TYPE (arg3);
|
|
if (error_operand_p (arg3))
|
|
result = error_mark_node;
|
|
converted = true;
|
|
}
|
|
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
if (result)
|
|
return result;
|
|
|
|
/* If, after the conversion, both operands have class type,
|
|
treat the cv-qualification of both operands as if it were the
|
|
union of the cv-qualification of the operands.
|
|
|
|
The standard is not clear about what to do in this
|
|
circumstance. For example, if the first operand has type
|
|
"const X" and the second operand has a user-defined
|
|
conversion to "volatile X", what is the type of the second
|
|
operand after this step? Making it be "const X" (matching
|
|
the first operand) seems wrong, as that discards the
|
|
qualification without actually performing a copy. Leaving it
|
|
as "volatile X" seems wrong as that will result in the
|
|
conditional expression failing altogether, even though,
|
|
according to this step, the one operand could be converted to
|
|
the type of the other. */
|
|
if (converted
|
|
&& CLASS_TYPE_P (arg2_type)
|
|
&& cp_type_quals (arg2_type) != cp_type_quals (arg3_type))
|
|
arg2_type = arg3_type =
|
|
cp_build_qualified_type (arg2_type,
|
|
cp_type_quals (arg2_type)
|
|
| cp_type_quals (arg3_type));
|
|
}
|
|
|
|
/* [expr.cond]
|
|
|
|
If the second and third operands are glvalues of the same value
|
|
category and have the same type, the result is of that type and
|
|
value category. */
|
|
if (((lvalue_p (arg2) && lvalue_p (arg3))
|
|
|| (xvalue_p (arg2) && xvalue_p (arg3)))
|
|
&& same_type_p (arg2_type, arg3_type))
|
|
{
|
|
result_type = arg2_type;
|
|
goto valid_operands;
|
|
}
|
|
|
|
/* [expr.cond]
|
|
|
|
Otherwise, the result is an rvalue. If the second and third
|
|
operand do not have the same type, and either has (possibly
|
|
cv-qualified) class type, overload resolution is used to
|
|
determine the conversions (if any) to be applied to the operands
|
|
(_over.match.oper_, _over.built_). */
|
|
is_glvalue = false;
|
|
if (!same_type_p (arg2_type, arg3_type)
|
|
&& (CLASS_TYPE_P (arg2_type) || CLASS_TYPE_P (arg3_type)))
|
|
{
|
|
releasing_vec args;
|
|
conversion *conv;
|
|
bool any_viable_p;
|
|
|
|
/* Rearrange the arguments so that add_builtin_candidate only has
|
|
to know about two args. In build_builtin_candidate, the
|
|
arguments are unscrambled. */
|
|
args->quick_push (arg2);
|
|
args->quick_push (arg3);
|
|
args->quick_push (arg1);
|
|
add_builtin_candidates (&candidates,
|
|
COND_EXPR,
|
|
NOP_EXPR,
|
|
ovl_op_identifier (false, COND_EXPR),
|
|
args,
|
|
LOOKUP_NORMAL, complain);
|
|
|
|
/* [expr.cond]
|
|
|
|
If the overload resolution fails, the program is
|
|
ill-formed. */
|
|
candidates = splice_viable (candidates, false, &any_viable_p);
|
|
if (!any_viable_p)
|
|
{
|
|
if (complain & tf_error)
|
|
error_at (loc, "operands to %<?:%> have different types %qT and %qT",
|
|
arg2_type, arg3_type);
|
|
return error_mark_node;
|
|
}
|
|
cand = tourney (candidates, complain);
|
|
if (!cand)
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
auto_diagnostic_group d;
|
|
op_error (loc, COND_EXPR, NOP_EXPR, arg1, arg2, arg3, FALSE);
|
|
print_z_candidates (loc, candidates);
|
|
}
|
|
return error_mark_node;
|
|
}
|
|
|
|
/* [expr.cond]
|
|
|
|
Otherwise, the conversions thus determined are applied, and
|
|
the converted operands are used in place of the original
|
|
operands for the remainder of this section. */
|
|
conv = cand->convs[0];
|
|
arg1 = convert_like (conv, arg1, complain);
|
|
conv = cand->convs[1];
|
|
arg2 = convert_like (conv, arg2, complain);
|
|
arg2_type = TREE_TYPE (arg2);
|
|
conv = cand->convs[2];
|
|
arg3 = convert_like (conv, arg3, complain);
|
|
arg3_type = TREE_TYPE (arg3);
|
|
}
|
|
|
|
/* [expr.cond]
|
|
|
|
Lvalue-to-rvalue (_conv.lval_), array-to-pointer (_conv.array_),
|
|
and function-to-pointer (_conv.func_) standard conversions are
|
|
performed on the second and third operands.
|
|
|
|
We need to force the lvalue-to-rvalue conversion here for class types,
|
|
so we get TARGET_EXPRs; trying to deal with a COND_EXPR of class rvalues
|
|
that isn't wrapped with a TARGET_EXPR plays havoc with exception
|
|
regions. */
|
|
|
|
arg2 = force_rvalue (arg2, complain);
|
|
if (!CLASS_TYPE_P (arg2_type))
|
|
arg2_type = TREE_TYPE (arg2);
|
|
|
|
arg3 = force_rvalue (arg3, complain);
|
|
if (!CLASS_TYPE_P (arg3_type))
|
|
arg3_type = TREE_TYPE (arg3);
|
|
|
|
if (arg2 == error_mark_node || arg3 == error_mark_node)
|
|
return error_mark_node;
|
|
|
|
/* [expr.cond]
|
|
|
|
After those conversions, one of the following shall hold:
|
|
|
|
--The second and third operands have the same type; the result is of
|
|
that type. */
|
|
if (same_type_p (arg2_type, arg3_type))
|
|
result_type = arg2_type;
|
|
/* [expr.cond]
|
|
|
|
--The second and third operands have arithmetic or enumeration
|
|
type; the usual arithmetic conversions are performed to bring
|
|
them to a common type, and the result is of that type. */
|
|
else if ((ARITHMETIC_TYPE_P (arg2_type)
|
|
|| UNSCOPED_ENUM_P (arg2_type))
|
|
&& (ARITHMETIC_TYPE_P (arg3_type)
|
|
|| UNSCOPED_ENUM_P (arg3_type)))
|
|
{
|
|
/* In this case, there is always a common type. */
|
|
result_type = type_after_usual_arithmetic_conversions (arg2_type,
|
|
arg3_type);
|
|
if (complain & tf_warning)
|
|
do_warn_double_promotion (result_type, arg2_type, arg3_type,
|
|
"implicit conversion from %qH to %qI to "
|
|
"match other result of conditional",
|
|
loc);
|
|
|
|
if (TREE_CODE (arg2_type) == ENUMERAL_TYPE
|
|
&& TREE_CODE (arg3_type) == ENUMERAL_TYPE)
|
|
{
|
|
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)
|
|
warning_at (loc, OPT_Wenum_compare, "enumerated mismatch "
|
|
"in conditional expression: %qT vs %qT",
|
|
arg2_type, arg3_type);
|
|
}
|
|
else if ((complain & tf_warning)
|
|
&& warn_deprecated_enum_float_conv
|
|
&& ((TREE_CODE (arg2_type) == ENUMERAL_TYPE
|
|
&& TREE_CODE (arg3_type) == REAL_TYPE)
|
|
|| (TREE_CODE (arg2_type) == REAL_TYPE
|
|
&& TREE_CODE (arg3_type) == ENUMERAL_TYPE)))
|
|
{
|
|
if (TREE_CODE (arg2_type) == ENUMERAL_TYPE)
|
|
warning_at (loc, OPT_Wdeprecated_enum_float_conversion,
|
|
"conditional expression between enumeration type "
|
|
"%qT and floating-point type %qT is deprecated",
|
|
arg2_type, arg3_type);
|
|
else
|
|
warning_at (loc, OPT_Wdeprecated_enum_float_conversion,
|
|
"conditional expression between floating-point "
|
|
"type %qT and enumeration type %qT is deprecated",
|
|
arg2_type, arg3_type);
|
|
}
|
|
else if ((extra_warnings || warn_enum_conversion)
|
|
&& ((TREE_CODE (arg2_type) == ENUMERAL_TYPE
|
|
&& !same_type_p (arg3_type, type_promotes_to (arg2_type)))
|
|
|| (TREE_CODE (arg3_type) == ENUMERAL_TYPE
|
|
&& !same_type_p (arg2_type,
|
|
type_promotes_to (arg3_type)))))
|
|
{
|
|
if (complain & tf_warning)
|
|
{
|
|
enum opt_code opt = (warn_enum_conversion
|
|
? OPT_Wenum_conversion
|
|
: OPT_Wextra);
|
|
warning_at (loc, opt, "enumerated and "
|
|
"non-enumerated type in conditional expression");
|
|
}
|
|
}
|
|
|
|
arg2 = perform_implicit_conversion (result_type, arg2, complain);
|
|
arg3 = perform_implicit_conversion (result_type, arg3, complain);
|
|
}
|
|
/* [expr.cond]
|
|
|
|
--The second and third operands have pointer type, or one has
|
|
pointer type and the other is a null pointer constant; pointer
|
|
conversions (_conv.ptr_) and qualification conversions
|
|
(_conv.qual_) are performed to bring them to their composite
|
|
pointer type (_expr.rel_). The result is of the composite
|
|
pointer type.
|
|
|
|
--The second and third operands have pointer to member type, or
|
|
one has pointer to member type and the other is a null pointer
|
|
constant; pointer to member conversions (_conv.mem_) and
|
|
qualification conversions (_conv.qual_) are performed to bring
|
|
them to a common type, whose cv-qualification shall match the
|
|
cv-qualification of either the second or the third operand.
|
|
The result is of the common type. */
|
|
else if ((null_ptr_cst_p (arg2)
|
|
&& TYPE_PTR_OR_PTRMEM_P (arg3_type))
|
|
|| (null_ptr_cst_p (arg3)
|
|
&& TYPE_PTR_OR_PTRMEM_P (arg2_type))
|
|
|| (TYPE_PTR_P (arg2_type) && TYPE_PTR_P (arg3_type))
|
|
|| (TYPE_PTRDATAMEM_P (arg2_type) && TYPE_PTRDATAMEM_P (arg3_type))
|
|
|| (TYPE_PTRMEMFUNC_P (arg2_type) && TYPE_PTRMEMFUNC_P (arg3_type)))
|
|
{
|
|
result_type = composite_pointer_type (loc,
|
|
arg2_type, arg3_type, arg2,
|
|
arg3, CPO_CONDITIONAL_EXPR,
|
|
complain);
|
|
if (result_type == error_mark_node)
|
|
return error_mark_node;
|
|
arg2 = perform_implicit_conversion (result_type, arg2, complain);
|
|
arg3 = perform_implicit_conversion (result_type, arg3, complain);
|
|
}
|
|
|
|
if (!result_type)
|
|
{
|
|
if (complain & tf_error)
|
|
error_at (loc, "operands to %<?:%> have different types %qT and %qT",
|
|
arg2_type, arg3_type);
|
|
return error_mark_node;
|
|
}
|
|
|
|
if (arg2 == error_mark_node || arg3 == error_mark_node)
|
|
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,
|
|
warn here, because the COND_EXPR will be turned into ARG2. */
|
|
if (warn_duplicated_branches
|
|
&& (complain & tf_warning)
|
|
&& (arg2 == arg3 || operand_equal_p (arg2, arg3,
|
|
OEP_ADDRESS_OF_SAME_FIELD)))
|
|
warning_at (EXPR_LOCATION (result), OPT_Wduplicated_branches,
|
|
"this condition has identical branches");
|
|
|
|
/* We can't use result_type below, as fold might have returned a
|
|
throw_expr. */
|
|
|
|
if (!is_glvalue)
|
|
{
|
|
/* Expand both sides into the same slot, hopefully the target of
|
|
the ?: expression. We used to check for TARGET_EXPRs here,
|
|
but now we sometimes wrap them in NOP_EXPRs so the test would
|
|
fail. */
|
|
if (CLASS_TYPE_P (TREE_TYPE (result)))
|
|
result = get_target_expr_sfinae (result, complain);
|
|
/* If this expression is an rvalue, but might be mistaken for an
|
|
lvalue, we must add a NON_LVALUE_EXPR. */
|
|
result = rvalue (result);
|
|
}
|
|
else
|
|
result = force_paren_expr (result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/* OPERAND is an operand to an expression. Perform necessary steps
|
|
required before using it. If OPERAND is NULL_TREE, NULL_TREE is
|
|
returned. */
|
|
|
|
static tree
|
|
prep_operand (tree operand)
|
|
{
|
|
if (operand)
|
|
{
|
|
if (CLASS_TYPE_P (TREE_TYPE (operand))
|
|
&& CLASSTYPE_TEMPLATE_INSTANTIATION (TREE_TYPE (operand)))
|
|
/* Make sure the template type is instantiated now. */
|
|
instantiate_class_template (TYPE_MAIN_VARIANT (TREE_TYPE (operand)));
|
|
}
|
|
|
|
return operand;
|
|
}
|
|
|
|
/* True iff CONV represents a conversion sequence which no other can be better
|
|
than under [over.ics.rank]: in other words, a "conversion" to the exact same
|
|
type (including binding to a reference to the same type). This is stronger
|
|
than the standard's "identity" category, which also includes reference
|
|
bindings that add cv-qualifiers or change rvalueness. */
|
|
|
|
static bool
|
|
perfect_conversion_p (conversion *conv)
|
|
{
|
|
if (CONVERSION_RANK (conv) != cr_identity)
|
|
return false;
|
|
if (conv->kind == ck_ref_bind)
|
|
{
|
|
if (!conv->rvaluedness_matches_p)
|
|
return false;
|
|
if (!same_type_p (TREE_TYPE (conv->type),
|
|
next_conversion (conv)->type))
|
|
return false;
|
|
}
|
|
if (conv->check_narrowing)
|
|
/* Brace elision is imperfect. */
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/* True if CAND represents a perfect match, i.e. all perfect conversions, so no
|
|
other candidate can be a better match. Since the template/non-template
|
|
tiebreaker comes immediately after the conversion comparison in
|
|
[over.match.best], a perfect non-template candidate is better than all
|
|
templates. */
|
|
|
|
static bool
|
|
perfect_candidate_p (z_candidate *cand)
|
|
{
|
|
if (cand->viable < 1)
|
|
return false;
|
|
/* CWG1402 makes an implicitly deleted move op worse than other
|
|
candidates. */
|
|
if (DECL_DELETED_FN (cand->fn) && DECL_DEFAULTED_FN (cand->fn)
|
|
&& move_fn_p (cand->fn))
|
|
return false;
|
|
int len = cand->num_convs;
|
|
for (int i = 0; i < len; ++i)
|
|
if (!perfect_conversion_p (cand->convs[i]))
|
|
return false;
|
|
if (conversion *conv = cand->second_conv)
|
|
if (!perfect_conversion_p (conv))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/* True iff one of CAND's argument conversions is NULL. */
|
|
|
|
static bool
|
|
missing_conversion_p (const z_candidate *cand)
|
|
{
|
|
for (unsigned i = 0; i < cand->num_convs; ++i)
|
|
if (!cand->convs[i])
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/* Add each of the viable functions in FNS (a FUNCTION_DECL or
|
|
OVERLOAD) to the CANDIDATES, returning an updated list of
|
|
CANDIDATES. The ARGS are the arguments provided to the call;
|
|
if FIRST_ARG is non-null it is the implicit object argument,
|
|
otherwise the first element of ARGS is used if needed. The
|
|
EXPLICIT_TARGS are explicit template arguments provided.
|
|
TEMPLATE_ONLY is true if only template functions should be
|
|
considered. CONVERSION_PATH, ACCESS_PATH, and FLAGS are as for
|
|
add_function_candidate. */
|
|
|
|
static void
|
|
add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args,
|
|
tree return_type,
|
|
tree explicit_targs, bool template_only,
|
|
tree conversion_path, tree access_path,
|
|
int flags,
|
|
struct z_candidate **candidates,
|
|
tsubst_flags_t complain)
|
|
{
|
|
tree ctype;
|
|
const vec<tree, va_gc> *non_static_args;
|
|
bool check_list_ctor = false;
|
|
bool check_converting = false;
|
|
unification_kind_t strict;
|
|
|
|
if (!fns)
|
|
return;
|
|
|
|
/* Precalculate special handling of constructors and conversion ops. */
|
|
tree fn = OVL_FIRST (fns);
|
|
if (DECL_CONV_FN_P (fn))
|
|
{
|
|
check_list_ctor = false;
|
|
check_converting = (flags & LOOKUP_ONLYCONVERTING) != 0;
|
|
if (flags & LOOKUP_NO_CONVERSION)
|
|
/* We're doing return_type(x). */
|
|
strict = DEDUCE_CONV;
|
|
else
|
|
/* We're doing x.operator return_type(). */
|
|
strict = DEDUCE_EXACT;
|
|
/* [over.match.funcs] For conversion functions, the function
|
|
is considered to be a member of the class of the implicit
|
|
object argument for the purpose of defining the type of
|
|
the implicit object parameter. */
|
|
ctype = TYPE_MAIN_VARIANT (TREE_TYPE (first_arg));
|
|
}
|
|
else
|
|
{
|
|
if (DECL_CONSTRUCTOR_P (fn))
|
|
{
|
|
check_list_ctor = (flags & LOOKUP_LIST_ONLY) != 0;
|
|
/* For list-initialization we consider explicit constructors
|
|
and complain if one is chosen. */
|
|
check_converting
|
|
= ((flags & (LOOKUP_ONLYCONVERTING|LOOKUP_LIST_INIT_CTOR))
|
|
== LOOKUP_ONLYCONVERTING);
|
|
}
|
|
strict = DEDUCE_CALL;
|
|
ctype = conversion_path ? BINFO_TYPE (conversion_path) : NULL_TREE;
|
|
}
|
|
|
|
if (first_arg)
|
|
non_static_args = args;
|
|
else
|
|
/* Delay creating the implicit this parameter until it is needed. */
|
|
non_static_args = NULL;
|
|
|
|
bool seen_strictly_viable = any_strictly_viable (*candidates);
|
|
/* If there's a non-template perfect match, we don't need to consider
|
|
templates. So check non-templates first. This optimization is only
|
|
really needed for the defaulted copy constructor of tuple and the like
|
|
(96926), but it seems like we might as well enable it more generally. */
|
|
bool seen_perfect = false;
|
|
enum { templates, non_templates, either } which = either;
|
|
if (template_only)
|
|
which = templates;
|
|
else /*if (flags & LOOKUP_DEFAULTED)*/
|
|
which = non_templates;
|
|
|
|
/* During overload resolution, we first consider each function under the
|
|
assumption that we'll eventually find a strictly viable candidate.
|
|
This allows us to circumvent our defacto behavior when checking
|
|
argument conversions and shortcut consideration of the candidate
|
|
upon encountering the first bad conversion. If this assumption
|
|
turns out to be false, and all candidates end up being non-strictly
|
|
viable, then we reconsider such candidates under the defacto behavior.
|
|
This trick is important for pruning member function overloads according
|
|
to their const/ref-qualifiers (since all 'this' conversions are at
|
|
worst bad) without breaking -fpermissive. */
|
|
tree bad_fns = NULL_TREE;
|
|
bool shortcut_bad_convs = true;
|
|
|
|
again:
|
|
for (tree fn : lkp_range (fns))
|
|
{
|
|
if (check_converting && DECL_NONCONVERTING_P (fn))
|
|
continue;
|
|
if (check_list_ctor && !is_list_ctor (fn))
|
|
continue;
|
|
if (which == templates && TREE_CODE (fn) != TEMPLATE_DECL)
|
|
continue;
|
|
if (which == non_templates && TREE_CODE (fn) == TEMPLATE_DECL)
|
|
continue;
|
|
|
|
tree fn_first_arg = NULL_TREE;
|
|
const vec<tree, va_gc> *fn_args = args;
|
|
|
|
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
|
|
{
|
|
/* Figure out where the object arg comes from. If this
|
|
function is a non-static member and we didn't get an
|
|
implicit object argument, move it out of args. */
|
|
if (first_arg == NULL_TREE)
|
|
{
|
|
unsigned int ix;
|
|
tree arg;
|
|
vec<tree, va_gc> *tempvec;
|
|
vec_alloc (tempvec, args->length () - 1);
|
|
for (ix = 1; args->iterate (ix, &arg); ++ix)
|
|
tempvec->quick_push (arg);
|
|
non_static_args = tempvec;
|
|
first_arg = (*args)[0];
|
|
}
|
|
|
|
fn_first_arg = first_arg;
|
|
fn_args = non_static_args;
|
|
}
|
|
|
|
/* Don't bother reversing an operator with two identical parameters. */
|
|
else if (vec_safe_length (args) == 2 && (flags & LOOKUP_REVERSED))
|
|
{
|
|
tree parmlist = TYPE_ARG_TYPES (TREE_TYPE (fn));
|
|
if (same_type_p (TREE_VALUE (parmlist),
|
|
TREE_VALUE (TREE_CHAIN (parmlist))))
|
|
continue;
|
|
}
|
|
|
|
if (TREE_CODE (fn) == TEMPLATE_DECL)
|
|
{
|
|
if (!add_template_candidate (candidates,
|
|
fn,
|
|
ctype,
|
|
explicit_targs,
|
|
fn_first_arg,
|
|
fn_args,
|
|
return_type,
|
|
access_path,
|
|
conversion_path,
|
|
flags,
|
|
strict,
|
|
shortcut_bad_convs,
|
|
complain))
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
add_function_candidate (candidates,
|
|
fn,
|
|
ctype,
|
|
fn_first_arg,
|
|
fn_args,
|
|
access_path,
|
|
conversion_path,
|
|
flags,
|
|
NULL,
|
|
shortcut_bad_convs,
|
|
complain);
|
|
if (perfect_candidate_p (*candidates))
|
|
seen_perfect = true;
|
|
}
|
|
|
|
z_candidate *cand = *candidates;
|
|
if (cand->viable == 1)
|
|
seen_strictly_viable = true;
|
|
|
|
if (cand->viable == -1
|
|
&& shortcut_bad_convs
|
|
&& missing_conversion_p (cand))
|
|
{
|
|
/* This candidate has been tentatively marked non-strictly viable,
|
|
and we didn't compute all argument conversions for it (having
|
|
stopped at the first bad conversion). Add the function to BAD_FNS
|
|
to fully reconsider later if we don't find any strictly viable
|
|
candidates. */
|
|
if (complain & (tf_error | tf_conv))
|
|
{
|
|
bad_fns = lookup_add (fn, bad_fns);
|
|
*candidates = (*candidates)->next;
|
|
}
|
|
else
|
|
/* But if we're in a SFINAE context, just mark this candidate as
|
|
unviable outright and avoid potentially reconsidering it.
|
|
This is safe to do because in a SFINAE context, performing a bad
|
|
conversion is always an error (even with -fpermissive), so a
|
|
non-strictly viable candidate is effectively unviable anyway. */
|
|
cand->viable = 0;
|
|
}
|
|
}
|
|
if (which == non_templates && !seen_perfect)
|
|
{
|
|
which = templates;
|
|
goto again;
|
|
}
|
|
else if (which == templates
|
|
&& !seen_strictly_viable
|
|
&& shortcut_bad_convs
|
|
&& bad_fns)
|
|
{
|
|
/* None of the candidates are strictly viable, so consider again those
|
|
functions in BAD_FNS, this time without shortcutting bad conversions
|
|
so that all their argument conversions are computed. */
|
|
which = either;
|
|
fns = bad_fns;
|
|
shortcut_bad_convs = false;
|
|
goto again;
|
|
}
|
|
}
|
|
|
|
/* Returns 1 if P0145R2 says that the LHS of operator CODE is evaluated first,
|
|
-1 if the RHS is evaluated first, or 0 if the order is unspecified. */
|
|
|
|
static int
|
|
op_is_ordered (tree_code code)
|
|
{
|
|
switch (code)
|
|
{
|
|
// 5. b @= a
|
|
case MODIFY_EXPR:
|
|
return (flag_strong_eval_order > 1 ? -1 : 0);
|
|
|
|
// 6. a[b]
|
|
case ARRAY_REF:
|
|
return (flag_strong_eval_order > 1 ? 1 : 0);
|
|
|
|
// 1. a.b
|
|
// Not overloadable (yet).
|
|
// 2. a->b
|
|
// Only one argument.
|
|
// 3. a->*b
|
|
case MEMBER_REF:
|
|
// 7. a << b
|
|
case LSHIFT_EXPR:
|
|
// 8. a >> b
|
|
case RSHIFT_EXPR:
|
|
// a && b
|
|
// Predates P0145R3.
|
|
case TRUTH_ANDIF_EXPR:
|
|
// a || b
|
|
// Predates P0145R3.
|
|
case TRUTH_ORIF_EXPR:
|
|
// a , b
|
|
// Predates P0145R3.
|
|
case COMPOUND_EXPR:
|
|
return (flag_strong_eval_order ? 1 : 0);
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Subroutine of build_new_op: Add to CANDIDATES all candidates for the
|
|
operator indicated by CODE/CODE2. This function calls itself recursively to
|
|
handle C++20 rewritten comparison operator candidates.
|
|
|
|
LOOKUPS, if non-NULL, is the set of pertinent namespace-scope operator
|
|
overloads to consider. This parameter is used when instantiating a
|
|
dependent operator expression and has the same structure as
|
|
DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS. */
|
|
|
|
static tree
|
|
add_operator_candidates (z_candidate **candidates,
|
|
tree_code code, tree_code code2,
|
|
vec<tree, va_gc> *arglist, tree lookups,
|
|
int flags, tsubst_flags_t complain)
|
|
{
|
|
z_candidate *start_candidates = *candidates;
|
|
bool ismodop = code2 != ERROR_MARK;
|
|
tree fnname = ovl_op_identifier (ismodop, ismodop ? code2 : code);
|
|
|
|
/* LOOKUP_REWRITTEN is set when we're looking for the == or <=> operator to
|
|
rewrite from, and also when we're looking for the e.g. < operator to use
|
|
on the result of <=>. In the latter case, we don't want the flag set in
|
|
the candidate, we just want to suppress looking for rewrites. */
|
|
bool rewritten = (flags & LOOKUP_REWRITTEN);
|
|
if (rewritten && code != EQ_EXPR && code != SPACESHIP_EXPR)
|
|
flags &= ~LOOKUP_REWRITTEN;
|
|
|
|
bool memonly = false;
|
|
switch (code)
|
|
{
|
|
/* =, ->, [], () must be non-static member functions. */
|
|
case MODIFY_EXPR:
|
|
if (code2 != NOP_EXPR)
|
|
break;
|
|
/* FALLTHRU */
|
|
case COMPONENT_REF:
|
|
case ARRAY_REF:
|
|
memonly = true;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Add namespace-scope operators to the list of functions to
|
|
consider. */
|
|
if (!memonly)
|
|
{
|
|
tree fns;
|
|
if (!lookups)
|
|
fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE);
|
|
/* If LOOKUPS is non-NULL, then we're instantiating a dependent operator
|
|
expression, and LOOKUPS is the result of stage 1 name lookup. */
|
|
else if (tree found = purpose_member (fnname, lookups))
|
|
fns = TREE_VALUE (found);
|
|
else
|
|
fns = NULL_TREE;
|
|
fns = lookup_arg_dependent (fnname, fns, arglist);
|
|
add_candidates (fns, NULL_TREE, arglist, NULL_TREE,
|
|
NULL_TREE, false, NULL_TREE, NULL_TREE,
|
|
flags, candidates, complain);
|
|
}
|
|
|
|
/* Add class-member operators to the candidate set. */
|
|
tree arg1_type = TREE_TYPE ((*arglist)[0]);
|
|
unsigned nargs = arglist->length () > 1 ? 2 : 1;
|
|
tree arg2_type = nargs > 1 ? TREE_TYPE ((*arglist)[1]) : NULL_TREE;
|
|
if (CLASS_TYPE_P (arg1_type))
|
|
{
|
|
tree fns = lookup_fnfields (arg1_type, fnname, 1, complain);
|
|
if (fns == error_mark_node)
|
|
return error_mark_node;
|
|
if (fns)
|
|
add_candidates (BASELINK_FUNCTIONS (fns),
|
|
NULL_TREE, arglist, NULL_TREE,
|
|
NULL_TREE, false,
|
|
BASELINK_BINFO (fns),
|
|
BASELINK_ACCESS_BINFO (fns),
|
|
flags, candidates, complain);
|
|
}
|
|
/* Per [over.match.oper]3.2, if no operand has a class type, then
|
|
only non-member functions that have type T1 or reference to
|
|
cv-qualified-opt T1 for the first argument, if the first argument
|
|
has an enumeration type, or T2 or reference to cv-qualified-opt
|
|
T2 for the second argument, if the second argument has an
|
|
enumeration type. Filter out those that don't match. */
|
|
else if (! arg2_type || ! CLASS_TYPE_P (arg2_type))
|
|
{
|
|
struct z_candidate **candp, **next;
|
|
|
|
for (candp = candidates; *candp != start_candidates; candp = next)
|
|
{
|
|
unsigned i;
|
|
z_candidate *cand = *candp;
|
|
next = &cand->next;
|
|
|
|
tree parmlist = TYPE_ARG_TYPES (TREE_TYPE (cand->fn));
|
|
|
|
for (i = 0; i < nargs; ++i)
|
|
{
|
|
tree parmtype = TREE_VALUE (parmlist);
|
|
tree argtype = unlowered_expr_type ((*arglist)[i]);
|
|
|
|
if (TYPE_REF_P (parmtype))
|
|
parmtype = TREE_TYPE (parmtype);
|
|
if (TREE_CODE (argtype) == ENUMERAL_TYPE
|
|
&& (same_type_ignoring_top_level_qualifiers_p
|
|
(argtype, parmtype)))
|
|
break;
|
|
|
|
parmlist = TREE_CHAIN (parmlist);
|
|
}
|
|
|
|
/* No argument has an appropriate type, so remove this
|
|
candidate function from the list. */
|
|
if (i == nargs)
|
|
{
|
|
*candp = cand->next;
|
|
next = candp;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!rewritten)
|
|
{
|
|
/* The standard says to rewrite built-in candidates, too,
|
|
but there's no point. */
|
|
add_builtin_candidates (candidates, code, code2, fnname, arglist,
|
|
flags, complain);
|
|
|
|
/* Maybe add C++20 rewritten comparison candidates. */
|
|
tree_code rewrite_code = ERROR_MARK;
|
|
if (cxx_dialect >= cxx20
|
|
&& nargs == 2
|
|
&& (OVERLOAD_TYPE_P (arg1_type) || OVERLOAD_TYPE_P (arg2_type)))
|
|
switch (code)
|
|
{
|
|
case LT_EXPR:
|
|
case LE_EXPR:
|
|
case GT_EXPR:
|
|
case GE_EXPR:
|
|
case SPACESHIP_EXPR:
|
|
rewrite_code = SPACESHIP_EXPR;
|
|
break;
|
|
|
|
case NE_EXPR:
|
|
case EQ_EXPR:
|
|
rewrite_code = EQ_EXPR;
|
|
break;
|
|
|
|
default:;
|
|
}
|
|
|
|
if (rewrite_code)
|
|
{
|
|
flags |= LOOKUP_REWRITTEN;
|
|
if (rewrite_code != code)
|
|
/* Add rewritten candidates in same order. */
|
|
add_operator_candidates (candidates, rewrite_code, ERROR_MARK,
|
|
arglist, lookups, flags, complain);
|
|
|
|
z_candidate *save_cand = *candidates;
|
|
|
|
/* Add rewritten candidates in reverse order. */
|
|
flags |= LOOKUP_REVERSED;
|
|
vec<tree,va_gc> *revlist = make_tree_vector ();
|
|
revlist->quick_push ((*arglist)[1]);
|
|
revlist->quick_push ((*arglist)[0]);
|
|
add_operator_candidates (candidates, rewrite_code, ERROR_MARK,
|
|
revlist, lookups, flags, complain);
|
|
|
|
/* Release the vec if we didn't add a candidate that uses it. */
|
|
for (z_candidate *c = *candidates; c != save_cand; c = c->next)
|
|
if (c->args == revlist)
|
|
{
|
|
revlist = NULL;
|
|
break;
|
|
}
|
|
release_tree_vector (revlist);
|
|
}
|
|
}
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
tree
|
|
build_new_op (const op_location_t &loc, enum tree_code code, int flags,
|
|
tree arg1, tree arg2, tree arg3, tree lookups,
|
|
tree *overload, tsubst_flags_t complain)
|
|
{
|
|
struct z_candidate *candidates = 0, *cand;
|
|
releasing_vec arglist;
|
|
tree result = NULL_TREE;
|
|
bool result_valid_p = false;
|
|
enum tree_code code2 = ERROR_MARK;
|
|
enum tree_code code_orig_arg1 = ERROR_MARK;
|
|
enum tree_code code_orig_arg2 = ERROR_MARK;
|
|
void *p;
|
|
bool strict_p;
|
|
bool any_viable_p;
|
|
|
|
auto_cond_timevar tv (TV_OVERLOAD);
|
|
|
|
if (error_operand_p (arg1)
|
|
|| error_operand_p (arg2)
|
|
|| error_operand_p (arg3))
|
|
return error_mark_node;
|
|
|
|
bool ismodop = code == MODIFY_EXPR;
|
|
if (ismodop)
|
|
{
|
|
code2 = TREE_CODE (arg3);
|
|
arg3 = NULL_TREE;
|
|
}
|
|
|
|
tree arg1_type = unlowered_expr_type (arg1);
|
|
tree arg2_type = arg2 ? unlowered_expr_type (arg2) : NULL_TREE;
|
|
|
|
arg1 = prep_operand (arg1);
|
|
|
|
switch (code)
|
|
{
|
|
case NEW_EXPR:
|
|
case VEC_NEW_EXPR:
|
|
case VEC_DELETE_EXPR:
|
|
case DELETE_EXPR:
|
|
/* Use build_operator_new_call and build_op_delete_call instead. */
|
|
gcc_unreachable ();
|
|
|
|
case CALL_EXPR:
|
|
/* Use build_op_call instead. */
|
|
gcc_unreachable ();
|
|
|
|
case TRUTH_ORIF_EXPR:
|
|
case TRUTH_ANDIF_EXPR:
|
|
case TRUTH_AND_EXPR:
|
|
case TRUTH_OR_EXPR:
|
|
/* These are saved for the sake of warn_logical_operator. */
|
|
code_orig_arg1 = TREE_CODE (arg1);
|
|
code_orig_arg2 = TREE_CODE (arg2);
|
|
break;
|
|
case GT_EXPR:
|
|
case LT_EXPR:
|
|
case GE_EXPR:
|
|
case LE_EXPR:
|
|
case EQ_EXPR:
|
|
case NE_EXPR:
|
|
/* These are saved for the sake of maybe_warn_bool_compare. */
|
|
code_orig_arg1 = TREE_CODE (arg1_type);
|
|
code_orig_arg2 = TREE_CODE (arg2_type);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
arg2 = prep_operand (arg2);
|
|
arg3 = prep_operand (arg3);
|
|
|
|
if (code == COND_EXPR)
|
|
/* Use build_conditional_expr instead. */
|
|
gcc_unreachable ();
|
|
else if (! OVERLOAD_TYPE_P (arg1_type)
|
|
&& (! arg2 || ! OVERLOAD_TYPE_P (arg2_type)))
|
|
goto builtin;
|
|
|
|
if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
|
|
{
|
|
arg2 = integer_zero_node;
|
|
arg2_type = integer_type_node;
|
|
}
|
|
|
|
arglist->quick_push (arg1);
|
|
if (arg2 != NULL_TREE)
|
|
arglist->quick_push (arg2);
|
|
if (arg3 != NULL_TREE)
|
|
arglist->quick_push (arg3);
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
p = conversion_obstack_alloc (0);
|
|
|
|
result = add_operator_candidates (&candidates, code, code2, arglist,
|
|
lookups, flags, complain);
|
|
if (result == error_mark_node)
|
|
goto user_defined_result_ready;
|
|
|
|
switch (code)
|
|
{
|
|
case COMPOUND_EXPR:
|
|
case ADDR_EXPR:
|
|
/* For these, the built-in candidates set is empty
|
|
[over.match.oper]/3. We don't want non-strict matches
|
|
because exact matches are always possible with built-in
|
|
operators. The built-in candidate set for COMPONENT_REF
|
|
would be empty too, but since there are no such built-in
|
|
operators, we accept non-strict matches for them. */
|
|
strict_p = true;
|
|
break;
|
|
|
|
default:
|
|
strict_p = false;
|
|
break;
|
|
}
|
|
|
|
candidates = splice_viable (candidates, strict_p, &any_viable_p);
|
|
if (!any_viable_p)
|
|
{
|
|
switch (code)
|
|
{
|
|
case POSTINCREMENT_EXPR:
|
|
case POSTDECREMENT_EXPR:
|
|
/* Don't try anything fancy if we're not allowed to produce
|
|
errors. */
|
|
if (!(complain & tf_error))
|
|
return error_mark_node;
|
|
|
|
/* Look for an `operator++ (int)'. Pre-1985 C++ didn't
|
|
distinguish between prefix and postfix ++ and
|
|
operator++() was used for both, so we allow this with
|
|
-fpermissive. */
|
|
else
|
|
{
|
|
tree fnname = ovl_op_identifier (ismodop, ismodop ? code2 : code);
|
|
const char *msg = (flag_permissive)
|
|
? G_("no %<%D(int)%> declared for postfix %qs,"
|
|
" trying prefix operator instead")
|
|
: G_("no %<%D(int)%> declared for postfix %qs");
|
|
permerror (loc, msg, fnname, OVL_OP_INFO (false, code)->name);
|
|
}
|
|
|
|
if (!flag_permissive)
|
|
return error_mark_node;
|
|
|
|
if (code == POSTINCREMENT_EXPR)
|
|
code = PREINCREMENT_EXPR;
|
|
else
|
|
code = PREDECREMENT_EXPR;
|
|
result = build_new_op (loc, code, flags, arg1, NULL_TREE,
|
|
NULL_TREE, lookups, overload, complain);
|
|
break;
|
|
|
|
/* The caller will deal with these. */
|
|
case ADDR_EXPR:
|
|
case COMPOUND_EXPR:
|
|
case COMPONENT_REF:
|
|
case CO_AWAIT_EXPR:
|
|
result = NULL_TREE;
|
|
result_valid_p = true;
|
|
break;
|
|
|
|
default:
|
|
if (complain & tf_error)
|
|
{
|
|
/* If one of the arguments of the operator represents
|
|
an invalid use of member function pointer, try to report
|
|
a meaningful error ... */
|
|
if (invalid_nonstatic_memfn_p (loc, arg1, tf_error)
|
|
|| invalid_nonstatic_memfn_p (loc, arg2, tf_error)
|
|
|| invalid_nonstatic_memfn_p (loc, arg3, tf_error))
|
|
/* We displayed the error message. */;
|
|
else
|
|
{
|
|
/* ... 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);
|
|
}
|
|
}
|
|
result = error_mark_node;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cand = tourney (candidates, complain);
|
|
if (cand == 0)
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
auto_diagnostic_group d;
|
|
op_error (loc, code, code2, arg1, arg2, arg3, TRUE);
|
|
print_z_candidates (loc, candidates);
|
|
}
|
|
result = error_mark_node;
|
|
if (overload)
|
|
*overload = error_mark_node;
|
|
}
|
|
else if (TREE_CODE (cand->fn) == FUNCTION_DECL)
|
|
{
|
|
if (overload)
|
|
*overload = cand->fn;
|
|
|
|
if (resolve_args (arglist, complain) == NULL)
|
|
result = error_mark_node;
|
|
else
|
|
{
|
|
tsubst_flags_t ocomplain = complain;
|
|
if (cand->rewritten ())
|
|
/* We'll wrap this call in another one. */
|
|
ocomplain &= ~tf_decltype;
|
|
if (cand->reversed ())
|
|
{
|
|
/* We swapped these in add_candidate, swap them back now. */
|
|
std::swap (cand->convs[0], cand->convs[1]);
|
|
if (cand->fn == current_function_decl)
|
|
warning_at (loc, 0, "in C++20 this comparison calls the "
|
|
"current function recursively with reversed "
|
|
"arguments");
|
|
}
|
|
result = build_over_call (cand, LOOKUP_NORMAL, ocomplain);
|
|
}
|
|
|
|
if (trivial_fn_p (cand->fn) || DECL_IMMEDIATE_FUNCTION_P (cand->fn))
|
|
/* There won't be a CALL_EXPR. */;
|
|
else if (result && result != error_mark_node)
|
|
{
|
|
tree call = extract_call_expr (result);
|
|
CALL_EXPR_OPERATOR_SYNTAX (call) = true;
|
|
|
|
/* Specify evaluation order as per P0145R2. */
|
|
CALL_EXPR_ORDERED_ARGS (call) = false;
|
|
switch (op_is_ordered (code))
|
|
{
|
|
case -1:
|
|
CALL_EXPR_REVERSE_ARGS (call) = true;
|
|
break;
|
|
|
|
case 1:
|
|
CALL_EXPR_ORDERED_ARGS (call) = true;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If this was a C++20 rewritten comparison, adjust the result. */
|
|
if (cand->rewritten ())
|
|
{
|
|
/* FIXME build_min_non_dep_op_overload can't handle rewrites. */
|
|
if (overload)
|
|
*overload = NULL_TREE;
|
|
switch (code)
|
|
{
|
|
case EQ_EXPR:
|
|
gcc_checking_assert (cand->reversed ());
|
|
gcc_fallthrough ();
|
|
case NE_EXPR:
|
|
/* If a rewritten operator== candidate is selected by
|
|
overload resolution for an operator @, its return type
|
|
shall be cv bool.... */
|
|
if (TREE_CODE (TREE_TYPE (result)) != BOOLEAN_TYPE)
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
auto_diagnostic_group d;
|
|
error_at (loc, "return type of %qD is not %qs",
|
|
cand->fn, "bool");
|
|
inform (loc, "used as rewritten candidate for "
|
|
"comparison of %qT and %qT",
|
|
arg1_type, arg2_type);
|
|
}
|
|
result = error_mark_node;
|
|
}
|
|
else if (code == NE_EXPR)
|
|
/* !(y == x) or !(x == y) */
|
|
result = build1_loc (loc, TRUTH_NOT_EXPR,
|
|
boolean_type_node, result);
|
|
break;
|
|
|
|
/* If a rewritten operator<=> candidate is selected by
|
|
overload resolution for an operator @, x @ y is
|
|
interpreted as 0 @ (y <=> x) if the selected candidate is
|
|
a synthesized candidate with reversed order of parameters,
|
|
or (x <=> y) @ 0 otherwise, using the selected rewritten
|
|
operator<=> candidate. */
|
|
case SPACESHIP_EXPR:
|
|
if (!cand->reversed ())
|
|
/* We're in the build_new_op call below for an outer
|
|
reversed call; we don't need to do anything more. */
|
|
break;
|
|
gcc_fallthrough ();
|
|
case LT_EXPR:
|
|
case LE_EXPR:
|
|
case GT_EXPR:
|
|
case GE_EXPR:
|
|
{
|
|
tree lhs = result;
|
|
tree rhs = integer_zero_node;
|
|
if (cand->reversed ())
|
|
std::swap (lhs, rhs);
|
|
warning_sentinel ws (warn_zero_as_null_pointer_constant);
|
|
result = build_new_op (loc, code,
|
|
LOOKUP_NORMAL|LOOKUP_REWRITTEN,
|
|
lhs, rhs, NULL_TREE, lookups,
|
|
NULL, complain);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Give any warnings we noticed during overload resolution. */
|
|
if (cand->warnings && (complain & tf_warning))
|
|
{
|
|
struct candidate_warning *w;
|
|
for (w = cand->warnings; w; w = w->next)
|
|
joust (cand, w->loser, 1, complain);
|
|
}
|
|
|
|
/* Check for comparison of different enum types. */
|
|
switch (code)
|
|
{
|
|
case GT_EXPR:
|
|
case LT_EXPR:
|
|
case GE_EXPR:
|
|
case LE_EXPR:
|
|
case EQ_EXPR:
|
|
case NE_EXPR:
|
|
if (TREE_CODE (arg1_type) == ENUMERAL_TYPE
|
|
&& TREE_CODE (arg2_type) == ENUMERAL_TYPE
|
|
&& (TYPE_MAIN_VARIANT (arg1_type)
|
|
!= TYPE_MAIN_VARIANT (arg2_type))
|
|
&& (complain & tf_warning))
|
|
warning_at (loc, OPT_Wenum_compare,
|
|
"comparison between %q#T and %q#T",
|
|
arg1_type, arg2_type);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* "If a built-in candidate is selected by overload resolution, the
|
|
operands of class type are converted to the types of the
|
|
corresponding parameters of the selected operation function,
|
|
except that the second standard conversion sequence of a
|
|
user-defined conversion sequence (12.3.3.1.2) is not applied." */
|
|
conversion *conv = cand->convs[0];
|
|
if (conv->user_conv_p)
|
|
{
|
|
conv = strip_standard_conversion (conv);
|
|
arg1 = convert_like (conv, arg1, complain);
|
|
}
|
|
|
|
if (arg2)
|
|
{
|
|
conv = cand->convs[1];
|
|
if (conv->user_conv_p)
|
|
{
|
|
conv = strip_standard_conversion (conv);
|
|
arg2 = convert_like (conv, arg2, complain);
|
|
}
|
|
}
|
|
|
|
if (arg3)
|
|
{
|
|
conv = cand->convs[2];
|
|
if (conv->user_conv_p)
|
|
{
|
|
conv = strip_standard_conversion (conv);
|
|
arg3 = convert_like (conv, arg3, complain);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
user_defined_result_ready:
|
|
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
if (result || result_valid_p)
|
|
return result;
|
|
|
|
builtin:
|
|
switch (code)
|
|
{
|
|
case MODIFY_EXPR:
|
|
return cp_build_modify_expr (loc, arg1, code2, arg2, complain);
|
|
|
|
case INDIRECT_REF:
|
|
return cp_build_indirect_ref (loc, arg1, RO_UNARY_STAR, complain);
|
|
|
|
case TRUTH_ANDIF_EXPR:
|
|
case TRUTH_ORIF_EXPR:
|
|
case TRUTH_AND_EXPR:
|
|
case TRUTH_OR_EXPR:
|
|
if (complain & tf_warning)
|
|
warn_logical_operator (loc, code, boolean_type_node,
|
|
code_orig_arg1, arg1,
|
|
code_orig_arg2, arg2);
|
|
/* Fall through. */
|
|
case GT_EXPR:
|
|
case LT_EXPR:
|
|
case GE_EXPR:
|
|
case LE_EXPR:
|
|
case EQ_EXPR:
|
|
case NE_EXPR:
|
|
if ((complain & tf_warning)
|
|
&& ((code_orig_arg1 == BOOLEAN_TYPE)
|
|
^ (code_orig_arg2 == BOOLEAN_TYPE)))
|
|
maybe_warn_bool_compare (loc, code, arg1, arg2);
|
|
if (complain & tf_warning && warn_tautological_compare)
|
|
warn_tautological_cmp (loc, code, arg1, arg2);
|
|
/* Fall through. */
|
|
case SPACESHIP_EXPR:
|
|
case PLUS_EXPR:
|
|
case MINUS_EXPR:
|
|
case MULT_EXPR:
|
|
case TRUNC_DIV_EXPR:
|
|
case MAX_EXPR:
|
|
case MIN_EXPR:
|
|
case LSHIFT_EXPR:
|
|
case RSHIFT_EXPR:
|
|
case TRUNC_MOD_EXPR:
|
|
case BIT_AND_EXPR:
|
|
case BIT_IOR_EXPR:
|
|
case BIT_XOR_EXPR:
|
|
return cp_build_binary_op (loc, code, arg1, arg2, complain);
|
|
|
|
case UNARY_PLUS_EXPR:
|
|
case NEGATE_EXPR:
|
|
case BIT_NOT_EXPR:
|
|
case TRUTH_NOT_EXPR:
|
|
case PREINCREMENT_EXPR:
|
|
case POSTINCREMENT_EXPR:
|
|
case PREDECREMENT_EXPR:
|
|
case POSTDECREMENT_EXPR:
|
|
case REALPART_EXPR:
|
|
case IMAGPART_EXPR:
|
|
case ABS_EXPR:
|
|
case CO_AWAIT_EXPR:
|
|
return cp_build_unary_op (code, arg1, false, complain);
|
|
|
|
case ARRAY_REF:
|
|
return cp_build_array_ref (input_location, arg1, arg2, complain);
|
|
|
|
case MEMBER_REF:
|
|
return build_m_component_ref (cp_build_indirect_ref (loc, arg1,
|
|
RO_ARROW_STAR,
|
|
complain),
|
|
arg2, complain);
|
|
|
|
/* The caller will deal with these. */
|
|
case ADDR_EXPR:
|
|
case COMPONENT_REF:
|
|
case COMPOUND_EXPR:
|
|
return NULL_TREE;
|
|
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Build a new call to operator[]. This may change ARGS. */
|
|
|
|
tree
|
|
build_op_subscript (const op_location_t &loc, tree obj,
|
|
vec<tree, va_gc> **args, tree *overload,
|
|
tsubst_flags_t complain)
|
|
{
|
|
struct z_candidate *candidates = 0, *cand;
|
|
tree fns, first_mem_arg = NULL_TREE;
|
|
bool any_viable_p;
|
|
tree result = NULL_TREE;
|
|
void *p;
|
|
|
|
auto_cond_timevar tv (TV_OVERLOAD);
|
|
|
|
obj = mark_lvalue_use (obj);
|
|
|
|
if (error_operand_p (obj))
|
|
return error_mark_node;
|
|
|
|
tree type = TREE_TYPE (obj);
|
|
|
|
obj = prep_operand (obj);
|
|
|
|
if (TYPE_BINFO (type))
|
|
{
|
|
fns = lookup_fnfields (TYPE_BINFO (type), ovl_op_identifier (ARRAY_REF),
|
|
1, complain);
|
|
if (fns == error_mark_node)
|
|
return error_mark_node;
|
|
}
|
|
else
|
|
fns = NULL_TREE;
|
|
|
|
if (args != NULL && *args != NULL)
|
|
{
|
|
*args = resolve_args (*args, complain);
|
|
if (*args == NULL)
|
|
return error_mark_node;
|
|
}
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
p = conversion_obstack_alloc (0);
|
|
|
|
if (fns)
|
|
{
|
|
first_mem_arg = obj;
|
|
|
|
add_candidates (BASELINK_FUNCTIONS (fns),
|
|
first_mem_arg, *args, NULL_TREE,
|
|
NULL_TREE, false,
|
|
BASELINK_BINFO (fns), BASELINK_ACCESS_BINFO (fns),
|
|
LOOKUP_NORMAL, &candidates, complain);
|
|
}
|
|
|
|
/* Be strict here because if we choose a bad conversion candidate, the
|
|
errors we get won't mention the call context. */
|
|
candidates = splice_viable (candidates, true, &any_viable_p);
|
|
if (!any_viable_p)
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
auto_diagnostic_group d;
|
|
error ("no match for call to %<%T::operator[] (%A)%>",
|
|
TREE_TYPE (obj), build_tree_list_vec (*args));
|
|
print_z_candidates (loc, candidates);
|
|
}
|
|
result = error_mark_node;
|
|
}
|
|
else
|
|
{
|
|
cand = tourney (candidates, complain);
|
|
if (cand == 0)
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
auto_diagnostic_group d;
|
|
error ("call of %<%T::operator[] (%A)%> is ambiguous",
|
|
TREE_TYPE (obj), build_tree_list_vec (*args));
|
|
print_z_candidates (loc, candidates);
|
|
}
|
|
result = error_mark_node;
|
|
}
|
|
else if (TREE_CODE (cand->fn) == FUNCTION_DECL
|
|
&& DECL_OVERLOADED_OPERATOR_P (cand->fn)
|
|
&& DECL_OVERLOADED_OPERATOR_IS (cand->fn, ARRAY_REF))
|
|
{
|
|
if (overload)
|
|
*overload = cand->fn;
|
|
result = build_over_call (cand, LOOKUP_NORMAL, complain);
|
|
if (trivial_fn_p (cand->fn) || DECL_IMMEDIATE_FUNCTION_P (cand->fn))
|
|
/* There won't be a CALL_EXPR. */;
|
|
else if (result && result != error_mark_node)
|
|
{
|
|
tree call = extract_call_expr (result);
|
|
CALL_EXPR_OPERATOR_SYNTAX (call) = true;
|
|
|
|
/* Specify evaluation order as per P0145R2. */
|
|
CALL_EXPR_ORDERED_ARGS (call) = op_is_ordered (ARRAY_REF) == 1;
|
|
}
|
|
}
|
|
else
|
|
gcc_unreachable ();
|
|
}
|
|
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
return result;
|
|
}
|
|
|
|
/* CALL was returned by some call-building function; extract the actual
|
|
CALL_EXPR from any bits that have been tacked on, e.g. by
|
|
convert_from_reference. */
|
|
|
|
tree
|
|
extract_call_expr (tree call)
|
|
{
|
|
while (TREE_CODE (call) == COMPOUND_EXPR)
|
|
call = TREE_OPERAND (call, 1);
|
|
if (REFERENCE_REF_P (call))
|
|
call = TREE_OPERAND (call, 0);
|
|
if (TREE_CODE (call) == TARGET_EXPR)
|
|
call = TARGET_EXPR_INITIAL (call);
|
|
if (cxx_dialect >= cxx20)
|
|
switch (TREE_CODE (call))
|
|
{
|
|
/* C++20 rewritten comparison operators. */
|
|
case TRUTH_NOT_EXPR:
|
|
call = TREE_OPERAND (call, 0);
|
|
break;
|
|
case LT_EXPR:
|
|
case LE_EXPR:
|
|
case GT_EXPR:
|
|
case GE_EXPR:
|
|
case SPACESHIP_EXPR:
|
|
{
|
|
tree op0 = TREE_OPERAND (call, 0);
|
|
if (integer_zerop (op0))
|
|
call = TREE_OPERAND (call, 1);
|
|
else
|
|
call = op0;
|
|
}
|
|
break;
|
|
default:;
|
|
}
|
|
|
|
if (TREE_CODE (call) != CALL_EXPR
|
|
&& TREE_CODE (call) != AGGR_INIT_EXPR
|
|
&& call != error_mark_node)
|
|
return NULL_TREE;
|
|
return call;
|
|
}
|
|
|
|
/* Returns true if FN has two parameters, of which the second has type
|
|
size_t. */
|
|
|
|
static bool
|
|
second_parm_is_size_t (tree fn)
|
|
{
|
|
tree t = FUNCTION_ARG_CHAIN (fn);
|
|
if (!t || !same_type_p (TREE_VALUE (t), size_type_node))
|
|
return false;
|
|
t = TREE_CHAIN (t);
|
|
if (t == void_list_node)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/* True if T, an allocation function, has std::align_val_t as its second
|
|
argument. */
|
|
|
|
bool
|
|
aligned_allocation_fn_p (tree t)
|
|
{
|
|
if (!aligned_new_threshold)
|
|
return false;
|
|
|
|
tree a = FUNCTION_ARG_CHAIN (t);
|
|
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;
|
|
}
|
|
|
|
struct dealloc_info
|
|
{
|
|
bool sized;
|
|
bool aligned;
|
|
tree destroying;
|
|
};
|
|
|
|
/* Returns true iff T, an element of an OVERLOAD chain, is a usual deallocation
|
|
function (3.7.4.2 [basic.stc.dynamic.deallocation]). If so, and DI is
|
|
non-null, also set *DI. */
|
|
|
|
static bool
|
|
usual_deallocation_fn_p (tree t, dealloc_info *di)
|
|
{
|
|
if (di) *di = dealloc_info();
|
|
|
|
/* A template instance is never a usual deallocation function,
|
|
regardless of its signature. */
|
|
if (TREE_CODE (t) == TEMPLATE_DECL
|
|
|| primary_template_specialization_p (t))
|
|
return false;
|
|
|
|
/* A usual deallocation function is a deallocation function whose parameters
|
|
after the first are
|
|
- optionally, a parameter of type std::destroying_delete_t, then
|
|
- optionally, a parameter of type std::size_t, then
|
|
- optionally, a parameter of type std::align_val_t. */
|
|
bool global = DECL_NAMESPACE_SCOPE_P (t);
|
|
tree chain = FUNCTION_ARG_CHAIN (t);
|
|
if (chain && destroying_delete_p (t))
|
|
{
|
|
if (di) di->destroying = TREE_VALUE (chain);
|
|
chain = TREE_CHAIN (chain);
|
|
}
|
|
if (chain
|
|
&& (!global || flag_sized_deallocation)
|
|
&& same_type_p (TREE_VALUE (chain), size_type_node))
|
|
{
|
|
if (di) di->sized = true;
|
|
chain = TREE_CHAIN (chain);
|
|
}
|
|
if (chain && aligned_new_threshold
|
|
&& same_type_p (TREE_VALUE (chain), align_type_node))
|
|
{
|
|
if (di) di->aligned = true;
|
|
chain = TREE_CHAIN (chain);
|
|
}
|
|
return (chain == void_list_node);
|
|
}
|
|
|
|
/* Just return whether FN is a usual deallocation function. */
|
|
|
|
bool
|
|
usual_deallocation_fn_p (tree fn)
|
|
{
|
|
return usual_deallocation_fn_p (fn, NULL);
|
|
}
|
|
|
|
/* Build a call to operator delete. This has to be handled very specially,
|
|
because the restrictions on what signatures match are different from all
|
|
other call instances. For a normal delete, only a delete taking (void *)
|
|
or (void *, size_t) is accepted. For a placement delete, only an exact
|
|
match with the placement new is accepted.
|
|
|
|
CODE is either DELETE_EXPR or VEC_DELETE_EXPR.
|
|
ADDR is the pointer to be deleted.
|
|
SIZE is the size of the memory block to be deleted.
|
|
GLOBAL_P is true if the delete-expression should not consider
|
|
class-specific delete operators.
|
|
PLACEMENT is the corresponding placement new call, or NULL_TREE.
|
|
|
|
If this call to "operator delete" is being generated as part to
|
|
deallocate memory allocated via a new-expression (as per [expr.new]
|
|
which requires that if the initialization throws an exception then
|
|
we call a deallocation function), then ALLOC_FN is the allocation
|
|
function. */
|
|
|
|
tree
|
|
build_op_delete_call (enum tree_code code, tree addr, tree size,
|
|
bool global_p, tree placement,
|
|
tree alloc_fn, tsubst_flags_t complain)
|
|
{
|
|
tree fn = NULL_TREE;
|
|
tree fns, fnname, type, t;
|
|
dealloc_info di_fn = { };
|
|
|
|
if (addr == error_mark_node)
|
|
return error_mark_node;
|
|
|
|
type = strip_array_types (TREE_TYPE (TREE_TYPE (addr)));
|
|
|
|
fnname = ovl_op_identifier (false, code);
|
|
|
|
if (CLASS_TYPE_P (type)
|
|
&& COMPLETE_TYPE_P (complete_type (type))
|
|
&& !global_p)
|
|
/* In [class.free]
|
|
|
|
If the result of the lookup is ambiguous or inaccessible, or if
|
|
the lookup selects a placement deallocation function, the
|
|
program is ill-formed.
|
|
|
|
Therefore, we ask lookup_fnfields to complain about ambiguity. */
|
|
{
|
|
fns = lookup_fnfields (TYPE_BINFO (type), fnname, 1, complain);
|
|
if (fns == error_mark_node)
|
|
return error_mark_node;
|
|
}
|
|
else
|
|
fns = NULL_TREE;
|
|
|
|
if (fns == NULL_TREE)
|
|
fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE);
|
|
|
|
/* Strip const and volatile from addr. */
|
|
tree oaddr = addr;
|
|
addr = cp_convert (ptr_type_node, addr, complain);
|
|
|
|
tree excluded_destroying = NULL_TREE;
|
|
|
|
if (placement)
|
|
{
|
|
/* "A declaration of a placement deallocation function matches the
|
|
declaration of a placement allocation function if it has the same
|
|
number of parameters and, after parameter transformations (8.3.5),
|
|
all parameter types except the first are identical."
|
|
|
|
So we build up the function type we want and ask instantiate_type
|
|
to get it for us. */
|
|
t = FUNCTION_ARG_CHAIN (alloc_fn);
|
|
t = tree_cons (NULL_TREE, ptr_type_node, t);
|
|
t = build_function_type (void_type_node, t);
|
|
|
|
fn = instantiate_type (t, fns, tf_none);
|
|
if (fn == error_mark_node)
|
|
return NULL_TREE;
|
|
|
|
fn = MAYBE_BASELINK_FUNCTIONS (fn);
|
|
|
|
/* "If the lookup finds the two-parameter form of a usual deallocation
|
|
function (3.7.4.2) and that function, considered as a placement
|
|
deallocation function, would have been selected as a match for the
|
|
allocation function, the program is ill-formed." */
|
|
if (second_parm_is_size_t (fn))
|
|
{
|
|
const char *const msg1
|
|
= G_("exception cleanup for this placement new selects "
|
|
"non-placement %<operator delete%>");
|
|
const char *const msg2
|
|
= G_("%qD is a usual (non-placement) deallocation "
|
|
"function in C++14 (or with %<-fsized-deallocation%>)");
|
|
|
|
/* But if the class has an operator delete (void *), then that is
|
|
the usual deallocation function, so we shouldn't complain
|
|
about using the operator delete (void *, size_t). */
|
|
if (DECL_CLASS_SCOPE_P (fn))
|
|
for (tree elt : lkp_range (MAYBE_BASELINK_FUNCTIONS (fns)))
|
|
{
|
|
if (usual_deallocation_fn_p (elt)
|
|
&& FUNCTION_ARG_CHAIN (elt) == void_list_node)
|
|
goto ok;
|
|
}
|
|
/* Before C++14 a two-parameter global deallocation function is
|
|
always a placement deallocation function, but warn if
|
|
-Wc++14-compat. */
|
|
else if (!flag_sized_deallocation)
|
|
{
|
|
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. */
|
|
if (DECL_NAMESPACE_SCOPE_P (fn))
|
|
inform (DECL_SOURCE_LOCATION (fn), msg2, fn);
|
|
else
|
|
inform (DECL_SOURCE_LOCATION (fn),
|
|
"%qD is a usual (non-placement) deallocation "
|
|
"function", fn);
|
|
}
|
|
}
|
|
else
|
|
return error_mark_node;
|
|
ok:;
|
|
}
|
|
}
|
|
else
|
|
/* "Any non-placement deallocation function matches a non-placement
|
|
allocation function. If the lookup finds a single matching
|
|
deallocation function, that function will be called; otherwise, no
|
|
deallocation function will be called." */
|
|
for (tree elt : lkp_range (MAYBE_BASELINK_FUNCTIONS (fns)))
|
|
{
|
|
dealloc_info di_elt;
|
|
if (usual_deallocation_fn_p (elt, &di_elt))
|
|
{
|
|
/* If we're called for an EH cleanup in a new-expression, we can't
|
|
use a destroying delete; the exception was thrown before the
|
|
object was constructed. */
|
|
if (alloc_fn && di_elt.destroying)
|
|
{
|
|
excluded_destroying = elt;
|
|
continue;
|
|
}
|
|
|
|
if (!fn)
|
|
{
|
|
fn = elt;
|
|
di_fn = di_elt;
|
|
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. */
|
|
if (di_elt.destroying != di_fn.destroying)
|
|
{
|
|
if (di_elt.destroying)
|
|
{
|
|
fn = elt;
|
|
di_fn = di_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
|
|
preferred function is found, that function is selected and the
|
|
selection process terminates. If more than one preferred
|
|
function is found, all non-preferred functions are eliminated
|
|
from further consideration. */
|
|
if (aligned_new_threshold)
|
|
{
|
|
bool want_align = type_has_new_extended_alignment (type);
|
|
if (di_elt.aligned != di_fn.aligned)
|
|
{
|
|
if (want_align == di_elt.aligned)
|
|
{
|
|
fn = elt;
|
|
di_fn = di_elt;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* -- If the deallocation functions have class scope, the one
|
|
without a parameter of type std::size_t is selected. */
|
|
bool want_size;
|
|
if (DECL_CLASS_SCOPE_P (fn))
|
|
want_size = false;
|
|
|
|
/* -- If the type is complete and if, for the second alternative
|
|
(delete array) only, the operand is a pointer to a class type
|
|
with a non-trivial destructor or a (possibly multi-dimensional)
|
|
array thereof, the function with a parameter of type std::size_t
|
|
is selected.
|
|
|
|
-- Otherwise, it is unspecified whether a deallocation function
|
|
with a parameter of type std::size_t is selected. */
|
|
else
|
|
{
|
|
want_size = COMPLETE_TYPE_P (type);
|
|
if (code == VEC_DELETE_EXPR
|
|
&& !TYPE_VEC_NEW_USES_COOKIE (type))
|
|
/* We need a cookie to determine the array size. */
|
|
want_size = false;
|
|
}
|
|
gcc_assert (di_fn.sized != di_elt.sized);
|
|
if (want_size == di_elt.sized)
|
|
{
|
|
fn = elt;
|
|
di_fn = di_elt;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If we have a matching function, call it. */
|
|
if (fn)
|
|
{
|
|
gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
|
|
|
|
/* If the FN is a member function, make sure that it is
|
|
accessible. */
|
|
if (BASELINK_P (fns))
|
|
perform_or_defer_access_check (BASELINK_BINFO (fns), fn, fn,
|
|
complain);
|
|
|
|
/* Core issue 901: It's ok to new a type with deleted delete. */
|
|
if (DECL_DELETED_FN (fn) && alloc_fn)
|
|
return NULL_TREE;
|
|
|
|
tree ret;
|
|
if (placement)
|
|
{
|
|
/* The placement args might not be suitable for overload
|
|
resolution at this point, so build the call directly. */
|
|
int nargs = call_expr_nargs (placement);
|
|
tree *argarray = XALLOCAVEC (tree, nargs);
|
|
int i;
|
|
argarray[0] = addr;
|
|
for (i = 1; i < nargs; i++)
|
|
argarray[i] = CALL_EXPR_ARG (placement, i);
|
|
if (!mark_used (fn, complain) && !(complain & tf_error))
|
|
return error_mark_node;
|
|
ret = build_cxx_call (fn, nargs, argarray, complain);
|
|
}
|
|
else
|
|
{
|
|
tree destroying = di_fn.destroying;
|
|
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 (input_location,
|
|
destroying, NULL_TREE,
|
|
complain);
|
|
}
|
|
|
|
releasing_vec args;
|
|
args->quick_push (addr);
|
|
if (destroying)
|
|
args->quick_push (destroying);
|
|
if (di_fn.sized)
|
|
args->quick_push (size);
|
|
if (di_fn.aligned)
|
|
{
|
|
tree al = build_int_cst (align_type_node, TYPE_ALIGN_UNIT (type));
|
|
args->quick_push (al);
|
|
}
|
|
ret = cp_build_function_call_vec (fn, &args, complain);
|
|
}
|
|
|
|
/* Set this flag for all callers of this function. In addition to
|
|
delete-expressions, this is called for deallocating coroutine state;
|
|
treat that as an implicit delete-expression. This is also called for
|
|
the delete if the constructor throws in a new-expression, and for a
|
|
deleting destructor (which implements a delete-expression). */
|
|
/* But leave this flag off for destroying delete to avoid wrong
|
|
assumptions in the optimizers. */
|
|
tree call = extract_call_expr (ret);
|
|
if (TREE_CODE (call) == CALL_EXPR && !destroying_delete_p (fn))
|
|
CALL_FROM_NEW_OR_DELETE_P (call) = 1;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* If there's only a destroying delete that we can't use because the
|
|
object isn't constructed yet, and we used global new, use global
|
|
delete as well. */
|
|
if (excluded_destroying
|
|
&& DECL_NAMESPACE_SCOPE_P (alloc_fn))
|
|
return build_op_delete_call (code, addr, size, true, placement,
|
|
alloc_fn, complain);
|
|
|
|
/* [expr.new]
|
|
|
|
If no unambiguous matching deallocation function can be found,
|
|
propagating the exception does not cause the object's memory to
|
|
be freed. */
|
|
if (alloc_fn)
|
|
{
|
|
if ((complain & tf_warning)
|
|
&& !placement)
|
|
{
|
|
bool w = warning (0,
|
|
"no corresponding deallocation function for %qD",
|
|
alloc_fn);
|
|
if (w && excluded_destroying)
|
|
inform (DECL_SOURCE_LOCATION (excluded_destroying), "destroying "
|
|
"delete %qD cannot be used to release the allocated memory"
|
|
" if the initialization throws because the object is not "
|
|
"constructed yet", excluded_destroying);
|
|
}
|
|
return NULL_TREE;
|
|
}
|
|
|
|
if (complain & tf_error)
|
|
error ("no suitable %<operator %s%> for %qT",
|
|
OVL_OP_INFO (false, code)->name, type);
|
|
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.
|
|
|
|
DIAG_DECL and DIAG_LOCATION will almost always be the same.
|
|
DIAG_LOCATION is just another DECL. NO_ACCESS_REASON is an optional
|
|
parameter used to specify why DECL wasn't accessible (e.g. ak_private
|
|
would be because DECL was private). If not using NO_ACCESS_REASON,
|
|
then it must be ak_none, and the access failure reason will be
|
|
figured out by looking at the protection of DECL. */
|
|
|
|
void
|
|
complain_about_access (tree decl, tree diag_decl, tree diag_location,
|
|
bool issue_error, access_kind no_access_reason)
|
|
{
|
|
/* If we have not already figured out why DECL is inaccessible... */
|
|
if (no_access_reason == ak_none)
|
|
{
|
|
/* Examine the access of DECL to find out why. */
|
|
if (TREE_PRIVATE (decl))
|
|
no_access_reason = ak_private;
|
|
else if (TREE_PROTECTED (decl))
|
|
no_access_reason = ak_protected;
|
|
}
|
|
|
|
/* Now generate an error message depending on calculated access. */
|
|
if (no_access_reason == ak_private)
|
|
{
|
|
if (issue_error)
|
|
error ("%q#D is private within this context", diag_decl);
|
|
inform (DECL_SOURCE_LOCATION (diag_location), "declared private here");
|
|
}
|
|
else if (no_access_reason == ak_protected)
|
|
{
|
|
if (issue_error)
|
|
error ("%q#D is protected within this context", diag_decl);
|
|
inform (DECL_SOURCE_LOCATION (diag_location), "declared protected here");
|
|
}
|
|
/* Couldn't figure out why DECL is inaccesible, so just say it's
|
|
inaccessible. */
|
|
else
|
|
{
|
|
if (issue_error)
|
|
error ("%q#D is inaccessible within this context", diag_decl);
|
|
inform (DECL_SOURCE_LOCATION (diag_decl), "declared here");
|
|
}
|
|
}
|
|
|
|
/* Initialize a temporary of type TYPE with EXPR. The FLAGS are a
|
|
bitwise or of LOOKUP_* values. If any errors are warnings are
|
|
generated, set *DIAGNOSTIC_FN to "error" or "warning",
|
|
respectively. If no diagnostics are generated, set *DIAGNOSTIC_FN
|
|
to NULL. */
|
|
|
|
static tree
|
|
build_temp (tree expr, tree type, int flags,
|
|
diagnostic_t *diagnostic_kind, tsubst_flags_t complain)
|
|
{
|
|
int savew, savee;
|
|
|
|
*diagnostic_kind = DK_UNSPECIFIED;
|
|
|
|
/* If the source is a packed field, calling the copy constructor will require
|
|
binding the field to the reference parameter to the copy constructor, and
|
|
we'll end up with an infinite loop. If we can use a bitwise copy, then
|
|
do that now. */
|
|
if ((lvalue_kind (expr) & clk_packed)
|
|
&& CLASS_TYPE_P (TREE_TYPE (expr))
|
|
&& !type_has_nontrivial_copy_init (TREE_TYPE (expr)))
|
|
return get_target_expr_sfinae (expr, complain);
|
|
|
|
/* In decltype, we might have decided not to wrap this call in a TARGET_EXPR.
|
|
But it turns out to be a subexpression, so perform temporary
|
|
materialization now. */
|
|
if (TREE_CODE (expr) == CALL_EXPR
|
|
&& CLASS_TYPE_P (type)
|
|
&& same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (expr)))
|
|
expr = build_cplus_new (type, expr, complain);
|
|
|
|
savew = warningcount + werrorcount, savee = errorcount;
|
|
releasing_vec args (make_tree_vector_single (expr));
|
|
expr = build_special_member_call (NULL_TREE, complete_ctor_identifier,
|
|
&args, type, flags, complain);
|
|
if (warningcount + werrorcount > savew)
|
|
*diagnostic_kind = DK_WARNING;
|
|
else if (errorcount > savee)
|
|
*diagnostic_kind = DK_ERROR;
|
|
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. */
|
|
|
|
static void
|
|
conversion_null_warnings (tree totype, tree expr, tree fn, int argnum)
|
|
{
|
|
/* Issue warnings about peculiar, but valid, uses of NULL. */
|
|
if (TREE_CODE (totype) != BOOLEAN_TYPE
|
|
&& ARITHMETIC_TYPE_P (totype)
|
|
&& null_node_p (expr))
|
|
{
|
|
location_t loc = get_location_for_expr_unwinding_for_system_header (expr);
|
|
if (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);
|
|
}
|
|
|
|
/* Issue warnings if "false" is converted to a NULL pointer */
|
|
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)
|
|
{
|
|
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 (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 ((TYPE_PTR_OR_PTRMEM_P (totype) || NULLPTR_TYPE_P (totype))
|
|
&& null_ptr_cst_p (expr))
|
|
{
|
|
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
|
|
standard conversion sequence of a user-defined conversion sequence, say
|
|
which user-defined conversion. */
|
|
|
|
static void
|
|
maybe_print_user_conv_context (conversion *convs)
|
|
{
|
|
if (convs->user_conv_p)
|
|
for (conversion *t = convs; t; t = next_conversion (t))
|
|
if (t->kind == ck_user)
|
|
{
|
|
print_z_candidate (0, N_(" after user-defined conversion:"),
|
|
t->cand);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Locate the parameter with the given index within FNDECL.
|
|
ARGNUM is zero based, -1 indicates the `this' argument of a method.
|
|
Return the location of the FNDECL itself if there are problems. */
|
|
|
|
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;
|
|
|
|
/* Locate param by index within DECL_ARGUMENTS (fndecl). */
|
|
for (i = 0, param = FUNCTION_FIRST_USER_PARM (fndecl);
|
|
i < argnum && param;
|
|
i++, param = TREE_CHAIN (param))
|
|
;
|
|
|
|
/* If something went wrong (e.g. if we have a builtin and thus no arguments),
|
|
return the location of FNDECL. */
|
|
if (param == NULL)
|
|
return DECL_SOURCE_LOCATION (fndecl);
|
|
|
|
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);
|
|
}
|
|
|
|
/* Maybe warn about C++20 Conversions to arrays of unknown bound. C is
|
|
the conversion, EXPR is the expression we're converting. */
|
|
|
|
static void
|
|
maybe_warn_array_conv (location_t loc, conversion *c, tree expr)
|
|
{
|
|
if (cxx_dialect >= cxx20)
|
|
return;
|
|
|
|
tree type = TREE_TYPE (expr);
|
|
type = strip_pointer_operator (type);
|
|
|
|
if (TREE_CODE (type) != ARRAY_TYPE
|
|
|| TYPE_DOMAIN (type) == NULL_TREE)
|
|
return;
|
|
|
|
if (pedantic && conv_binds_to_array_of_unknown_bound (c))
|
|
pedwarn (loc, OPT_Wc__20_extensions,
|
|
"conversions to arrays of unknown bound "
|
|
"are only available with %<-std=c++20%> or %<-std=gnu++20%>");
|
|
}
|
|
|
|
/* We call this recursively in convert_like_internal. */
|
|
static tree convert_like (conversion *, tree, tree, int, bool, bool,
|
|
tsubst_flags_t);
|
|
|
|
/* 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
|
|
being called to continue a conversion chain. It is negative when a
|
|
reference binding will be applied, positive otherwise. If
|
|
ISSUE_CONVERSION_WARNINGS is true, warnings about suspicious
|
|
conversions will be emitted if appropriate. If C_CAST_P is true,
|
|
this conversion is coming from a C-style cast; in that case,
|
|
conversions to inaccessible bases are permitted. */
|
|
|
|
static tree
|
|
convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
|
|
bool issue_conversion_warnings, bool c_cast_p,
|
|
tsubst_flags_t complain)
|
|
{
|
|
tree totype = convs->type;
|
|
diagnostic_t diag_kind;
|
|
int flags;
|
|
location_t loc = cp_expr_loc_or_input_loc (expr);
|
|
|
|
if (convs->bad_p && !(complain & tf_error))
|
|
return error_mark_node;
|
|
|
|
if (convs->bad_p
|
|
&& convs->kind != ck_user
|
|
&& convs->kind != ck_list
|
|
&& convs->kind != ck_ambig
|
|
&& (convs->kind != ck_ref_bind
|
|
|| (convs->user_conv_p && next_conversion (convs)->bad_p))
|
|
&& (convs->kind != ck_rvalue
|
|
|| SCALAR_TYPE_P (totype))
|
|
&& convs->kind != ck_base)
|
|
{
|
|
bool complained = false;
|
|
conversion *t = convs;
|
|
|
|
/* Give a helpful error if this is bad because of excess braces. */
|
|
if (BRACE_ENCLOSED_INITIALIZER_P (expr)
|
|
&& SCALAR_TYPE_P (totype)
|
|
&& CONSTRUCTOR_NELTS (expr) > 0
|
|
&& BRACE_ENCLOSED_INITIALIZER_P (CONSTRUCTOR_ELT (expr, 0)->value))
|
|
{
|
|
complained = permerror (loc, "too many braces around initializer "
|
|
"for %qT", totype);
|
|
while (BRACE_ENCLOSED_INITIALIZER_P (expr)
|
|
&& CONSTRUCTOR_NELTS (expr) == 1)
|
|
expr = CONSTRUCTOR_ELT (expr, 0)->value;
|
|
}
|
|
|
|
/* Give a helpful error if this is bad because a conversion to bool
|
|
from std::nullptr_t requires direct-initialization. */
|
|
if (NULLPTR_TYPE_P (TREE_TYPE (expr))
|
|
&& TREE_CODE (totype) == BOOLEAN_TYPE)
|
|
complained = permerror (loc, "converting to %qH from %qI requires "
|
|
"direct-initialization",
|
|
totype, TREE_TYPE (expr));
|
|
|
|
for (; t ; t = next_conversion (t))
|
|
{
|
|
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);
|
|
if (complained)
|
|
print_z_candidate (loc, N_("candidate is:"), t->cand);
|
|
expr = convert_like (t, expr, fn, argnum,
|
|
/*issue_conversion_warnings=*/false,
|
|
/*c_cast_p=*/false, complain);
|
|
if (convs->kind == ck_ref_bind)
|
|
expr = convert_to_reference (totype, expr, CONV_IMPLICIT,
|
|
LOOKUP_NORMAL, NULL_TREE,
|
|
complain);
|
|
else
|
|
expr = cp_convert (totype, expr, complain);
|
|
if (complained)
|
|
maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
|
|
return expr;
|
|
}
|
|
else if (t->kind == ck_user || !t->bad_p)
|
|
{
|
|
expr = convert_like (t, expr, fn, argnum,
|
|
/*issue_conversion_warnings=*/false,
|
|
/*c_cast_p=*/false, complain);
|
|
break;
|
|
}
|
|
else if (t->kind == ck_ambig)
|
|
return convert_like (t, expr, fn, argnum,
|
|
/*issue_conversion_warnings=*/false,
|
|
/*c_cast_p=*/false, complain);
|
|
else if (t->kind == ck_identity)
|
|
break;
|
|
}
|
|
if (!complained && expr != error_mark_node)
|
|
{
|
|
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 (issue_conversion_warnings && (complain & tf_warning))
|
|
conversion_null_warnings (totype, expr, fn, argnum);
|
|
|
|
switch (convs->kind)
|
|
{
|
|
case ck_user:
|
|
{
|
|
struct z_candidate *cand = convs->cand;
|
|
|
|
if (cand == NULL)
|
|
/* We chose the surrogate function from add_conv_candidate, now we
|
|
actually need to build the conversion. */
|
|
cand = build_user_type_conversion_1 (totype, expr,
|
|
LOOKUP_NO_CONVERSION, complain);
|
|
|
|
tree convfn = cand->fn;
|
|
|
|
/* When converting from an init list we consider explicit
|
|
constructors, but actually trying to call one is an error. */
|
|
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) || convs->need_temporary_p)
|
|
/* And in C++98 a default constructor can't be explicit. */
|
|
&& cxx_dialect >= cxx11)
|
|
{
|
|
if (!(complain & tf_error))
|
|
return error_mark_node;
|
|
location_t loc = location_of (expr);
|
|
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))
|
|
inform (loc, "in C++11 and above a default constructor "
|
|
"can be explicit");
|
|
}
|
|
else
|
|
error ("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)
|
|
&& !processing_template_decl)
|
|
{
|
|
bool direct = CONSTRUCTOR_IS_DIRECT_INIT (expr);
|
|
if (abstract_virtuals_error_sfinae (NULL_TREE, totype, complain))
|
|
return error_mark_node;
|
|
expr = build_value_init (totype, complain);
|
|
expr = get_target_expr_sfinae (expr, complain);
|
|
if (expr != error_mark_node)
|
|
{
|
|
TARGET_EXPR_LIST_INIT_P (expr) = true;
|
|
TARGET_EXPR_DIRECT_INIT_P (expr) = direct;
|
|
}
|
|
return 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. */
|
|
expr = build_over_call (cand, LOOKUP_NORMAL|LOOKUP_NO_CONVERSION,
|
|
complain);
|
|
|
|
/* If this is a constructor or a function returning an aggr type,
|
|
we need to build up a TARGET_EXPR. */
|
|
if (DECL_CONSTRUCTOR_P (convfn))
|
|
{
|
|
expr = build_cplus_new (totype, expr, complain);
|
|
|
|
/* Remember that this was list-initialization. */
|
|
if (convs->check_narrowing && expr != error_mark_node)
|
|
TARGET_EXPR_LIST_INIT_P (expr) = true;
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
case ck_identity:
|
|
if (BRACE_ENCLOSED_INITIALIZER_P (expr))
|
|
{
|
|
int nelts = CONSTRUCTOR_NELTS (expr);
|
|
if (nelts == 0)
|
|
expr = build_value_init (totype, complain);
|
|
else if (nelts == 1)
|
|
expr = CONSTRUCTOR_ELT (expr, 0)->value;
|
|
else
|
|
gcc_unreachable ();
|
|
}
|
|
expr = mark_use (expr, /*rvalue_p=*/!convs->rvaluedness_matches_p,
|
|
/*read_p=*/true, UNKNOWN_LOCATION,
|
|
/*reject_builtin=*/true);
|
|
|
|
if (type_unknown_p (expr))
|
|
expr = instantiate_type (totype, expr, complain);
|
|
if (expr == null_node
|
|
&& INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (totype))
|
|
/* If __null has been converted to an integer type, we do not want to
|
|
continue to warn about uses of EXPR as an integer, rather than as a
|
|
pointer. */
|
|
expr = build_int_cst (totype, 0);
|
|
return expr;
|
|
case ck_ambig:
|
|
/* We leave bad_p off ck_ambig because overload resolution considers
|
|
it valid, it just fails when we try to perform it. So we need to
|
|
check complain here, too. */
|
|
if (complain & tf_error)
|
|
{
|
|
/* Call build_user_type_conversion again for the error. */
|
|
int flags = (convs->need_temporary_p
|
|
? LOOKUP_IMPLICIT : LOOKUP_NORMAL);
|
|
build_user_type_conversion (totype, convs->u.expr, flags, complain);
|
|
gcc_assert (seen_error ());
|
|
maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
|
|
}
|
|
return error_mark_node;
|
|
|
|
case ck_list:
|
|
{
|
|
/* Conversion to std::initializer_list<T>. */
|
|
tree elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (totype), 0);
|
|
unsigned len = CONSTRUCTOR_NELTS (expr);
|
|
tree array;
|
|
|
|
if (len)
|
|
{
|
|
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 (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);
|
|
}
|
|
else
|
|
array = nullptr_node;
|
|
|
|
array = cp_convert (build_pointer_type (elttype), array, complain);
|
|
if (array == error_mark_node)
|
|
return error_mark_node;
|
|
|
|
/* Build up the initializer_list object. Note: fail gracefully
|
|
if the object cannot be completed because, for example, no
|
|
definition is provided (c++/80956). */
|
|
totype = complete_type_or_maybe_complain (totype, NULL_TREE, complain);
|
|
if (!totype)
|
|
return error_mark_node;
|
|
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));
|
|
tree new_ctor = build_constructor (totype, vec);
|
|
return get_target_expr_sfinae (new_ctor, complain);
|
|
}
|
|
|
|
case ck_aggr:
|
|
if (TREE_CODE (totype) == COMPLEX_TYPE)
|
|
{
|
|
tree real = CONSTRUCTOR_ELT (expr, 0)->value;
|
|
tree imag = CONSTRUCTOR_ELT (expr, 1)->value;
|
|
real = perform_implicit_conversion (TREE_TYPE (totype),
|
|
real, complain);
|
|
imag = perform_implicit_conversion (TREE_TYPE (totype),
|
|
imag, complain);
|
|
expr = build2 (COMPLEX_EXPR, totype, real, imag);
|
|
return expr;
|
|
}
|
|
expr = reshape_init (totype, expr, complain);
|
|
expr = get_target_expr_sfinae (digest_init (totype, expr, complain),
|
|
complain);
|
|
if (expr != error_mark_node)
|
|
TARGET_EXPR_LIST_INIT_P (expr) = true;
|
|
return expr;
|
|
|
|
default:
|
|
break;
|
|
};
|
|
|
|
expr = convert_like (next_conversion (convs), expr, fn, argnum,
|
|
convs->kind == ck_ref_bind
|
|
? issue_conversion_warnings : false,
|
|
c_cast_p, complain & ~tf_no_cleanup);
|
|
if (expr == error_mark_node)
|
|
return error_mark_node;
|
|
|
|
switch (convs->kind)
|
|
{
|
|
case ck_rvalue:
|
|
expr = decay_conversion (expr, complain);
|
|
if (expr == error_mark_node)
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
auto_diagnostic_group d;
|
|
maybe_print_user_conv_context (convs);
|
|
maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
|
|
}
|
|
return error_mark_node;
|
|
}
|
|
|
|
if (! MAYBE_CLASS_TYPE_P (totype))
|
|
return expr;
|
|
|
|
/* Don't introduce copies when passing arguments along to the inherited
|
|
constructor. */
|
|
if (current_function_decl
|
|
&& flag_new_inheriting_ctors
|
|
&& DECL_INHERITED_CTOR (current_function_decl))
|
|
return expr;
|
|
|
|
if (TREE_CODE (expr) == TARGET_EXPR
|
|
&& TARGET_EXPR_LIST_INIT_P (expr))
|
|
/* Copy-list-initialization doesn't actually involve a copy. */
|
|
return expr;
|
|
|
|
/* Fall through. */
|
|
case ck_base:
|
|
if (convs->kind == ck_base && !convs->need_temporary_p)
|
|
{
|
|
/* We are going to bind a reference directly to a base-class
|
|
subobject of EXPR. */
|
|
/* Build an expression for `*((base*) &expr)'. */
|
|
expr = convert_to_base (expr, totype,
|
|
!c_cast_p, /*nonnull=*/true, complain);
|
|
return expr;
|
|
}
|
|
|
|
/* Copy-initialization where the cv-unqualified version of the source
|
|
type is the same class as, or a derived class of, the class of the
|
|
destination [is treated as direct-initialization]. [dcl.init] */
|
|
flags = LOOKUP_NORMAL;
|
|
/* This conversion is being done in the context of a user-defined
|
|
conversion (i.e. the second step of copy-initialization), so
|
|
don't allow any more. */
|
|
if (convs->user_conv_p)
|
|
flags |= LOOKUP_NO_CONVERSION;
|
|
/* We might be performing a conversion of the argument
|
|
to the user-defined conversion, i.e., not a conversion of the
|
|
result of the user-defined conversion. In which case we skip
|
|
explicit constructors. */
|
|
if (convs->copy_init_p)
|
|
flags |= LOOKUP_ONLYCONVERTING;
|
|
if (convs->rvaluedness_matches_p)
|
|
/* standard_conversion got LOOKUP_PREFER_RVALUE. */
|
|
flags |= LOOKUP_PREFER_RVALUE;
|
|
expr = build_temp (expr, totype, flags, &diag_kind, complain);
|
|
if (diag_kind && complain)
|
|
{
|
|
auto_diagnostic_group d;
|
|
maybe_print_user_conv_context (convs);
|
|
maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
|
|
}
|
|
|
|
return build_cplus_new (totype, expr, complain);
|
|
|
|
case ck_ref_bind:
|
|
{
|
|
tree ref_type = totype;
|
|
|
|
/* direct_reference_binding might have inserted a ck_qual under
|
|
this ck_ref_bind for the benefit of conversion sequence ranking.
|
|
Ignore the conversion; we'll create our own below. */
|
|
if (next_conversion (convs)->kind == ck_qual
|
|
&& !convs->need_temporary_p)
|
|
{
|
|
gcc_assert (same_type_p (TREE_TYPE (expr),
|
|
next_conversion (convs)->type));
|
|
/* Strip the cast created by the ck_qual; cp_build_addr_expr
|
|
below expects an lvalue. */
|
|
STRIP_NOPS (expr);
|
|
}
|
|
|
|
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 "
|
|
"lvalue of type %qI", totype, extype);
|
|
else if (!TYPE_REF_IS_RVALUE (ref_type) && !lvalue_p (expr)
|
|
&& !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type)))
|
|
{
|
|
conversion *next = next_conversion (convs);
|
|
if (next->kind == ck_std)
|
|
{
|
|
next = next_conversion (next);
|
|
error_at (loc, "cannot bind non-const lvalue reference of "
|
|
"type %qH to a value of type %qI",
|
|
totype, next->type);
|
|
}
|
|
else if (!CP_TYPE_CONST_P (TREE_TYPE (ref_type)))
|
|
error_at (loc, "cannot bind non-const lvalue reference of "
|
|
"type %qH to an rvalue of type %qI", totype, extype);
|
|
else // extype is volatile
|
|
error_at (loc, "cannot bind lvalue reference of type "
|
|
"%qH to an rvalue of type %qI", totype,
|
|
extype);
|
|
}
|
|
else if (!reference_compatible_p (TREE_TYPE (totype), extype))
|
|
{
|
|
/* If we're converting from T[] to T[N], don't talk
|
|
about discarding qualifiers. (Converting from T[N] to
|
|
T[] is allowed by P0388R4.) */
|
|
if (TREE_CODE (extype) == ARRAY_TYPE
|
|
&& TYPE_DOMAIN (extype) == NULL_TREE
|
|
&& TREE_CODE (TREE_TYPE (totype)) == ARRAY_TYPE
|
|
&& TYPE_DOMAIN (TREE_TYPE (totype)) != NULL_TREE)
|
|
error_at (loc, "cannot bind reference of type %qH to %qI "
|
|
"due to different array bounds", totype, extype);
|
|
else
|
|
error_at (loc, "binding reference of type %qH to %qI "
|
|
"discards qualifiers", totype, extype);
|
|
}
|
|
else
|
|
gcc_unreachable ();
|
|
maybe_print_user_conv_context (convs);
|
|
maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
|
|
|
|
return error_mark_node;
|
|
}
|
|
else if (complain & tf_warning)
|
|
maybe_warn_array_conv (loc, convs, expr);
|
|
|
|
/* If necessary, create a temporary.
|
|
|
|
VA_ARG_EXPR and CONSTRUCTOR expressions are special cases
|
|
that need temporaries, even when their types are reference
|
|
compatible with the type of reference being bound, so the
|
|
upcoming call to cp_build_addr_expr doesn't fail. */
|
|
if (convs->need_temporary_p
|
|
|| TREE_CODE (expr) == CONSTRUCTOR
|
|
|| TREE_CODE (expr) == VA_ARG_EXPR)
|
|
{
|
|
/* Otherwise, a temporary of type "cv1 T1" is created and
|
|
initialized from the initializer expression using the rules
|
|
for a non-reference copy-initialization (8.5). */
|
|
|
|
tree type = TREE_TYPE (ref_type);
|
|
cp_lvalue_kind lvalue = lvalue_kind (expr);
|
|
|
|
gcc_assert (similar_type_p (type, next_conversion (convs)->type));
|
|
if (!CP_TYPE_CONST_NON_VOLATILE_P (type)
|
|
&& !TYPE_REF_IS_RVALUE (ref_type))
|
|
{
|
|
/* If the reference is volatile or non-const, we
|
|
cannot create a temporary. */
|
|
if (complain & tf_error)
|
|
{
|
|
if (lvalue & clk_bitfield)
|
|
error_at (loc, "cannot bind bit-field %qE to %qT",
|
|
expr, ref_type);
|
|
else if (lvalue & clk_packed)
|
|
error_at (loc, "cannot bind packed field %qE to %qT",
|
|
expr, ref_type);
|
|
else
|
|
error_at (loc, "cannot bind rvalue %qE to %qT",
|
|
expr, ref_type);
|
|
}
|
|
return error_mark_node;
|
|
}
|
|
/* If the source is a packed field, and we must use a copy
|
|
constructor, then building the target expr will require
|
|
binding the field to the reference parameter to the
|
|
copy constructor, and we'll end up with an infinite
|
|
loop. If we can use a bitwise copy, then we'll be
|
|
OK. */
|
|
if ((lvalue & clk_packed)
|
|
&& CLASS_TYPE_P (type)
|
|
&& type_has_nontrivial_copy_init (type))
|
|
{
|
|
error_at (loc, "cannot bind packed field %qE to %qT",
|
|
expr, ref_type);
|
|
return error_mark_node;
|
|
}
|
|
if (lvalue & clk_bitfield)
|
|
{
|
|
expr = convert_bitfield_to_declared_type (expr);
|
|
expr = fold_convert (type, expr);
|
|
}
|
|
|
|
/* Creating &TARGET_EXPR<> in a template would break when
|
|
tsubsting the expression, so use an IMPLICIT_CONV_EXPR
|
|
instead. This can happen even when there's no class
|
|
involved, e.g., when converting an integer to a reference
|
|
type. */
|
|
if (processing_template_decl)
|
|
return build1 (IMPLICIT_CONV_EXPR, totype, expr);
|
|
expr = build_target_expr_with_type (expr, type, complain);
|
|
}
|
|
|
|
/* Take the address of the thing to which we will bind the
|
|
reference. */
|
|
expr = cp_build_addr_expr (expr, complain);
|
|
if (expr == error_mark_node)
|
|
return error_mark_node;
|
|
|
|
/* Convert it to a pointer to the type referred to by the
|
|
reference. This will adjust the pointer if a derived to
|
|
base conversion is being performed. */
|
|
expr = cp_convert (build_pointer_type (TREE_TYPE (ref_type)),
|
|
expr, complain);
|
|
/* Convert the pointer to the desired reference type. */
|
|
return build_nop (ref_type, expr);
|
|
}
|
|
|
|
case ck_lvalue:
|
|
return decay_conversion (expr, complain);
|
|
|
|
case ck_fnptr:
|
|
/* ??? Should the address of a transaction-safe pointer point to the TM
|
|
clone, and this conversion look up the primary function? */
|
|
return build_nop (totype, expr);
|
|
|
|
case ck_qual:
|
|
/* Warn about deprecated conversion if appropriate. */
|
|
if (complain & tf_warning)
|
|
{
|
|
string_conv_p (totype, expr, 1);
|
|
maybe_warn_array_conv (loc, convs, expr);
|
|
}
|
|
break;
|
|
|
|
case ck_ptr:
|
|
if (convs->base_p)
|
|
expr = convert_to_base (expr, totype, !c_cast_p,
|
|
/*nonnull=*/false, complain);
|
|
return build_nop (totype, expr);
|
|
|
|
case ck_pmem:
|
|
return convert_ptrmem (totype, expr, /*allow_inverse_p=*/false,
|
|
c_cast_p, complain);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (convs->check_narrowing
|
|
&& !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
|
|
expr = cp_convert (totype, expr, complain);
|
|
|
|
return expr;
|
|
}
|
|
|
|
/* Return true if converting FROM to TO is unsafe in a template. */
|
|
|
|
static bool
|
|
conv_unsafe_in_template_p (tree to, tree from)
|
|
{
|
|
/* Converting classes involves TARGET_EXPR. */
|
|
if (CLASS_TYPE_P (to) || CLASS_TYPE_P (from))
|
|
return true;
|
|
|
|
/* Converting real to integer produces FIX_TRUNC_EXPR which tsubst
|
|
doesn't handle. */
|
|
if (SCALAR_FLOAT_TYPE_P (from) && INTEGRAL_OR_ENUMERATION_TYPE_P (to))
|
|
return true;
|
|
|
|
/* Converting integer to real isn't a trivial conversion, either. */
|
|
if (INTEGRAL_OR_ENUMERATION_TYPE_P (from) && SCALAR_FLOAT_TYPE_P (to))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/* Wrapper for convert_like_internal that handles creating
|
|
IMPLICIT_CONV_EXPR. */
|
|
|
|
static tree
|
|
convert_like (conversion *convs, tree expr, tree fn, int argnum,
|
|
bool issue_conversion_warnings, bool c_cast_p,
|
|
tsubst_flags_t complain)
|
|
{
|
|
/* Creating &TARGET_EXPR<> in a template breaks when substituting,
|
|
and creating a CALL_EXPR in a template breaks in finish_call_expr
|
|
so use an IMPLICIT_CONV_EXPR for this conversion. We would have
|
|
created such codes e.g. when calling a user-defined conversion
|
|
function. */
|
|
tree conv_expr = NULL_TREE;
|
|
if (processing_template_decl
|
|
&& convs->kind != ck_identity
|
|
&& conv_unsafe_in_template_p (convs->type, TREE_TYPE (expr)))
|
|
{
|
|
conv_expr = build1 (IMPLICIT_CONV_EXPR, convs->type, expr);
|
|
if (convs->kind != ck_ref_bind)
|
|
conv_expr = convert_from_reference (conv_expr);
|
|
if (!convs->bad_p)
|
|
return conv_expr;
|
|
/* Do the normal processing to give the bad_p errors. But we still
|
|
need to return the IMPLICIT_CONV_EXPR, unless we're returning
|
|
error_mark_node. */
|
|
}
|
|
expr = convert_like_internal (convs, expr, fn, argnum,
|
|
issue_conversion_warnings, c_cast_p, complain);
|
|
if (expr == error_mark_node)
|
|
return error_mark_node;
|
|
return conv_expr ? conv_expr : expr;
|
|
}
|
|
|
|
/* Convenience wrapper for convert_like. */
|
|
|
|
static inline tree
|
|
convert_like (conversion *convs, tree expr, tsubst_flags_t complain)
|
|
{
|
|
return convert_like (convs, expr, NULL_TREE, 0,
|
|
/*issue_conversion_warnings=*/true,
|
|
/*c_cast_p=*/false, complain);
|
|
}
|
|
|
|
/* Convenience wrapper for convert_like. */
|
|
|
|
static inline tree
|
|
convert_like_with_context (conversion *convs, tree expr, tree fn, int argnum,
|
|
tsubst_flags_t complain)
|
|
{
|
|
return convert_like (convs, expr, fn, argnum,
|
|
/*issue_conversion_warnings=*/true,
|
|
/*c_cast_p=*/false, complain);
|
|
}
|
|
|
|
/* ARG is being passed to a varargs function. Perform any conversions
|
|
required. Return the converted value. */
|
|
|
|
tree
|
|
convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain)
|
|
{
|
|
tree arg_type = TREE_TYPE (arg);
|
|
location_t loc = cp_expr_loc_or_input_loc (arg);
|
|
|
|
/* [expr.call]
|
|
|
|
If the argument has integral or enumeration type that is subject
|
|
to the integral promotions (_conv.prom_), or a floating-point
|
|
type that is subject to the floating-point promotion
|
|
(_conv.fpprom_), the value of the argument is converted to the
|
|
promoted type before the call. */
|
|
if (TREE_CODE (arg_type) == REAL_TYPE
|
|
&& (TYPE_PRECISION (arg_type)
|
|
< TYPE_PRECISION (double_type_node))
|
|
&& !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type)))
|
|
{
|
|
if ((complain & tf_warning)
|
|
&& warn_double_promotion && !c_inhibit_evaluation_warnings)
|
|
warning_at (loc, OPT_Wdouble_promotion,
|
|
"implicit conversion from %qH to %qI when passing "
|
|
"argument to function",
|
|
arg_type, double_type_node);
|
|
arg = mark_rvalue_use (arg);
|
|
arg = convert_to_real_nofold (double_type_node, arg);
|
|
}
|
|
else if (NULLPTR_TYPE_P (arg_type))
|
|
{
|
|
arg = mark_rvalue_use (arg);
|
|
if (TREE_SIDE_EFFECTS (arg))
|
|
{
|
|
warning_sentinel w(warn_unused_result);
|
|
arg = cp_build_compound_expr (arg, null_pointer_node, complain);
|
|
}
|
|
else
|
|
arg = null_pointer_node;
|
|
}
|
|
else if (INTEGRAL_OR_ENUMERATION_TYPE_P (arg_type))
|
|
{
|
|
if (SCOPED_ENUM_P (arg_type))
|
|
{
|
|
tree prom = cp_convert (ENUM_UNDERLYING_TYPE (arg_type), arg,
|
|
complain);
|
|
prom = cp_perform_integral_promotions (prom, complain);
|
|
if (abi_version_crosses (6)
|
|
&& 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,
|
|
TREE_TYPE (prom), ENUM_UNDERLYING_TYPE (arg_type));
|
|
if (!abi_version_at_least (6))
|
|
arg = prom;
|
|
}
|
|
else
|
|
arg = cp_perform_integral_promotions (arg, complain);
|
|
}
|
|
else
|
|
/* [expr.call]
|
|
|
|
The lvalue-to-rvalue, array-to-pointer, and function-to-pointer
|
|
standard conversions are performed. */
|
|
arg = decay_conversion (arg, complain);
|
|
|
|
arg = require_complete_type_sfinae (arg, complain);
|
|
arg_type = TREE_TYPE (arg);
|
|
|
|
if (arg != error_mark_node
|
|
/* In a template (or ill-formed code), we can have an incomplete type
|
|
even after require_complete_type_sfinae, in which case we don't know
|
|
whether it has trivial copy or not. */
|
|
&& COMPLETE_TYPE_P (arg_type)
|
|
&& !cp_unevaluated_operand)
|
|
{
|
|
/* [expr.call] 5.2.2/7:
|
|
Passing a potentially-evaluated argument of class type (Clause 9)
|
|
with a non-trivial copy constructor or a non-trivial destructor
|
|
with no corresponding parameter is conditionally-supported, with
|
|
implementation-defined semantics.
|
|
|
|
We support it as pass-by-invisible-reference, just like a normal
|
|
value parameter.
|
|
|
|
If the call appears in the context of a sizeof expression,
|
|
it is not potentially-evaluated. */
|
|
if (type_has_nontrivial_copy_init (arg_type)
|
|
|| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (arg_type))
|
|
{
|
|
arg = force_rvalue (arg, complain);
|
|
if (complain & tf_warning)
|
|
warning (OPT_Wconditionally_supported,
|
|
"passing objects of non-trivially-copyable "
|
|
"type %q#T through %<...%> is conditionally supported",
|
|
arg_type);
|
|
return build1 (ADDR_EXPR, build_reference_type (arg_type), arg);
|
|
}
|
|
/* Build up a real lvalue-to-rvalue conversion in case the
|
|
copy constructor is trivial but not callable. */
|
|
else if (CLASS_TYPE_P (arg_type))
|
|
force_rvalue (arg, complain);
|
|
|
|
}
|
|
|
|
return arg;
|
|
}
|
|
|
|
/* va_arg (EXPR, TYPE) is a builtin. Make sure it is not abused. */
|
|
|
|
tree
|
|
build_x_va_arg (location_t loc, tree expr, tree type)
|
|
{
|
|
if (processing_template_decl)
|
|
{
|
|
tree r = build_min (VA_ARG_EXPR, type, expr);
|
|
SET_EXPR_LOCATION (r, loc);
|
|
return r;
|
|
}
|
|
|
|
type = complete_type_or_else (type, NULL_TREE);
|
|
|
|
if (expr == error_mark_node || !type)
|
|
return error_mark_node;
|
|
|
|
expr = mark_lvalue_use (expr);
|
|
|
|
if (TYPE_REF_P (type))
|
|
{
|
|
error ("cannot receive reference type %qT through %<...%>", type);
|
|
return error_mark_node;
|
|
}
|
|
|
|
if (type_has_nontrivial_copy_init (type)
|
|
|| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
|
|
{
|
|
/* conditionally-supported behavior [expr.call] 5.2.2/7. Let's treat
|
|
it as pass by invisible reference. */
|
|
warning_at (loc, OPT_Wconditionally_supported,
|
|
"receiving objects of non-trivially-copyable type %q#T "
|
|
"through %<...%> is conditionally-supported", type);
|
|
|
|
tree ref = cp_build_reference_type (type, false);
|
|
expr = build_va_arg (loc, expr, ref);
|
|
return convert_from_reference (expr);
|
|
}
|
|
|
|
tree ret = build_va_arg (loc, expr, type);
|
|
if (CLASS_TYPE_P (type))
|
|
/* Wrap the VA_ARG_EXPR in a TARGET_EXPR now so other code doesn't need to
|
|
know how to handle it. */
|
|
ret = get_target_expr (ret);
|
|
return ret;
|
|
}
|
|
|
|
/* TYPE has been given to va_arg. Apply the default conversions which
|
|
would have happened when passed via ellipsis. Return the promoted
|
|
type, or the passed type if there is no change. */
|
|
|
|
tree
|
|
cxx_type_promotes_to (tree type)
|
|
{
|
|
tree promote;
|
|
|
|
/* Perform the array-to-pointer and function-to-pointer
|
|
conversions. */
|
|
type = type_decays_to (type);
|
|
|
|
promote = type_promotes_to (type);
|
|
if (same_type_p (type, promote))
|
|
promote = type;
|
|
|
|
return promote;
|
|
}
|
|
|
|
/* ARG is a default argument expression being passed to a parameter of
|
|
the indicated TYPE, which is a parameter to FN. PARMNUM is the
|
|
zero-based argument number. Do any required conversions. Return
|
|
the converted value. */
|
|
|
|
static GTY(()) vec<tree, va_gc> *default_arg_context;
|
|
void
|
|
push_defarg_context (tree fn)
|
|
{ vec_safe_push (default_arg_context, fn); }
|
|
|
|
void
|
|
pop_defarg_context (void)
|
|
{ default_arg_context->pop (); }
|
|
|
|
tree
|
|
convert_default_arg (tree type, tree arg, tree fn, int parmnum,
|
|
tsubst_flags_t complain)
|
|
{
|
|
int i;
|
|
tree t;
|
|
|
|
/* See through clones. */
|
|
fn = DECL_ORIGIN (fn);
|
|
/* And inheriting ctors. */
|
|
if (flag_new_inheriting_ctors)
|
|
fn = strip_inheriting_ctors (fn);
|
|
|
|
/* Detect recursion. */
|
|
FOR_EACH_VEC_SAFE_ELT (default_arg_context, i, t)
|
|
if (t == fn)
|
|
{
|
|
if (complain & tf_error)
|
|
error ("recursive evaluation of default argument for %q#D", fn);
|
|
return error_mark_node;
|
|
}
|
|
|
|
/* If the ARG is an unparsed default argument expression, the
|
|
conversion cannot be performed. */
|
|
if (TREE_CODE (arg) == DEFERRED_PARSE)
|
|
{
|
|
if (complain & tf_error)
|
|
error ("call to %qD uses the default argument for parameter %P, which "
|
|
"is not yet defined", fn, parmnum);
|
|
return error_mark_node;
|
|
}
|
|
|
|
push_defarg_context (fn);
|
|
|
|
if (fn && DECL_TEMPLATE_INFO (fn))
|
|
arg = tsubst_default_argument (fn, parmnum, type, arg, complain);
|
|
|
|
/* Due to:
|
|
|
|
[dcl.fct.default]
|
|
|
|
The names in the expression are bound, and the semantic
|
|
constraints are checked, at the point where the default
|
|
expressions appears.
|
|
|
|
we must not perform access checks here. */
|
|
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, /*clear location*/true);
|
|
|
|
arg = convert_for_initialization (0, type, arg, LOOKUP_IMPLICIT,
|
|
ICR_DEFAULT_ARGUMENT, fn, parmnum,
|
|
complain);
|
|
arg = convert_for_arg_passing (type, arg, complain);
|
|
pop_deferring_access_checks();
|
|
|
|
pop_defarg_context ();
|
|
|
|
return arg;
|
|
}
|
|
|
|
/* Returns the type which will really be used for passing an argument of
|
|
type TYPE. */
|
|
|
|
tree
|
|
type_passed_as (tree type)
|
|
{
|
|
/* Pass classes with copy ctors by invisible reference. */
|
|
if (TREE_ADDRESSABLE (type))
|
|
type = build_reference_type (type);
|
|
else if (targetm.calls.promote_prototypes (NULL_TREE)
|
|
&& INTEGRAL_TYPE_P (type)
|
|
&& COMPLETE_TYPE_P (type)
|
|
&& tree_int_cst_lt (TYPE_SIZE (type), TYPE_SIZE (integer_type_node)))
|
|
type = integer_type_node;
|
|
|
|
return type;
|
|
}
|
|
|
|
/* Actually perform the appropriate conversion. */
|
|
|
|
tree
|
|
convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
|
|
{
|
|
tree bitfield_type;
|
|
|
|
/* If VAL is a bitfield, then -- since it has already been converted
|
|
to TYPE -- it cannot have a precision greater than TYPE.
|
|
|
|
If it has a smaller precision, we must widen it here. For
|
|
example, passing "int f:3;" to a function expecting an "int" will
|
|
not result in any conversion before this point.
|
|
|
|
If the precision is the same we must not risk widening. For
|
|
example, the COMPONENT_REF for a 32-bit "long long" bitfield will
|
|
often have type "int", even though the C++ type for the field is
|
|
"long long". If the value is being passed to a function
|
|
expecting an "int", then no conversions will be required. But,
|
|
if we call convert_bitfield_to_declared_type, the bitfield will
|
|
be converted to "long long". */
|
|
bitfield_type = is_bitfield_expr_with_lowered_type (val);
|
|
if (bitfield_type
|
|
&& TYPE_PRECISION (TREE_TYPE (val)) < TYPE_PRECISION (type))
|
|
val = convert_to_integer_nofold (TYPE_MAIN_VARIANT (bitfield_type), val);
|
|
|
|
if (val == error_mark_node)
|
|
;
|
|
/* Pass classes with copy ctors by invisible reference. */
|
|
else if (TREE_ADDRESSABLE (type))
|
|
val = build1 (ADDR_EXPR, build_reference_type (type), val);
|
|
else if (targetm.calls.promote_prototypes (NULL_TREE)
|
|
&& INTEGRAL_TYPE_P (type)
|
|
&& COMPLETE_TYPE_P (type)
|
|
&& tree_int_cst_lt (TYPE_SIZE (type), TYPE_SIZE (integer_type_node)))
|
|
val = cp_perform_integral_promotions (val, complain);
|
|
if (complain & tf_warning)
|
|
{
|
|
if (warn_suggest_attribute_format)
|
|
{
|
|
tree rhstype = TREE_TYPE (val);
|
|
const enum tree_code coder = TREE_CODE (rhstype);
|
|
const enum tree_code codel = TREE_CODE (type);
|
|
if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE)
|
|
&& coder == codel
|
|
&& check_missing_format_attribute (type, rhstype))
|
|
warning (OPT_Wsuggest_attribute_format,
|
|
"argument of function call might be a candidate "
|
|
"for a format attribute");
|
|
}
|
|
maybe_warn_parm_abi (type, cp_expr_loc_or_input_loc (val));
|
|
}
|
|
|
|
if (complain & tf_warning)
|
|
warn_for_address_or_pointer_of_packed_member (type, val);
|
|
|
|
return val;
|
|
}
|
|
|
|
/* Returns non-zero iff FN is a function with magic varargs, i.e. ones for
|
|
which just decay_conversion or no conversions at all should be done.
|
|
This is true for some builtins which don't act like normal functions.
|
|
Return 2 if no conversions at all should be done, 1 if just
|
|
decay_conversion. Return 3 for special treatment of the 3rd argument
|
|
for __builtin_*_overflow_p. */
|
|
|
|
int
|
|
magic_varargs_p (tree fn)
|
|
{
|
|
if (DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL)
|
|
switch (DECL_FUNCTION_CODE (fn))
|
|
{
|
|
case BUILT_IN_CLASSIFY_TYPE:
|
|
case BUILT_IN_CONSTANT_P:
|
|
case BUILT_IN_NEXT_ARG:
|
|
case BUILT_IN_VA_START:
|
|
return 1;
|
|
|
|
case BUILT_IN_ADD_OVERFLOW_P:
|
|
case BUILT_IN_SUB_OVERFLOW_P:
|
|
case BUILT_IN_MUL_OVERFLOW_P:
|
|
return 3;
|
|
|
|
default:;
|
|
return lookup_attribute ("type generic",
|
|
TYPE_ATTRIBUTES (TREE_TYPE (fn))) != 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Returns the decl of the dispatcher function if FN is a function version. */
|
|
|
|
tree
|
|
get_function_version_dispatcher (tree fn)
|
|
{
|
|
tree dispatcher_decl = NULL;
|
|
|
|
if (DECL_LOCAL_DECL_P (fn))
|
|
fn = DECL_LOCAL_DECL_ALIAS (fn);
|
|
|
|
gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
|
|
&& DECL_FUNCTION_VERSIONED (fn));
|
|
|
|
gcc_assert (targetm.get_function_versions_dispatcher);
|
|
dispatcher_decl = targetm.get_function_versions_dispatcher (fn);
|
|
|
|
if (dispatcher_decl == NULL)
|
|
{
|
|
error_at (input_location, "use of multiversioned function "
|
|
"without a default");
|
|
return NULL;
|
|
}
|
|
|
|
retrofit_lang_decl (dispatcher_decl);
|
|
gcc_assert (dispatcher_decl != NULL);
|
|
return dispatcher_decl;
|
|
}
|
|
|
|
/* fn is a function version dispatcher that is marked used. Mark all the
|
|
semantically identical function versions it will dispatch as used. */
|
|
|
|
void
|
|
mark_versions_used (tree fn)
|
|
{
|
|
struct cgraph_node *node;
|
|
struct cgraph_function_version_info *node_v;
|
|
struct cgraph_function_version_info *it_v;
|
|
|
|
gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
|
|
|
|
node = cgraph_node::get (fn);
|
|
if (node == NULL)
|
|
return;
|
|
|
|
gcc_assert (node->dispatcher_function);
|
|
|
|
node_v = node->function_version ();
|
|
if (node_v == NULL)
|
|
return;
|
|
|
|
/* All semantically identical versions are chained. Traverse and mark each
|
|
one of them as used. */
|
|
it_v = node_v->next;
|
|
while (it_v != NULL)
|
|
{
|
|
mark_used (it_v->this_node->decl);
|
|
it_v = it_v->next;
|
|
}
|
|
}
|
|
|
|
/* Build a call to "the copy constructor" for the type of A, even if it
|
|
wouldn't be selected by normal overload resolution. Used for
|
|
diagnostics. */
|
|
|
|
static tree
|
|
call_copy_ctor (tree a, tsubst_flags_t complain)
|
|
{
|
|
tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (a));
|
|
tree binfo = TYPE_BINFO (ctype);
|
|
tree copy = get_copy_ctor (ctype, complain);
|
|
copy = build_baselink (binfo, binfo, copy, NULL_TREE);
|
|
tree ob = build_dummy_object (ctype);
|
|
releasing_vec args (make_tree_vector_single (a));
|
|
tree r = build_new_method_call (ob, copy, &args, NULL_TREE,
|
|
LOOKUP_NORMAL, NULL, complain);
|
|
return r;
|
|
}
|
|
|
|
/* Return the base constructor corresponding to COMPLETE_CTOR or NULL_TREE. */
|
|
|
|
static tree
|
|
base_ctor_for (tree complete_ctor)
|
|
{
|
|
tree clone;
|
|
FOR_EACH_CLONE (clone, DECL_CLONED_FUNCTION (complete_ctor))
|
|
if (DECL_BASE_CONSTRUCTOR_P (clone))
|
|
return clone;
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Try to make EXP suitable to be used as the initializer for a base subobject,
|
|
and return whether we were successful. EXP must have already been cleared
|
|
by unsafe_copy_elision_p{,_opt}. */
|
|
|
|
static bool
|
|
make_base_init_ok (tree exp)
|
|
{
|
|
if (TREE_CODE (exp) == TARGET_EXPR)
|
|
exp = TARGET_EXPR_INITIAL (exp);
|
|
while (TREE_CODE (exp) == COMPOUND_EXPR)
|
|
exp = TREE_OPERAND (exp, 1);
|
|
if (TREE_CODE (exp) == COND_EXPR)
|
|
{
|
|
bool ret = make_base_init_ok (TREE_OPERAND (exp, 2));
|
|
if (tree op1 = TREE_OPERAND (exp, 1))
|
|
{
|
|
bool r1 = make_base_init_ok (op1);
|
|
/* If unsafe_copy_elision_p was false, the arms should match. */
|
|
gcc_assert (r1 == ret);
|
|
}
|
|
return ret;
|
|
}
|
|
if (TREE_CODE (exp) != AGGR_INIT_EXPR)
|
|
/* A trivial copy is OK. */
|
|
return true;
|
|
if (!AGGR_INIT_VIA_CTOR_P (exp))
|
|
/* unsafe_copy_elision_p_opt must have said this is OK. */
|
|
return true;
|
|
tree fn = cp_get_callee_fndecl_nofold (exp);
|
|
if (DECL_BASE_CONSTRUCTOR_P (fn))
|
|
return true;
|
|
gcc_assert (DECL_COMPLETE_CONSTRUCTOR_P (fn));
|
|
fn = base_ctor_for (fn);
|
|
if (!fn || DECL_HAS_VTT_PARM_P (fn))
|
|
/* The base constructor has more parameters, so we can't just change the
|
|
call target. It would be possible to splice in the appropriate
|
|
arguments, but probably not worth the complexity. */
|
|
return false;
|
|
mark_used (fn);
|
|
AGGR_INIT_EXPR_FN (exp) = build_address (fn);
|
|
return true;
|
|
}
|
|
|
|
/* Return 2 if T refers to a base, 1 if a potentially-overlapping field,
|
|
neither of which can be used for return by invisible reference. We avoid
|
|
doing C++17 mandatory copy elision for either of these cases.
|
|
|
|
This returns non-zero even if the type of T has no tail padding that other
|
|
data could be allocated into, because that depends on the particular ABI.
|
|
unsafe_copy_elision_p_opt does consider whether there is padding. */
|
|
|
|
int
|
|
unsafe_return_slot_p (tree t)
|
|
{
|
|
/* Check empty bases separately, they don't have fields. */
|
|
if (is_empty_base_ref (t))
|
|
return 2;
|
|
|
|
STRIP_NOPS (t);
|
|
if (TREE_CODE (t) == ADDR_EXPR)
|
|
t = TREE_OPERAND (t, 0);
|
|
if (TREE_CODE (t) == COMPONENT_REF)
|
|
t = TREE_OPERAND (t, 1);
|
|
if (TREE_CODE (t) != FIELD_DECL)
|
|
return false;
|
|
if (!CLASS_TYPE_P (TREE_TYPE (t)))
|
|
/* The middle-end will do the right thing for scalar types. */
|
|
return false;
|
|
if (DECL_FIELD_IS_BASE (t))
|
|
return 2;
|
|
if (lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (t)))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/* True IFF EXP is a prvalue that represents return by invisible reference. */
|
|
|
|
static bool
|
|
init_by_return_slot_p (tree exp)
|
|
{
|
|
/* Copy elision only happens with a TARGET_EXPR. */
|
|
if (TREE_CODE (exp) != TARGET_EXPR)
|
|
return false;
|
|
tree init = TARGET_EXPR_INITIAL (exp);
|
|
/* build_compound_expr pushes COMPOUND_EXPR inside TARGET_EXPR. */
|
|
while (TREE_CODE (init) == COMPOUND_EXPR)
|
|
init = TREE_OPERAND (init, 1);
|
|
if (TREE_CODE (init) == COND_EXPR)
|
|
{
|
|
/* We'll end up copying from each of the arms of the COND_EXPR directly
|
|
into the target, so look at them. */
|
|
if (tree op = TREE_OPERAND (init, 1))
|
|
if (init_by_return_slot_p (op))
|
|
return true;
|
|
return init_by_return_slot_p (TREE_OPERAND (init, 2));
|
|
}
|
|
return (TREE_CODE (init) == AGGR_INIT_EXPR
|
|
&& !AGGR_INIT_VIA_CTOR_P (init));
|
|
}
|
|
|
|
/* We can't elide a copy from a function returning by value to a
|
|
potentially-overlapping subobject, as the callee might clobber tail padding.
|
|
Return true iff this could be that case.
|
|
|
|
Places that use this function (or _opt) to decide to elide a copy should
|
|
probably use make_safe_copy_elision instead. */
|
|
|
|
static bool
|
|
unsafe_copy_elision_p (tree target, tree exp)
|
|
{
|
|
return unsafe_return_slot_p (target) && init_by_return_slot_p (exp);
|
|
}
|
|
|
|
/* As above, but for optimization allow more cases that are actually safe. */
|
|
|
|
static bool
|
|
unsafe_copy_elision_p_opt (tree target, tree exp)
|
|
{
|
|
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
|
|
/* It's safe to elide the copy for a class with no tail padding. */
|
|
if (!is_empty_class (type)
|
|
&& tree_int_cst_equal (TYPE_SIZE (type), CLASSTYPE_SIZE (type)))
|
|
return false;
|
|
return unsafe_copy_elision_p (target, exp);
|
|
}
|
|
|
|
/* Try to make EXP suitable to be used as the initializer for TARGET,
|
|
and return whether we were successful. */
|
|
|
|
bool
|
|
make_safe_copy_elision (tree target, tree exp)
|
|
{
|
|
int uns = unsafe_return_slot_p (target);
|
|
if (!uns)
|
|
return true;
|
|
if (init_by_return_slot_p (exp))
|
|
return false;
|
|
if (uns == 1)
|
|
return true;
|
|
return make_base_init_ok (exp);
|
|
}
|
|
|
|
/* True IFF the result of the conversion C is a prvalue. */
|
|
|
|
static bool
|
|
conv_is_prvalue (conversion *c)
|
|
{
|
|
if (c->kind == ck_rvalue)
|
|
return true;
|
|
if (c->kind == ck_base && c->need_temporary_p)
|
|
return true;
|
|
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 true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/* True iff C is a conversion that binds a reference to a prvalue. */
|
|
|
|
static bool
|
|
conv_binds_ref_to_prvalue (conversion *c)
|
|
{
|
|
if (c->kind != ck_ref_bind)
|
|
return false;
|
|
if (c->need_temporary_p)
|
|
return true;
|
|
|
|
return conv_is_prvalue (next_conversion (c));
|
|
}
|
|
|
|
/* True iff converting EXPR to a reference type TYPE does not involve
|
|
creating a temporary. */
|
|
|
|
bool
|
|
ref_conv_binds_directly_p (tree type, tree expr)
|
|
{
|
|
gcc_assert (TYPE_REF_P (type));
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
void *p = conversion_obstack_alloc (0);
|
|
|
|
conversion *conv = implicit_conversion (type, TREE_TYPE (expr), expr,
|
|
/*c_cast_p=*/false,
|
|
LOOKUP_IMPLICIT, tf_none);
|
|
bool ret = conv && !conv->bad_p && !conv_binds_ref_to_prvalue (conv);
|
|
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Call the trivial destructor for INSTANCE, which can be either an lvalue of
|
|
class type or a pointer to class type. If NO_PTR_DEREF is true and
|
|
INSTANCE has pointer type, clobber the pointer rather than what it points
|
|
to. */
|
|
|
|
tree
|
|
build_trivial_dtor_call (tree instance, bool no_ptr_deref)
|
|
{
|
|
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))
|
|
&& (!no_ptr_deref || TYPE_REF_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);
|
|
}
|
|
|
|
/* Return true if in an immediate function context, or an unevaluated operand,
|
|
or a subexpression of an immediate invocation. */
|
|
|
|
bool
|
|
in_immediate_context ()
|
|
{
|
|
return (cp_unevaluated_operand != 0
|
|
|| (current_function_decl != NULL_TREE
|
|
&& DECL_IMMEDIATE_FUNCTION_P (current_function_decl))
|
|
|| (current_binding_level->kind == sk_function_parms
|
|
&& current_binding_level->immediate_fn_ctx_p)
|
|
|| in_consteval_if_p);
|
|
}
|
|
|
|
/* Return true if a call to FN with number of arguments NARGS
|
|
is an immediate invocation. */
|
|
|
|
static bool
|
|
immediate_invocation_p (tree fn, int nargs)
|
|
{
|
|
return (TREE_CODE (fn) == FUNCTION_DECL
|
|
&& DECL_IMMEDIATE_FUNCTION_P (fn)
|
|
&& !in_immediate_context ()
|
|
/* As an exception, we defer std::source_location::current ()
|
|
invocations until genericization because LWG3396 mandates
|
|
special behavior for it. */
|
|
&& (nargs > 1 || !source_location_current_p (fn)));
|
|
}
|
|
|
|
/* temp_override for in_consteval_if_p, which can't use make_temp_override
|
|
because it is a bitfield. */
|
|
|
|
struct in_consteval_if_p_temp_override {
|
|
bool save_in_consteval_if_p;
|
|
in_consteval_if_p_temp_override ()
|
|
: save_in_consteval_if_p (in_consteval_if_p) {}
|
|
void reset () { in_consteval_if_p = save_in_consteval_if_p; }
|
|
~in_consteval_if_p_temp_override ()
|
|
{ reset (); }
|
|
};
|
|
|
|
/* 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
|
|
bitmask of various LOOKUP_* flags which apply to the call itself. */
|
|
|
|
static tree
|
|
build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
|
|
{
|
|
tree fn = cand->fn;
|
|
const vec<tree, va_gc> *args = cand->args;
|
|
tree first_arg = cand->first_arg;
|
|
conversion **convs = cand->convs;
|
|
conversion *conv;
|
|
tree parm = TYPE_ARG_TYPES (TREE_TYPE (fn));
|
|
int parmlen;
|
|
tree val;
|
|
int i = 0;
|
|
int j = 0;
|
|
unsigned int arg_index = 0;
|
|
int is_method = 0;
|
|
int nargs;
|
|
tree *argarray;
|
|
bool already_used = false;
|
|
|
|
/* In a template, there is no need to perform all of the work that
|
|
is normally done. We are only interested in the type of the call
|
|
expression, i.e., the return type of the function. Any semantic
|
|
errors will be deferred until the template is instantiated. */
|
|
if (processing_template_decl)
|
|
{
|
|
if (undeduced_auto_decl (fn))
|
|
mark_used (fn, complain);
|
|
else
|
|
/* Otherwise set TREE_USED for the benefit of -Wunused-function.
|
|
See PR80598. */
|
|
TREE_USED (fn) = 1;
|
|
|
|
tree return_type = TREE_TYPE (TREE_TYPE (fn));
|
|
tree callee;
|
|
if (first_arg == NULL_TREE)
|
|
{
|
|
callee = build_addr_func (fn, complain);
|
|
if (callee == error_mark_node)
|
|
return error_mark_node;
|
|
}
|
|
else
|
|
{
|
|
callee = build_baselink (cand->conversion_path, cand->access_path,
|
|
fn, NULL_TREE);
|
|
callee = build_min (COMPONENT_REF, TREE_TYPE (fn),
|
|
first_arg, callee, NULL_TREE);
|
|
}
|
|
|
|
tree expr = build_call_vec (return_type, callee, args);
|
|
SET_EXPR_LOCATION (expr, input_location);
|
|
if (TREE_THIS_VOLATILE (fn) && cfun)
|
|
current_function_returns_abnormally = 1;
|
|
if (immediate_invocation_p (fn, vec_safe_length (args)))
|
|
{
|
|
tree obj_arg = NULL_TREE, exprimm = expr;
|
|
if (DECL_CONSTRUCTOR_P (fn))
|
|
obj_arg = first_arg;
|
|
if (obj_arg
|
|
&& is_dummy_object (obj_arg)
|
|
&& !type_dependent_expression_p (obj_arg))
|
|
{
|
|
exprimm = build_cplus_new (DECL_CONTEXT (fn), expr, complain);
|
|
obj_arg = NULL_TREE;
|
|
}
|
|
/* Look through *(const T *)&obj. */
|
|
else if (obj_arg && TREE_CODE (obj_arg) == INDIRECT_REF)
|
|
{
|
|
tree addr = TREE_OPERAND (obj_arg, 0);
|
|
STRIP_NOPS (addr);
|
|
if (TREE_CODE (addr) == ADDR_EXPR)
|
|
{
|
|
tree typeo = TREE_TYPE (obj_arg);
|
|
tree typei = TREE_TYPE (TREE_OPERAND (addr, 0));
|
|
if (same_type_ignoring_top_level_qualifiers_p (typeo, typei))
|
|
obj_arg = TREE_OPERAND (addr, 0);
|
|
}
|
|
}
|
|
fold_non_dependent_expr (exprimm, complain,
|
|
/*manifestly_const_eval=*/true,
|
|
obj_arg);
|
|
}
|
|
return convert_from_reference (expr);
|
|
}
|
|
|
|
/* Give any warnings we noticed during overload resolution. */
|
|
if (cand->warnings && (complain & tf_warning))
|
|
{
|
|
struct candidate_warning *w;
|
|
for (w = cand->warnings; w; w = w->next)
|
|
joust (cand, w->loser, 1, complain);
|
|
}
|
|
|
|
/* Core issue 2327: P0135 doesn't say how to handle the case where the
|
|
argument to the copy constructor ends up being a prvalue after
|
|
conversion. Let's do the normal processing, but pretend we aren't
|
|
actually using the copy constructor. */
|
|
bool force_elide = false;
|
|
if (cxx_dialect >= cxx17
|
|
&& cand->num_convs == 1
|
|
&& DECL_COMPLETE_CONSTRUCTOR_P (fn)
|
|
&& (DECL_COPY_CONSTRUCTOR_P (fn)
|
|
|| DECL_MOVE_CONSTRUCTOR_P (fn))
|
|
&& !unsafe_return_slot_p (first_arg)
|
|
&& conv_binds_ref_to_prvalue (convs[0]))
|
|
{
|
|
force_elide = true;
|
|
goto not_really_used;
|
|
}
|
|
|
|
/* OK, we're actually calling this inherited constructor; set its deletedness
|
|
appropriately. We can get away with doing this here because calling is
|
|
the only way to refer to a constructor. */
|
|
if (DECL_INHERITED_CTOR (fn)
|
|
&& !deduce_inheriting_ctor (fn))
|
|
{
|
|
if (complain & tf_error)
|
|
mark_used (fn);
|
|
return error_mark_node;
|
|
}
|
|
|
|
/* Make =delete work with SFINAE. */
|
|
if (DECL_DELETED_FN (fn))
|
|
{
|
|
if (complain & tf_error)
|
|
mark_used (fn);
|
|
return error_mark_node;
|
|
}
|
|
|
|
if (DECL_FUNCTION_MEMBER_P (fn))
|
|
{
|
|
tree access_fn;
|
|
/* If FN is a template function, two cases must be considered.
|
|
For example:
|
|
|
|
struct A {
|
|
protected:
|
|
template <class T> void f();
|
|
};
|
|
template <class T> struct B {
|
|
protected:
|
|
void g();
|
|
};
|
|
struct C : A, B<int> {
|
|
using A::f; // #1
|
|
using B<int>::g; // #2
|
|
};
|
|
|
|
In case #1 where `A::f' is a member template, DECL_ACCESS is
|
|
recorded in the primary template but not in its specialization.
|
|
We check access of FN using its primary template.
|
|
|
|
In case #2, where `B<int>::g' has a DECL_TEMPLATE_INFO simply
|
|
because it is a member of class template B, DECL_ACCESS is
|
|
recorded in the specialization `B<int>::g'. We cannot use its
|
|
primary template because `B<T>::g' and `B<int>::g' may have
|
|
different access. */
|
|
if (DECL_TEMPLATE_INFO (fn)
|
|
&& DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (fn)))
|
|
access_fn = DECL_TI_TEMPLATE (fn);
|
|
else
|
|
access_fn = fn;
|
|
if (!perform_or_defer_access_check (cand->access_path, access_fn,
|
|
fn, complain))
|
|
return error_mark_node;
|
|
}
|
|
|
|
/* If we're checking for implicit delete, don't bother with argument
|
|
conversions. */
|
|
if (flags & LOOKUP_SPECULATIVE)
|
|
{
|
|
if (cand->viable == 1)
|
|
return fn;
|
|
else if (!(complain & tf_error))
|
|
/* Reject bad conversions now. */
|
|
return error_mark_node;
|
|
/* else continue to get conversion error. */
|
|
}
|
|
|
|
not_really_used:
|
|
|
|
/* N3276 magic doesn't apply to nested calls. */
|
|
tsubst_flags_t decltype_flag = (complain & tf_decltype);
|
|
complain &= ~tf_decltype;
|
|
/* No-Cleanup doesn't apply to nested calls either. */
|
|
tsubst_flags_t no_cleanup_complain = complain;
|
|
complain &= ~tf_no_cleanup;
|
|
|
|
/* Find maximum size of vector to hold converted arguments. */
|
|
parmlen = list_length (parm);
|
|
nargs = vec_safe_length (args) + (first_arg != NULL_TREE ? 1 : 0);
|
|
if (parmlen > nargs)
|
|
nargs = parmlen;
|
|
argarray = XALLOCAVEC (tree, nargs);
|
|
|
|
in_consteval_if_p_temp_override icip;
|
|
/* If the call is immediate function invocation, make sure
|
|
taking address of immediate functions is allowed in its arguments. */
|
|
if (immediate_invocation_p (STRIP_TEMPLATE (fn), nargs))
|
|
in_consteval_if_p = true;
|
|
|
|
/* The implicit parameters to a constructor are not considered by overload
|
|
resolution, and must be of the proper type. */
|
|
if (DECL_CONSTRUCTOR_P (fn))
|
|
{
|
|
tree object_arg;
|
|
if (first_arg != NULL_TREE)
|
|
{
|
|
object_arg = first_arg;
|
|
first_arg = NULL_TREE;
|
|
}
|
|
else
|
|
{
|
|
object_arg = (*args)[arg_index];
|
|
++arg_index;
|
|
}
|
|
argarray[j++] = build_this (object_arg);
|
|
parm = TREE_CHAIN (parm);
|
|
/* We should never try to call the abstract constructor. */
|
|
gcc_assert (!DECL_HAS_IN_CHARGE_PARM_P (fn));
|
|
|
|
if (DECL_HAS_VTT_PARM_P (fn))
|
|
{
|
|
argarray[j++] = (*args)[arg_index];
|
|
++arg_index;
|
|
parm = TREE_CHAIN (parm);
|
|
}
|
|
|
|
if (cxx_dialect < cxx20
|
|
&& (cand->flags & LOOKUP_PREFER_RVALUE))
|
|
{
|
|
/* 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)...." */
|
|
gcc_assert (!(complain & tf_error));
|
|
tree ptype = convs[0]->type;
|
|
/* Allow calling a by-value converting constructor even though it
|
|
isn't permitted by the above, because we've allowed it since GCC 5
|
|
(PR58051) and it's allowed in C++20. But don't call a copy
|
|
constructor. */
|
|
if ((TYPE_REF_P (ptype) && !TYPE_REF_IS_RVALUE (ptype))
|
|
|| CONVERSION_RANK (convs[0]) > cr_exact)
|
|
return error_mark_node;
|
|
}
|
|
}
|
|
/* Bypass access control for 'this' parameter. */
|
|
else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
|
|
{
|
|
tree arg = build_this (first_arg != NULL_TREE
|
|
? first_arg
|
|
: (*args)[arg_index]);
|
|
tree argtype = TREE_TYPE (arg);
|
|
|
|
if (arg == error_mark_node)
|
|
return error_mark_node;
|
|
|
|
if (convs[i]->bad_p)
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
auto_diagnostic_group d;
|
|
if (permerror (input_location, "passing %qT as %<this%> "
|
|
"argument discards qualifiers",
|
|
TREE_TYPE (argtype)))
|
|
inform (DECL_SOURCE_LOCATION (fn), " in call to %qD", fn);
|
|
}
|
|
else
|
|
return error_mark_node;
|
|
}
|
|
|
|
/* The class where FN is defined. */
|
|
tree ctx = DECL_CONTEXT (fn);
|
|
|
|
/* See if the function member or the whole class type is declared
|
|
final and the call can be devirtualized. */
|
|
if (DECL_FINAL_P (fn) || CLASSTYPE_FINAL (ctx))
|
|
flags |= LOOKUP_NONVIRTUAL;
|
|
|
|
/* [class.mfct.non-static]: If a non-static member function of a class
|
|
X is called for an object that is not of type X, or of a type
|
|
derived from X, the behavior is undefined.
|
|
|
|
So we can assume that anything passed as 'this' is non-null, and
|
|
optimize accordingly. */
|
|
/* Check that the base class is accessible. */
|
|
if (!accessible_base_p (TREE_TYPE (argtype),
|
|
BINFO_TYPE (cand->conversion_path), true))
|
|
{
|
|
if (complain & tf_error)
|
|
error ("%qT is not an accessible base of %qT",
|
|
BINFO_TYPE (cand->conversion_path),
|
|
TREE_TYPE (argtype));
|
|
else
|
|
return error_mark_node;
|
|
}
|
|
/* If fn was found by a using declaration, the conversion path
|
|
will be to the derived class, not the base declaring fn. We
|
|
must convert to the base. */
|
|
tree base_binfo = cand->conversion_path;
|
|
if (BINFO_TYPE (base_binfo) != ctx)
|
|
{
|
|
base_binfo = lookup_base (base_binfo, ctx, ba_unique, NULL, complain);
|
|
if (base_binfo == error_mark_node)
|
|
return error_mark_node;
|
|
}
|
|
|
|
/* If we know the dynamic type of the object, look up the final overrider
|
|
in the BINFO. */
|
|
if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0
|
|
&& resolves_to_fixed_type_p (arg))
|
|
{
|
|
tree ov = lookup_vfn_in_binfo (DECL_VINDEX (fn), base_binfo);
|
|
|
|
/* And unwind base_binfo to match. If we don't find the type we're
|
|
looking for in BINFO_INHERITANCE_CHAIN, we're looking at diamond
|
|
inheritance; for now do a normal virtual call in that case. */
|
|
tree octx = DECL_CONTEXT (ov);
|
|
tree obinfo = base_binfo;
|
|
while (obinfo && !SAME_BINFO_TYPE_P (BINFO_TYPE (obinfo), octx))
|
|
obinfo = BINFO_INHERITANCE_CHAIN (obinfo);
|
|
if (obinfo)
|
|
{
|
|
fn = ov;
|
|
base_binfo = obinfo;
|
|
flags |= LOOKUP_NONVIRTUAL;
|
|
}
|
|
}
|
|
|
|
tree converted_arg = build_base_path (PLUS_EXPR, arg,
|
|
base_binfo, 1, complain);
|
|
|
|
argarray[j++] = converted_arg;
|
|
parm = TREE_CHAIN (parm);
|
|
if (first_arg != NULL_TREE)
|
|
first_arg = NULL_TREE;
|
|
else
|
|
++arg_index;
|
|
++i;
|
|
is_method = 1;
|
|
}
|
|
|
|
gcc_assert (first_arg == NULL_TREE);
|
|
for (; arg_index < vec_safe_length (args) && parm;
|
|
parm = TREE_CHAIN (parm), ++arg_index, ++i)
|
|
{
|
|
tree type = TREE_VALUE (parm);
|
|
tree arg = (*args)[arg_index];
|
|
bool conversion_warning = true;
|
|
|
|
conv = convs[i];
|
|
|
|
/* If the argument is NULL and used to (implicitly) instantiate a
|
|
template function (and bind one of the template arguments to
|
|
the type of 'long int'), we don't want to warn about passing NULL
|
|
to non-pointer argument.
|
|
For example, if we have this template function:
|
|
|
|
template<typename T> void func(T x) {}
|
|
|
|
we want to warn (when -Wconversion is enabled) in this case:
|
|
|
|
void foo() {
|
|
func<int>(NULL);
|
|
}
|
|
|
|
but not in this case:
|
|
|
|
void foo() {
|
|
func(NULL);
|
|
}
|
|
*/
|
|
if (null_node_p (arg)
|
|
&& DECL_TEMPLATE_INFO (fn)
|
|
&& cand->template_decl
|
|
&& !cand->explicit_targs)
|
|
conversion_warning = false;
|
|
|
|
/* Set user_conv_p on the argument conversions, so rvalue/base handling
|
|
knows not to allow any more UDCs. This needs to happen after we
|
|
process cand->warnings. */
|
|
if (flags & LOOKUP_NO_CONVERSION)
|
|
conv->user_conv_p = true;
|
|
|
|
tsubst_flags_t arg_complain = complain;
|
|
if (!conversion_warning)
|
|
arg_complain &= ~tf_warning;
|
|
|
|
val = convert_like_with_context (conv, arg, fn, i - is_method,
|
|
arg_complain);
|
|
val = convert_for_arg_passing (type, val, arg_complain);
|
|
|
|
if (val == error_mark_node)
|
|
return error_mark_node;
|
|
else
|
|
argarray[j++] = val;
|
|
}
|
|
|
|
/* Default arguments */
|
|
for (; parm && parm != void_list_node; parm = TREE_CHAIN (parm), i++)
|
|
{
|
|
if (TREE_VALUE (parm) == error_mark_node)
|
|
return error_mark_node;
|
|
val = convert_default_arg (TREE_VALUE (parm),
|
|
TREE_PURPOSE (parm),
|
|
fn, i - is_method,
|
|
complain);
|
|
if (val == error_mark_node)
|
|
return error_mark_node;
|
|
argarray[j++] = val;
|
|
}
|
|
|
|
/* Ellipsis */
|
|
int magic = magic_varargs_p (fn);
|
|
for (; arg_index < vec_safe_length (args); ++arg_index)
|
|
{
|
|
tree a = (*args)[arg_index];
|
|
if ((magic == 3 && arg_index == 2) || magic == 2)
|
|
{
|
|
/* Do no conversions for certain magic varargs. */
|
|
a = mark_type_use (a);
|
|
if (TREE_CODE (a) == FUNCTION_DECL && reject_gcc_builtin (a))
|
|
return error_mark_node;
|
|
}
|
|
else if (magic != 0)
|
|
/* For other magic varargs only do decay_conversion. */
|
|
a = decay_conversion (a, complain);
|
|
else if (DECL_CONSTRUCTOR_P (fn)
|
|
&& same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (fn),
|
|
TREE_TYPE (a)))
|
|
{
|
|
/* Avoid infinite recursion trying to call A(...). */
|
|
if (complain & tf_error)
|
|
/* Try to call the actual copy constructor for a good error. */
|
|
call_copy_ctor (a, complain);
|
|
return error_mark_node;
|
|
}
|
|
else
|
|
a = convert_arg_to_ellipsis (a, complain);
|
|
if (a == error_mark_node)
|
|
return error_mark_node;
|
|
argarray[j++] = a;
|
|
}
|
|
|
|
gcc_assert (j <= nargs);
|
|
nargs = j;
|
|
icip.reset ();
|
|
|
|
/* Avoid performing argument transformation if warnings are disabled.
|
|
When tf_warning is set and at least one of the warnings is active
|
|
the check_function_arguments function might warn about something. */
|
|
|
|
bool warned_p = false;
|
|
if ((complain & tf_warning)
|
|
&& (warn_nonnull
|
|
|| warn_format
|
|
|| warn_suggest_attribute_format
|
|
|| warn_restrict))
|
|
{
|
|
tree *fargs = (!nargs ? argarray
|
|
: (tree *) alloca (nargs * sizeof (tree)));
|
|
for (j = 0; j < nargs; j++)
|
|
{
|
|
/* For -Wformat undo the implicit passing by hidden reference
|
|
done by convert_arg_to_ellipsis. */
|
|
if (TREE_CODE (argarray[j]) == ADDR_EXPR
|
|
&& TYPE_REF_P (TREE_TYPE (argarray[j])))
|
|
fargs[j] = TREE_OPERAND (argarray[j], 0);
|
|
else
|
|
fargs[j] = argarray[j];
|
|
}
|
|
|
|
warned_p = check_function_arguments (input_location, fn, TREE_TYPE (fn),
|
|
nargs, fargs, NULL);
|
|
}
|
|
|
|
if (DECL_INHERITED_CTOR (fn))
|
|
{
|
|
/* Check for passing ellipsis arguments to an inherited constructor. We
|
|
could handle this by open-coding the inherited constructor rather than
|
|
defining it, but let's not bother now. */
|
|
if (!cp_unevaluated_operand
|
|
&& cand->num_convs
|
|
&& cand->convs[cand->num_convs-1]->ellipsis_p)
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
sorry ("passing arguments to ellipsis of inherited constructor "
|
|
"%qD", cand->fn);
|
|
inform (DECL_SOURCE_LOCATION (cand->fn), "declared here");
|
|
}
|
|
return error_mark_node;
|
|
}
|
|
|
|
/* A base constructor inheriting from a virtual base doesn't get the
|
|
inherited arguments, just this and __vtt. */
|
|
if (ctor_omit_inherited_parms (fn))
|
|
nargs = 2;
|
|
}
|
|
|
|
/* Avoid actually calling copy constructors and copy assignment operators,
|
|
if possible. */
|
|
|
|
if (! flag_elide_constructors && !force_elide)
|
|
/* Do things the hard way. */;
|
|
else if (cand->num_convs == 1
|
|
&& (DECL_COPY_CONSTRUCTOR_P (fn)
|
|
|| DECL_MOVE_CONSTRUCTOR_P (fn))
|
|
/* It's unsafe to elide the constructor when handling
|
|
a noexcept-expression, it may evaluate to the wrong
|
|
value (c++/53025). */
|
|
&& (force_elide || cp_noexcept_operand == 0))
|
|
{
|
|
tree targ;
|
|
tree arg = argarray[num_artificial_parms_for (fn)];
|
|
tree fa = argarray[0];
|
|
bool trivial = trivial_fn_p (fn);
|
|
|
|
/* Pull out the real argument, disregarding const-correctness. */
|
|
targ = arg;
|
|
/* Strip the reference binding for the constructor parameter. */
|
|
if (CONVERT_EXPR_P (targ)
|
|
&& 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)
|
|
&& !TYPE_REF_P (TREE_TYPE (targ)))
|
|
|| TREE_CODE (targ) == NON_LVALUE_EXPR)
|
|
targ = TREE_OPERAND (targ, 0);
|
|
if (TREE_CODE (targ) == ADDR_EXPR)
|
|
{
|
|
targ = TREE_OPERAND (targ, 0);
|
|
if (!same_type_ignoring_top_level_qualifiers_p
|
|
(TREE_TYPE (TREE_TYPE (arg)), TREE_TYPE (targ)))
|
|
targ = NULL_TREE;
|
|
}
|
|
else
|
|
targ = NULL_TREE;
|
|
|
|
if (targ)
|
|
arg = targ;
|
|
else
|
|
arg = cp_build_fold_indirect_ref (arg);
|
|
|
|
/* In C++17 we shouldn't be copying a TARGET_EXPR except into a
|
|
potentially-overlapping subobject. */
|
|
if (CHECKING_P && cxx_dialect >= cxx17)
|
|
gcc_assert (TREE_CODE (arg) != TARGET_EXPR
|
|
|| force_elide
|
|
/* It's from binding the ref parm to a packed field. */
|
|
|| convs[0]->need_temporary_p
|
|
|| seen_error ()
|
|
/* See unsafe_copy_elision_p. */
|
|
|| unsafe_return_slot_p (fa));
|
|
|
|
bool unsafe = unsafe_copy_elision_p_opt (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_handle_deprecated_or_unavailable (fn, complain);
|
|
|
|
if (eliding_temp && DECL_BASE_CONSTRUCTOR_P (fn)
|
|
&& !make_base_init_ok (arg))
|
|
unsafe = true;
|
|
|
|
/* 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. */
|
|
if (is_dummy_object (fa))
|
|
{
|
|
if (TREE_CODE (arg) == TARGET_EXPR)
|
|
return arg;
|
|
else if (trivial)
|
|
return force_target_expr (DECL_CONTEXT (fn), arg, complain);
|
|
}
|
|
else if ((trivial || TREE_CODE (arg) == TARGET_EXPR)
|
|
&& !unsafe)
|
|
{
|
|
tree to = cp_build_fold_indirect_ref (fa);
|
|
val = build2 (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
|
|
return val;
|
|
}
|
|
}
|
|
else if (DECL_ASSIGNMENT_OPERATOR_P (fn)
|
|
&& DECL_OVERLOADED_OPERATOR_IS (fn, NOP_EXPR)
|
|
&& trivial_fn_p (fn))
|
|
{
|
|
/* Don't use cp_build_fold_indirect_ref, op= returns an lvalue even if
|
|
the object argument isn't one. */
|
|
tree to = cp_build_indirect_ref (input_location, argarray[0],
|
|
RO_ARROW, complain);
|
|
tree type = TREE_TYPE (to);
|
|
tree as_base = CLASSTYPE_AS_BASE (type);
|
|
tree arg = argarray[1];
|
|
location_t loc = cp_expr_loc_or_input_loc (arg);
|
|
|
|
if (is_really_empty_class (type, /*ignore_vptr*/true))
|
|
{
|
|
/* Avoid copying empty classes. */
|
|
val = build2 (COMPOUND_EXPR, type, arg, to);
|
|
suppress_warning (val, OPT_Wunused);
|
|
}
|
|
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);
|
|
}
|
|
else
|
|
{
|
|
/* We must only copy the non-tail padding parts. */
|
|
tree arg0, arg2, t;
|
|
tree array_type, alias_set;
|
|
|
|
arg2 = TYPE_SIZE_UNIT (as_base);
|
|
to = cp_stabilize_reference (to);
|
|
arg0 = cp_build_addr_expr (to, complain);
|
|
|
|
array_type = build_array_type (unsigned_char_type_node,
|
|
build_index_type
|
|
(size_binop (MINUS_EXPR,
|
|
arg2, size_int (1))));
|
|
alias_set = build_int_cst (build_pointer_type (type), 0);
|
|
t = build2 (MODIFY_EXPR, void_type_node,
|
|
build2 (MEM_REF, array_type, arg0, alias_set),
|
|
build2 (MEM_REF, array_type, arg, alias_set));
|
|
val = build2 (COMPOUND_EXPR, TREE_TYPE (to), t, to);
|
|
suppress_warning (val, OPT_Wunused);
|
|
}
|
|
|
|
cp_handle_deprecated_or_unavailable (fn, complain);
|
|
|
|
return val;
|
|
}
|
|
else if (trivial_fn_p (fn))
|
|
{
|
|
if (DECL_DESTRUCTOR_P (fn))
|
|
return build_trivial_dtor_call (argarray[0]);
|
|
else if (default_ctor_p (fn))
|
|
{
|
|
if (is_dummy_object (argarray[0]))
|
|
return force_target_expr (DECL_CONTEXT (fn), void_node,
|
|
no_cleanup_complain);
|
|
else
|
|
return cp_build_fold_indirect_ref (argarray[0]);
|
|
}
|
|
}
|
|
|
|
gcc_assert (!force_elide);
|
|
|
|
if (!already_used
|
|
&& !mark_used (fn, complain))
|
|
return error_mark_node;
|
|
|
|
/* Warn if the built-in writes to an object of a non-trivial type. */
|
|
if (warn_class_memaccess
|
|
&& vec_safe_length (args) >= 2
|
|
&& DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL)
|
|
maybe_warn_class_memaccess (input_location, fn, args);
|
|
|
|
if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
|
|
{
|
|
tree t;
|
|
tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (argarray[0])),
|
|
DECL_CONTEXT (fn),
|
|
ba_any, NULL, complain);
|
|
gcc_assert (binfo && binfo != error_mark_node);
|
|
|
|
argarray[0] = build_base_path (PLUS_EXPR, argarray[0], binfo, 1,
|
|
complain);
|
|
if (TREE_SIDE_EFFECTS (argarray[0]))
|
|
argarray[0] = save_expr (argarray[0]);
|
|
t = build_pointer_type (TREE_TYPE (fn));
|
|
fn = build_vfn_ref (argarray[0], DECL_VINDEX (fn));
|
|
TREE_TYPE (fn) = t;
|
|
}
|
|
else
|
|
{
|
|
/* If FN is marked deprecated, then we've already issued a deprecated-use
|
|
warning from mark_used above, so avoid redundantly issuing another one
|
|
from build_addr_func. */
|
|
warning_sentinel w (warn_deprecated_decl);
|
|
|
|
fn = build_addr_func (fn, complain);
|
|
if (fn == error_mark_node)
|
|
return error_mark_node;
|
|
}
|
|
|
|
tree call = build_cxx_call (fn, nargs, argarray, complain|decltype_flag);
|
|
if (call == error_mark_node)
|
|
return call;
|
|
if (cand->flags & LOOKUP_LIST_INIT_CTOR)
|
|
{
|
|
tree c = extract_call_expr (call);
|
|
/* build_new_op will clear this when appropriate. */
|
|
CALL_EXPR_ORDERED_ARGS (c) = true;
|
|
}
|
|
if (warned_p)
|
|
{
|
|
tree c = extract_call_expr (call);
|
|
if (TREE_CODE (c) == CALL_EXPR)
|
|
suppress_warning (c /* Suppress all warnings. */);
|
|
}
|
|
if (TREE_CODE (fn) == ADDR_EXPR)
|
|
{
|
|
tree fndecl = STRIP_TEMPLATE (TREE_OPERAND (fn, 0));
|
|
if (immediate_invocation_p (fndecl, nargs))
|
|
{
|
|
tree obj_arg = NULL_TREE;
|
|
/* Undo convert_from_reference called by build_cxx_call. */
|
|
if (REFERENCE_REF_P (call))
|
|
call = TREE_OPERAND (call, 0);
|
|
if (DECL_CONSTRUCTOR_P (fndecl))
|
|
obj_arg = cand->first_arg ? cand->first_arg : (*args)[0];
|
|
if (obj_arg && is_dummy_object (obj_arg))
|
|
{
|
|
call = build_cplus_new (DECL_CONTEXT (fndecl), call, complain);
|
|
obj_arg = NULL_TREE;
|
|
}
|
|
/* Look through *(const T *)&obj. */
|
|
else if (obj_arg && TREE_CODE (obj_arg) == INDIRECT_REF)
|
|
{
|
|
tree addr = TREE_OPERAND (obj_arg, 0);
|
|
STRIP_NOPS (addr);
|
|
if (TREE_CODE (addr) == ADDR_EXPR)
|
|
{
|
|
tree typeo = TREE_TYPE (obj_arg);
|
|
tree typei = TREE_TYPE (TREE_OPERAND (addr, 0));
|
|
if (same_type_ignoring_top_level_qualifiers_p (typeo, typei))
|
|
obj_arg = TREE_OPERAND (addr, 0);
|
|
}
|
|
}
|
|
call = cxx_constant_value_sfinae (call, obj_arg, complain);
|
|
if (obj_arg && !error_operand_p (call))
|
|
call = build2 (INIT_EXPR, void_type_node, obj_arg, call);
|
|
call = convert_from_reference (call);
|
|
}
|
|
}
|
|
return call;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
|
|
/* Return the DECL of the first non-static subobject of class TYPE
|
|
that satisfies the predicate PRED or null if none can be found. */
|
|
|
|
template <class Predicate>
|
|
tree
|
|
first_non_static_field (tree type, Predicate pred)
|
|
{
|
|
if (!type || !CLASS_TYPE_P (type))
|
|
return NULL_TREE;
|
|
|
|
for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
|
|
{
|
|
if (TREE_CODE (field) != FIELD_DECL)
|
|
continue;
|
|
if (TREE_STATIC (field))
|
|
continue;
|
|
if (pred (field))
|
|
return field;
|
|
}
|
|
|
|
int i = 0;
|
|
|
|
for (tree base_binfo, binfo = TYPE_BINFO (type);
|
|
BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
|
|
{
|
|
tree base = TREE_TYPE (base_binfo);
|
|
if (pred (base))
|
|
return base;
|
|
if (tree field = first_non_static_field (base, pred))
|
|
return field;
|
|
}
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
struct NonPublicField
|
|
{
|
|
bool operator() (const_tree t) const
|
|
{
|
|
return DECL_P (t) && (TREE_PRIVATE (t) || TREE_PROTECTED (t));
|
|
}
|
|
};
|
|
|
|
/* Return the DECL of the first non-public subobject of class TYPE
|
|
or null if none can be found. */
|
|
|
|
static inline tree
|
|
first_non_public_field (tree type)
|
|
{
|
|
return first_non_static_field (type, NonPublicField ());
|
|
}
|
|
|
|
struct NonTrivialField
|
|
{
|
|
bool operator() (const_tree t) const
|
|
{
|
|
return !trivial_type_p (DECL_P (t) ? TREE_TYPE (t) : t);
|
|
}
|
|
};
|
|
|
|
/* Return the DECL of the first non-trivial subobject of class TYPE
|
|
or null if none can be found. */
|
|
|
|
static inline tree
|
|
first_non_trivial_field (tree type)
|
|
{
|
|
return first_non_static_field (type, NonTrivialField ());
|
|
}
|
|
|
|
} /* unnamed namespace */
|
|
|
|
/* Return true if all copy and move assignment operator overloads for
|
|
class TYPE are trivial and at least one of them is not deleted and,
|
|
when ACCESS is set, accessible. Return false otherwise. Set
|
|
HASASSIGN to true when the TYPE has a (not necessarily trivial)
|
|
copy or move assignment. */
|
|
|
|
static bool
|
|
has_trivial_copy_assign_p (tree type, bool access, bool *hasassign)
|
|
{
|
|
tree fns = get_class_binding (type, assign_op_identifier);
|
|
bool all_trivial = true;
|
|
|
|
/* Iterate over overloads of the assignment operator, checking
|
|
accessible copy assignments for triviality. */
|
|
|
|
for (tree f : ovl_range (fns))
|
|
{
|
|
/* Skip operators that aren't copy assignments. */
|
|
if (!copy_fn_p (f))
|
|
continue;
|
|
|
|
bool accessible = (!access || !(TREE_PRIVATE (f) || TREE_PROTECTED (f))
|
|
|| accessible_p (TYPE_BINFO (type), f, true));
|
|
|
|
/* Skip template assignment operators and deleted functions. */
|
|
if (TREE_CODE (f) != FUNCTION_DECL || DECL_DELETED_FN (f))
|
|
continue;
|
|
|
|
if (accessible)
|
|
*hasassign = true;
|
|
|
|
if (!accessible || !trivial_fn_p (f))
|
|
all_trivial = false;
|
|
|
|
/* Break early when both properties have been determined. */
|
|
if (*hasassign && !all_trivial)
|
|
break;
|
|
}
|
|
|
|
/* Return true if they're all trivial and one of the expressions
|
|
TYPE() = TYPE() or TYPE() = (TYPE&)() is valid. */
|
|
tree ref = cp_build_reference_type (type, false);
|
|
return (all_trivial
|
|
&& (is_trivially_xible (MODIFY_EXPR, type, type)
|
|
|| is_trivially_xible (MODIFY_EXPR, type, ref)));
|
|
}
|
|
|
|
/* Return true if all copy and move ctor overloads for class TYPE are
|
|
trivial and at least one of them is not deleted and, when ACCESS is
|
|
set, accessible. Return false otherwise. Set each element of HASCTOR[]
|
|
to true when the TYPE has a (not necessarily trivial) default and copy
|
|
(or move) ctor, respectively. */
|
|
|
|
static bool
|
|
has_trivial_copy_p (tree type, bool access, bool hasctor[2])
|
|
{
|
|
tree fns = get_class_binding (type, complete_ctor_identifier);
|
|
bool all_trivial = true;
|
|
|
|
for (tree f : ovl_range (fns))
|
|
{
|
|
/* Skip template constructors. */
|
|
if (TREE_CODE (f) != FUNCTION_DECL)
|
|
continue;
|
|
|
|
bool cpy_or_move_ctor_p = copy_fn_p (f);
|
|
|
|
/* Skip ctors other than default, copy, and move. */
|
|
if (!cpy_or_move_ctor_p && !default_ctor_p (f))
|
|
continue;
|
|
|
|
if (DECL_DELETED_FN (f))
|
|
continue;
|
|
|
|
bool accessible = (!access || !(TREE_PRIVATE (f) || TREE_PROTECTED (f))
|
|
|| accessible_p (TYPE_BINFO (type), f, true));
|
|
|
|
if (accessible)
|
|
hasctor[cpy_or_move_ctor_p] = true;
|
|
|
|
if (cpy_or_move_ctor_p && (!accessible || !trivial_fn_p (f)))
|
|
all_trivial = false;
|
|
|
|
/* Break early when both properties have been determined. */
|
|
if (hasctor[0] && hasctor[1] && !all_trivial)
|
|
break;
|
|
}
|
|
|
|
return all_trivial;
|
|
}
|
|
|
|
/* Issue a warning on a call to the built-in function FNDECL if it is
|
|
a raw memory write whose destination is not an object of (something
|
|
like) trivial or standard layout type with a non-deleted assignment
|
|
and copy ctor. Detects const correctness violations, corrupting
|
|
references, virtual table pointers, and bypassing non-trivial
|
|
assignments. */
|
|
|
|
static void
|
|
maybe_warn_class_memaccess (location_t loc, tree fndecl,
|
|
const vec<tree, va_gc> *args)
|
|
{
|
|
/* Except for bcopy where it's second, the destination pointer is
|
|
the first argument for all functions handled here. Compute
|
|
the index of the destination and source arguments. */
|
|
unsigned dstidx = DECL_FUNCTION_CODE (fndecl) == BUILT_IN_BCOPY;
|
|
unsigned srcidx = !dstidx;
|
|
|
|
tree dest = (*args)[dstidx];
|
|
if (!TREE_TYPE (dest)
|
|
|| (TREE_CODE (TREE_TYPE (dest)) != ARRAY_TYPE
|
|
&& !INDIRECT_TYPE_P (TREE_TYPE (dest))))
|
|
return;
|
|
|
|
tree srctype = NULL_TREE;
|
|
|
|
/* Determine the type of the pointed-to object and whether it's
|
|
a complete class type. */
|
|
tree desttype = TREE_TYPE (TREE_TYPE (dest));
|
|
|
|
if (!desttype || !COMPLETE_TYPE_P (desttype) || !CLASS_TYPE_P (desttype))
|
|
return;
|
|
|
|
/* Check to see if the raw memory call is made by a non-static member
|
|
function with THIS as the destination argument for the destination
|
|
type. If so, and if the class has no non-trivial bases or members,
|
|
be more permissive. */
|
|
if (current_function_decl
|
|
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (current_function_decl)
|
|
&& is_this_parameter (tree_strip_nop_conversions (dest)))
|
|
{
|
|
tree ctx = DECL_CONTEXT (current_function_decl);
|
|
bool special = same_type_ignoring_top_level_qualifiers_p (ctx, desttype);
|
|
tree binfo = TYPE_BINFO (ctx);
|
|
|
|
if (special
|
|
&& !BINFO_VTABLE (binfo)
|
|
&& !first_non_trivial_field (desttype))
|
|
return;
|
|
}
|
|
|
|
/* True if the class is trivial. */
|
|
bool trivial = trivial_type_p (desttype);
|
|
|
|
/* Set to true if DESTYPE has an accessible copy assignment. */
|
|
bool hasassign = false;
|
|
/* True if all of the class' overloaded copy assignment operators
|
|
are all trivial (and not deleted) and at least one of them is
|
|
accessible. */
|
|
bool trivassign = has_trivial_copy_assign_p (desttype, true, &hasassign);
|
|
|
|
/* Set to true if DESTTYPE has an accessible default and copy ctor,
|
|
respectively. */
|
|
bool hasctors[2] = { false, false };
|
|
|
|
/* True if all of the class' overloaded copy constructors are all
|
|
trivial (and not deleted) and at least one of them is accessible. */
|
|
bool trivcopy = has_trivial_copy_p (desttype, true, hasctors);
|
|
|
|
/* Set FLD to the first private/protected member of the class. */
|
|
tree fld = trivial ? first_non_public_field (desttype) : NULL_TREE;
|
|
|
|
/* The warning format string. */
|
|
const char *warnfmt = NULL;
|
|
/* A suggested alternative to offer instead of the raw memory call.
|
|
Empty string when none can be come up with. */
|
|
const char *suggest = "";
|
|
bool warned = false;
|
|
|
|
switch (DECL_FUNCTION_CODE (fndecl))
|
|
{
|
|
case BUILT_IN_MEMSET:
|
|
if (!integer_zerop (maybe_constant_value ((*args)[1])))
|
|
{
|
|
/* Diagnose setting non-copy-assignable or non-trivial types,
|
|
or types with a private member, to (potentially) non-zero
|
|
bytes. Since the value of the bytes being written is unknown,
|
|
suggest using assignment instead (if one exists). Also warn
|
|
for writes into objects for which zero-initialization doesn't
|
|
mean all bits clear (pointer-to-member data, where null is all
|
|
bits set). Since the value being written is (most likely)
|
|
non-zero, simply suggest assignment (but not copy assignment). */
|
|
suggest = "; use assignment instead";
|
|
if (!trivassign)
|
|
warnfmt = G_("%qD writing to an object of type %#qT with "
|
|
"no trivial copy-assignment");
|
|
else if (!trivial)
|
|
warnfmt = G_("%qD writing to an object of non-trivial type %#qT%s");
|
|
else if (fld)
|
|
{
|
|
const char *access = TREE_PRIVATE (fld) ? "private" : "protected";
|
|
warned = warning_at (loc, OPT_Wclass_memaccess,
|
|
"%qD writing to an object of type %#qT with "
|
|
"%qs member %qD",
|
|
fndecl, desttype, access, fld);
|
|
}
|
|
else if (!zero_init_p (desttype))
|
|
warnfmt = G_("%qD writing to an object of type %#qT containing "
|
|
"a pointer to data member%s");
|
|
|
|
break;
|
|
}
|
|
/* Fall through. */
|
|
|
|
case BUILT_IN_BZERO:
|
|
/* Similarly to the above, diagnose clearing non-trivial or non-
|
|
standard layout objects, or objects of types with no assignmenmt.
|
|
Since the value being written is known to be zero, suggest either
|
|
copy assignment, copy ctor, or default ctor as an alternative,
|
|
depending on what's available. */
|
|
|
|
if (hasassign && hasctors[0])
|
|
suggest = G_("; use assignment or value-initialization instead");
|
|
else if (hasassign)
|
|
suggest = G_("; use assignment instead");
|
|
else if (hasctors[0])
|
|
suggest = G_("; use value-initialization instead");
|
|
|
|
if (!trivassign)
|
|
warnfmt = G_("%qD clearing an object of type %#qT with "
|
|
"no trivial copy-assignment%s");
|
|
else if (!trivial)
|
|
warnfmt = G_("%qD clearing an object of non-trivial type %#qT%s");
|
|
else if (!zero_init_p (desttype))
|
|
warnfmt = G_("%qD clearing an object of type %#qT containing "
|
|
"a pointer-to-member%s");
|
|
break;
|
|
|
|
case BUILT_IN_BCOPY:
|
|
case BUILT_IN_MEMCPY:
|
|
case BUILT_IN_MEMMOVE:
|
|
case BUILT_IN_MEMPCPY:
|
|
/* Determine the type of the source object. */
|
|
srctype = TREE_TYPE ((*args)[srcidx]);
|
|
if (!srctype || !INDIRECT_TYPE_P (srctype))
|
|
srctype = void_type_node;
|
|
else
|
|
srctype = TREE_TYPE (srctype);
|
|
|
|
/* Since it's impossible to determine wheter the byte copy is
|
|
being used in place of assignment to an existing object or
|
|
as a substitute for initialization, assume it's the former.
|
|
Determine the best alternative to use instead depending on
|
|
what's not deleted. */
|
|
if (hasassign && hasctors[1])
|
|
suggest = G_("; use copy-assignment or copy-initialization instead");
|
|
else if (hasassign)
|
|
suggest = G_("; use copy-assignment instead");
|
|
else if (hasctors[1])
|
|
suggest = G_("; use copy-initialization instead");
|
|
|
|
if (!trivassign)
|
|
warnfmt = G_("%qD writing to an object of type %#qT with no trivial "
|
|
"copy-assignment%s");
|
|
else if (!trivially_copyable_p (desttype))
|
|
warnfmt = G_("%qD writing to an object of non-trivially copyable "
|
|
"type %#qT%s");
|
|
else if (!trivcopy)
|
|
warnfmt = G_("%qD writing to an object with a deleted copy constructor");
|
|
|
|
else if (!trivial
|
|
&& !VOID_TYPE_P (srctype)
|
|
&& !is_byte_access_type (srctype)
|
|
&& !same_type_ignoring_top_level_qualifiers_p (desttype,
|
|
srctype))
|
|
{
|
|
/* Warn when copying into a non-trivial object from an object
|
|
of a different type other than void or char. */
|
|
warned = warning_at (loc, OPT_Wclass_memaccess,
|
|
"%qD copying an object of non-trivial type "
|
|
"%#qT from an array of %#qT",
|
|
fndecl, desttype, srctype);
|
|
}
|
|
else if (fld
|
|
&& !VOID_TYPE_P (srctype)
|
|
&& !is_byte_access_type (srctype)
|
|
&& !same_type_ignoring_top_level_qualifiers_p (desttype,
|
|
srctype))
|
|
{
|
|
const char *access = TREE_PRIVATE (fld) ? "private" : "protected";
|
|
warned = warning_at (loc, OPT_Wclass_memaccess,
|
|
"%qD copying an object of type %#qT with "
|
|
"%qs member %qD from an array of %#qT; use "
|
|
"assignment or copy-initialization instead",
|
|
fndecl, desttype, access, fld, srctype);
|
|
}
|
|
else if (!trivial && vec_safe_length (args) > 2)
|
|
{
|
|
tree sz = maybe_constant_value ((*args)[2]);
|
|
if (!tree_fits_uhwi_p (sz))
|
|
break;
|
|
|
|
/* Finally, warn on partial copies. */
|
|
unsigned HOST_WIDE_INT typesize
|
|
= tree_to_uhwi (TYPE_SIZE_UNIT (desttype));
|
|
if (typesize == 0)
|
|
break;
|
|
if (unsigned HOST_WIDE_INT partial = tree_to_uhwi (sz) % typesize)
|
|
warned = warning_at (loc, OPT_Wclass_memaccess,
|
|
(typesize - partial > 1
|
|
? G_("%qD writing to an object of "
|
|
"a non-trivial type %#qT leaves %wu "
|
|
"bytes unchanged")
|
|
: G_("%qD writing to an object of "
|
|
"a non-trivial type %#qT leaves %wu "
|
|
"byte unchanged")),
|
|
fndecl, desttype, typesize - partial);
|
|
}
|
|
break;
|
|
|
|
case BUILT_IN_REALLOC:
|
|
|
|
if (!trivially_copyable_p (desttype))
|
|
warnfmt = G_("%qD moving an object of non-trivially copyable type "
|
|
"%#qT; use %<new%> and %<delete%> instead");
|
|
else if (!trivcopy)
|
|
warnfmt = G_("%qD moving an object of type %#qT with deleted copy "
|
|
"constructor; use %<new%> and %<delete%> instead");
|
|
else if (!get_dtor (desttype, tf_none))
|
|
warnfmt = G_("%qD moving an object of type %#qT with deleted "
|
|
"destructor");
|
|
else if (!trivial)
|
|
{
|
|
tree sz = maybe_constant_value ((*args)[1]);
|
|
if (TREE_CODE (sz) == INTEGER_CST
|
|
&& tree_int_cst_lt (sz, TYPE_SIZE_UNIT (desttype)))
|
|
/* Finally, warn on reallocation into insufficient space. */
|
|
warned = warning_at (loc, OPT_Wclass_memaccess,
|
|
"%qD moving an object of non-trivial type "
|
|
"%#qT and size %E into a region of size %E",
|
|
fndecl, desttype, TYPE_SIZE_UNIT (desttype),
|
|
sz);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if (warnfmt)
|
|
{
|
|
if (suggest)
|
|
warned = warning_at (loc, OPT_Wclass_memaccess,
|
|
warnfmt, fndecl, desttype, suggest);
|
|
else
|
|
warned = warning_at (loc, OPT_Wclass_memaccess,
|
|
warnfmt, fndecl, desttype);
|
|
}
|
|
|
|
if (warned)
|
|
inform (location_of (desttype), "%#qT declared here", desttype);
|
|
}
|
|
|
|
/* Build and return a call to FN, using NARGS arguments in ARGARRAY.
|
|
If FN is the result of resolving an overloaded target built-in,
|
|
ORIG_FNDECL is the original function decl, otherwise it is null.
|
|
This function performs no overload resolution, conversion, or other
|
|
high-level operations. */
|
|
|
|
tree
|
|
build_cxx_call (tree fn, int nargs, tree *argarray,
|
|
tsubst_flags_t complain, tree orig_fndecl)
|
|
{
|
|
tree fndecl;
|
|
|
|
/* Remember roughly where this call is. */
|
|
location_t loc = cp_expr_loc_or_input_loc (fn);
|
|
fn = build_call_a (fn, nargs, argarray);
|
|
SET_EXPR_LOCATION (fn, loc);
|
|
|
|
fndecl = get_callee_fndecl (fn);
|
|
if (!orig_fndecl)
|
|
orig_fndecl = fndecl;
|
|
|
|
/* Check that arguments to builtin functions match the expectations. */
|
|
if (fndecl
|
|
&& !processing_template_decl
|
|
&& fndecl_built_in_p (fndecl))
|
|
{
|
|
int i;
|
|
|
|
/* We need to take care that values to BUILT_IN_NORMAL
|
|
are reduced. */
|
|
for (i = 0; i < nargs; i++)
|
|
argarray[i] = maybe_constant_value (argarray[i]);
|
|
|
|
if (!check_builtin_function_arguments (EXPR_LOCATION (fn), vNULL, fndecl,
|
|
orig_fndecl, nargs, argarray))
|
|
return error_mark_node;
|
|
else if (fndecl_built_in_p (fndecl, BUILT_IN_CLEAR_PADDING))
|
|
{
|
|
tree arg0 = argarray[0];
|
|
STRIP_NOPS (arg0);
|
|
if (TREE_CODE (arg0) == ADDR_EXPR
|
|
&& DECL_P (TREE_OPERAND (arg0, 0))
|
|
&& same_type_ignoring_top_level_qualifiers_p
|
|
(TREE_TYPE (TREE_TYPE (argarray[0])),
|
|
TREE_TYPE (TREE_TYPE (arg0))))
|
|
/* For __builtin_clear_padding (&var) we know the type
|
|
is for a complete object, so there is no risk in clearing
|
|
padding that is reused in some derived class member. */;
|
|
else if (!trivially_copyable_p (TREE_TYPE (TREE_TYPE (argarray[0]))))
|
|
{
|
|
error_at (EXPR_LOC_OR_LOC (argarray[0], input_location),
|
|
"argument %u in call to function %qE "
|
|
"has pointer to a non-trivially-copyable type (%qT)",
|
|
1, fndecl, TREE_TYPE (argarray[0]));
|
|
return error_mark_node;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (VOID_TYPE_P (TREE_TYPE (fn)))
|
|
return fn;
|
|
|
|
/* 5.2.2/11: If a function call is a prvalue of object type: if the
|
|
function call is either the operand of a decltype-specifier or the
|
|
right operand of a comma operator that is the operand of a
|
|
decltype-specifier, a temporary object is not introduced for the
|
|
prvalue. The type of the prvalue may be incomplete. */
|
|
if (!(complain & tf_decltype))
|
|
{
|
|
fn = require_complete_type_sfinae (fn, complain);
|
|
if (fn == error_mark_node)
|
|
return error_mark_node;
|
|
|
|
if (MAYBE_CLASS_TYPE_P (TREE_TYPE (fn)))
|
|
{
|
|
fn = build_cplus_new (TREE_TYPE (fn), fn, complain);
|
|
maybe_warn_parm_abi (TREE_TYPE (fn), loc);
|
|
}
|
|
}
|
|
return convert_from_reference (fn);
|
|
}
|
|
|
|
/* Returns the value to use for the in-charge parameter when making a
|
|
call to a function with the indicated NAME.
|
|
|
|
FIXME:Can't we find a neater way to do this mapping? */
|
|
|
|
tree
|
|
in_charge_arg_for_name (tree name)
|
|
{
|
|
if (IDENTIFIER_CTOR_P (name))
|
|
{
|
|
if (name == complete_ctor_identifier)
|
|
return integer_one_node;
|
|
gcc_checking_assert (name == base_ctor_identifier);
|
|
}
|
|
else
|
|
{
|
|
if (name == complete_dtor_identifier)
|
|
return integer_two_node;
|
|
else if (name == deleting_dtor_identifier)
|
|
return integer_three_node;
|
|
gcc_checking_assert (name == base_dtor_identifier);
|
|
}
|
|
|
|
return integer_zero_node;
|
|
}
|
|
|
|
/* We've built up a constructor call RET. Complain if it delegates to the
|
|
constructor we're currently compiling. */
|
|
|
|
static void
|
|
check_self_delegation (tree ret)
|
|
{
|
|
if (TREE_CODE (ret) == TARGET_EXPR)
|
|
ret = TARGET_EXPR_INITIAL (ret);
|
|
tree fn = cp_get_callee_fndecl_nofold (ret);
|
|
if (fn && DECL_ABSTRACT_ORIGIN (fn) == current_function_decl)
|
|
error ("constructor delegates to itself");
|
|
}
|
|
|
|
/* Build a call to a constructor, destructor, or an assignment
|
|
operator for INSTANCE, an expression with class type. NAME
|
|
indicates the special member function to call; *ARGS are the
|
|
arguments. ARGS may be NULL. This may change ARGS. BINFO
|
|
indicates the base of INSTANCE that is to be passed as the `this'
|
|
parameter to the member function called.
|
|
|
|
FLAGS are the LOOKUP_* flags to use when processing the call.
|
|
|
|
If NAME indicates a complete object constructor, INSTANCE may be
|
|
NULL_TREE. In this case, the caller will call build_cplus_new to
|
|
store the newly constructed object into a VAR_DECL. */
|
|
|
|
tree
|
|
build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args,
|
|
tree binfo, int flags, tsubst_flags_t complain)
|
|
{
|
|
tree fns;
|
|
/* The type of the subobject to be constructed or destroyed. */
|
|
tree class_type;
|
|
vec<tree, va_gc> *allocated = NULL;
|
|
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. */
|
|
if (!complete_type_or_maybe_complain (binfo, NULL_TREE, complain))
|
|
return error_mark_node;
|
|
|
|
binfo = TYPE_BINFO (binfo);
|
|
}
|
|
|
|
gcc_assert (binfo != NULL_TREE);
|
|
|
|
class_type = BINFO_TYPE (binfo);
|
|
|
|
/* Handle the special case where INSTANCE is NULL_TREE. */
|
|
if (name == complete_ctor_identifier && !instance)
|
|
instance = build_dummy_object (class_type);
|
|
else
|
|
{
|
|
/* Convert to the base class, if necessary. */
|
|
if (!same_type_ignoring_top_level_qualifiers_p
|
|
(TREE_TYPE (instance), BINFO_TYPE (binfo)))
|
|
{
|
|
if (IDENTIFIER_CDTOR_P (name))
|
|
/* For constructors and destructors, either the base is
|
|
non-virtual, or it is virtual but we are doing the
|
|
conversion from a constructor or destructor for the
|
|
complete object. In either case, we can convert
|
|
statically. */
|
|
instance = convert_to_base_statically (instance, binfo);
|
|
else
|
|
{
|
|
/* However, for assignment operators, we must convert
|
|
dynamically if the base is virtual. */
|
|
gcc_checking_assert (name == assign_op_identifier);
|
|
instance = build_base_path (PLUS_EXPR, instance,
|
|
binfo, /*nonnull=*/1, complain);
|
|
}
|
|
}
|
|
}
|
|
|
|
gcc_assert (instance != NULL_TREE);
|
|
|
|
/* In C++17, "If the initializer expression is a prvalue and the
|
|
cv-unqualified version of the source type is the same class as the class
|
|
of the destination, the initializer expression is used to initialize the
|
|
destination object." Handle that here to avoid doing overload
|
|
resolution. */
|
|
if (cxx_dialect >= cxx17
|
|
&& args && vec_safe_length (*args) == 1
|
|
&& !unsafe_return_slot_p (instance))
|
|
{
|
|
tree arg = (**args)[0];
|
|
|
|
if (BRACE_ENCLOSED_INITIALIZER_P (arg)
|
|
&& !TYPE_HAS_LIST_CTOR (class_type)
|
|
&& !CONSTRUCTOR_IS_DESIGNATED_INIT (arg)
|
|
&& CONSTRUCTOR_NELTS (arg) == 1)
|
|
arg = CONSTRUCTOR_ELT (arg, 0)->value;
|
|
|
|
if ((TREE_CODE (arg) == TARGET_EXPR
|
|
|| TREE_CODE (arg) == CONSTRUCTOR)
|
|
&& (same_type_ignoring_top_level_qualifiers_p
|
|
(class_type, TREE_TYPE (arg))))
|
|
{
|
|
if (is_dummy_object (instance))
|
|
return arg;
|
|
else if (TREE_CODE (arg) == TARGET_EXPR)
|
|
TARGET_EXPR_DIRECT_INIT_P (arg) = true;
|
|
|
|
if ((complain & tf_error)
|
|
&& (flags & LOOKUP_DELEGATING_CONS))
|
|
check_self_delegation (arg);
|
|
/* Avoid change of behavior on Wunused-var-2.C. */
|
|
instance = mark_lvalue_use (instance);
|
|
return build2 (INIT_EXPR, class_type, instance, arg);
|
|
}
|
|
}
|
|
|
|
fns = lookup_fnfields (binfo, name, 1, complain);
|
|
|
|
/* When making a call to a constructor or destructor for a subobject
|
|
that uses virtual base classes, pass down a pointer to a VTT for
|
|
the subobject. */
|
|
if ((name == base_ctor_identifier
|
|
|| name == base_dtor_identifier)
|
|
&& CLASSTYPE_VBASECLASSES (class_type))
|
|
{
|
|
tree vtt;
|
|
tree sub_vtt;
|
|
|
|
/* If the current function is a complete object constructor
|
|
or destructor, then we fetch the VTT directly.
|
|
Otherwise, we look it up using the VTT we were given. */
|
|
vtt = DECL_CHAIN (CLASSTYPE_VTABLES (current_class_type));
|
|
vtt = decay_conversion (vtt, complain);
|
|
if (vtt == error_mark_node)
|
|
return error_mark_node;
|
|
vtt = build_if_in_charge (vtt, current_vtt_parm);
|
|
if (BINFO_SUBVTT_INDEX (binfo))
|
|
sub_vtt = fold_build_pointer_plus (vtt, BINFO_SUBVTT_INDEX (binfo));
|
|
else
|
|
sub_vtt = vtt;
|
|
|
|
if (args == NULL)
|
|
{
|
|
allocated = make_tree_vector ();
|
|
args = &allocated;
|
|
}
|
|
|
|
vec_safe_insert (*args, 0, sub_vtt);
|
|
}
|
|
|
|
ret = build_new_method_call (instance, fns, args,
|
|
TYPE_BINFO (BINFO_TYPE (binfo)),
|
|
flags, /*fn=*/NULL,
|
|
complain);
|
|
|
|
if (allocated != NULL)
|
|
release_tree_vector (allocated);
|
|
|
|
if ((complain & tf_error)
|
|
&& (flags & LOOKUP_DELEGATING_CONS)
|
|
&& name == complete_ctor_identifier)
|
|
check_self_delegation (ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Return the NAME, as a C string. The NAME indicates a function that
|
|
is a member of TYPE. *FREE_P is set to true if the caller must
|
|
free the memory returned.
|
|
|
|
Rather than go through all of this, we should simply set the names
|
|
of constructors and destructors appropriately, and dispense with
|
|
ctor_identifier, dtor_identifier, etc. */
|
|
|
|
static char *
|
|
name_as_c_string (tree name, tree type, bool *free_p)
|
|
{
|
|
const char *pretty_name;
|
|
|
|
/* Assume that we will not allocate memory. */
|
|
*free_p = false;
|
|
/* Constructors and destructors are special. */
|
|
if (IDENTIFIER_CDTOR_P (name))
|
|
{
|
|
pretty_name
|
|
= identifier_to_locale (IDENTIFIER_POINTER (constructor_name (type)));
|
|
/* For a destructor, add the '~'. */
|
|
if (IDENTIFIER_DTOR_P (name))
|
|
{
|
|
pretty_name = concat ("~", pretty_name, NULL);
|
|
/* Remember that we need to free the memory allocated. */
|
|
*free_p = true;
|
|
}
|
|
}
|
|
else if (IDENTIFIER_CONV_OP_P (name))
|
|
{
|
|
pretty_name = concat ("operator ",
|
|
type_as_string_translate (TREE_TYPE (name),
|
|
TFF_PLAIN_IDENTIFIER),
|
|
NULL);
|
|
/* Remember that we need to free the memory allocated. */
|
|
*free_p = true;
|
|
}
|
|
else
|
|
pretty_name = identifier_to_locale (IDENTIFIER_POINTER (name));
|
|
|
|
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))
|
|
{
|
|
tree from_type = conv->from;
|
|
if (!TYPE_P (conv->from))
|
|
from_type = lvalue_type (conv->from);
|
|
complain_about_bad_argument (conv->loc,
|
|
from_type, 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. */
|
|
|
|
tree
|
|
build_new_method_call (tree instance, tree fns, vec<tree, va_gc> **args,
|
|
tree conversion_path, int flags,
|
|
tree *fn_p, tsubst_flags_t complain)
|
|
{
|
|
struct z_candidate *candidates = 0, *cand;
|
|
tree explicit_targs = NULL_TREE;
|
|
tree basetype = NULL_TREE;
|
|
tree access_binfo;
|
|
tree optype;
|
|
tree first_mem_arg = NULL_TREE;
|
|
tree name;
|
|
bool skip_first_for_error;
|
|
vec<tree, va_gc> *user_args;
|
|
tree call;
|
|
tree fn;
|
|
int template_only = 0;
|
|
bool any_viable_p;
|
|
tree orig_instance;
|
|
tree orig_fns;
|
|
vec<tree, va_gc> *orig_args = NULL;
|
|
void *p;
|
|
|
|
auto_cond_timevar tv (TV_OVERLOAD);
|
|
|
|
gcc_assert (instance != NULL_TREE);
|
|
|
|
/* We don't know what function we're going to call, yet. */
|
|
if (fn_p)
|
|
*fn_p = NULL_TREE;
|
|
|
|
if (error_operand_p (instance)
|
|
|| !fns || error_operand_p (fns))
|
|
return error_mark_node;
|
|
|
|
if (!BASELINK_P (fns))
|
|
{
|
|
if (complain & tf_error)
|
|
error ("call to non-function %qD", fns);
|
|
return error_mark_node;
|
|
}
|
|
|
|
orig_instance = instance;
|
|
orig_fns = fns;
|
|
|
|
/* Dismantle the baselink to collect all the information we need. */
|
|
if (!conversion_path)
|
|
conversion_path = BASELINK_BINFO (fns);
|
|
access_binfo = BASELINK_ACCESS_BINFO (fns);
|
|
optype = BASELINK_OPTYPE (fns);
|
|
fns = BASELINK_FUNCTIONS (fns);
|
|
if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
|
|
{
|
|
explicit_targs = TREE_OPERAND (fns, 1);
|
|
fns = TREE_OPERAND (fns, 0);
|
|
template_only = 1;
|
|
}
|
|
gcc_assert (OVL_P (fns));
|
|
fn = OVL_FIRST (fns);
|
|
name = DECL_NAME (fn);
|
|
|
|
basetype = TYPE_MAIN_VARIANT (TREE_TYPE (instance));
|
|
gcc_assert (CLASS_TYPE_P (basetype));
|
|
|
|
user_args = args == NULL ? NULL : *args;
|
|
/* Under DR 147 A::A() is an invalid constructor call,
|
|
not a functional cast. */
|
|
if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn))
|
|
{
|
|
if (! (complain & tf_error))
|
|
return error_mark_node;
|
|
|
|
basetype = DECL_CONTEXT (fn);
|
|
name = constructor_name (basetype);
|
|
auto_diagnostic_group d;
|
|
if (permerror (input_location,
|
|
"cannot call constructor %<%T::%D%> directly",
|
|
basetype, name))
|
|
inform (input_location, "for a function-style cast, remove the "
|
|
"redundant %<::%D%>", name);
|
|
call = build_functional_cast (input_location, basetype,
|
|
build_tree_list_vec (user_args),
|
|
complain);
|
|
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
|
|
static member function. */
|
|
instance = mark_type_use (instance);
|
|
|
|
/* Figure out whether to skip the first argument for the error
|
|
message we will display to users if an error occurs. We don't
|
|
want to display any compiler-generated arguments. The "this"
|
|
pointer hasn't been added yet. However, we must remove the VTT
|
|
pointer if this is a call to a base-class constructor or
|
|
destructor. */
|
|
skip_first_for_error = false;
|
|
if (IDENTIFIER_CDTOR_P (name))
|
|
{
|
|
/* Callers should explicitly indicate whether they want to ctor
|
|
the complete object or just the part without virtual bases. */
|
|
gcc_assert (name != ctor_identifier);
|
|
|
|
/* Remove the VTT pointer, if present. */
|
|
if ((name == base_ctor_identifier || name == base_dtor_identifier)
|
|
&& CLASSTYPE_VBASECLASSES (basetype))
|
|
skip_first_for_error = true;
|
|
|
|
/* It's OK to call destructors and constructors on cv-qualified
|
|
objects. Therefore, convert the INSTANCE to the unqualified
|
|
type, if necessary. */
|
|
if (!same_type_p (basetype, TREE_TYPE (instance)))
|
|
{
|
|
instance = build_this (instance);
|
|
instance = build_nop (build_pointer_type (basetype), instance);
|
|
instance = build_fold_indirect_ref (instance);
|
|
}
|
|
}
|
|
else
|
|
gcc_assert (!DECL_DESTRUCTOR_P (fn) && !DECL_CONSTRUCTOR_P (fn));
|
|
|
|
/* For the overload resolution we need to find the actual `this`
|
|
that would be captured if the call turns out to be to a
|
|
non-static member function. Do not actually capture it at this
|
|
point. */
|
|
if (DECL_CONSTRUCTOR_P (fn))
|
|
/* Constructors don't use the enclosing 'this'. */
|
|
first_mem_arg = instance;
|
|
else
|
|
first_mem_arg = maybe_resolve_dummy (instance, false);
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
p = conversion_obstack_alloc (0);
|
|
|
|
/* The number of arguments artificial parms in ARGS; we subtract one because
|
|
there's no 'this' in ARGS. */
|
|
unsigned skip = num_artificial_parms_for (fn) - 1;
|
|
|
|
/* If CONSTRUCTOR_IS_DIRECT_INIT is set, this was a T{ } form
|
|
initializer, not T({ }). */
|
|
if (DECL_CONSTRUCTOR_P (fn)
|
|
&& vec_safe_length (user_args) > skip
|
|
&& DIRECT_LIST_INIT_P ((*user_args)[skip]))
|
|
{
|
|
tree init_list = (*user_args)[skip];
|
|
tree init = NULL_TREE;
|
|
|
|
gcc_assert (user_args->length () == skip + 1
|
|
&& !(flags & LOOKUP_ONLYCONVERTING));
|
|
|
|
/* If the initializer list has no elements and T is a class type with
|
|
a default constructor, the object is value-initialized. Handle
|
|
this here so we don't need to handle it wherever we use
|
|
build_special_member_call. */
|
|
if (CONSTRUCTOR_NELTS (init_list) == 0
|
|
&& TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype)
|
|
/* For a user-provided default constructor, use the normal
|
|
mechanisms so that protected access works. */
|
|
&& type_has_non_user_provided_default_constructor (basetype)
|
|
&& !processing_template_decl)
|
|
init = build_value_init (basetype, complain);
|
|
|
|
/* If BASETYPE is an aggregate, we need to do aggregate
|
|
initialization. */
|
|
else if (CP_AGGREGATE_TYPE_P (basetype))
|
|
{
|
|
init = reshape_init (basetype, init_list, complain);
|
|
init = digest_init (basetype, init, complain);
|
|
}
|
|
|
|
if (init)
|
|
{
|
|
if (is_dummy_object (instance))
|
|
return get_target_expr_sfinae (init, complain);
|
|
init = build2 (INIT_EXPR, TREE_TYPE (instance), instance, init);
|
|
TREE_SIDE_EFFECTS (init) = true;
|
|
return init;
|
|
}
|
|
|
|
/* Otherwise go ahead with overload resolution. */
|
|
add_list_candidates (fns, first_mem_arg, user_args,
|
|
basetype, explicit_targs, template_only,
|
|
conversion_path, access_binfo, flags,
|
|
&candidates, complain);
|
|
}
|
|
else
|
|
add_candidates (fns, first_mem_arg, user_args, optype,
|
|
explicit_targs, template_only, conversion_path,
|
|
access_binfo, flags, &candidates, complain);
|
|
|
|
any_viable_p = false;
|
|
candidates = splice_viable (candidates, false, &any_viable_p);
|
|
|
|
if (!any_viable_p)
|
|
{
|
|
/* [dcl.init], 17.6.2.2:
|
|
|
|
Otherwise, if no constructor is viable, the destination type is
|
|
a (possibly cv-qualified) aggregate class A, and the initializer
|
|
is a parenthesized expression-list, the object is initialized as
|
|
follows...
|
|
|
|
We achieve this by building up a CONSTRUCTOR, as for list-init,
|
|
and setting CONSTRUCTOR_IS_PAREN_INIT to distinguish between
|
|
the two. */
|
|
if (DECL_CONSTRUCTOR_P (fn)
|
|
&& !(flags & LOOKUP_ONLYCONVERTING)
|
|
&& cxx_dialect >= cxx20
|
|
&& CP_AGGREGATE_TYPE_P (basetype)
|
|
&& !vec_safe_is_empty (user_args))
|
|
{
|
|
/* Create a CONSTRUCTOR from ARGS, e.g. {1, 2} from <1, 2>. */
|
|
tree ctor = build_constructor_from_vec (init_list_type_node,
|
|
user_args);
|
|
CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true;
|
|
CONSTRUCTOR_IS_PAREN_INIT (ctor) = true;
|
|
if (is_dummy_object (instance))
|
|
return ctor;
|
|
else
|
|
{
|
|
ctor = digest_init (basetype, ctor, complain);
|
|
if (ctor == error_mark_node)
|
|
return error_mark_node;
|
|
ctor = build2 (INIT_EXPR, TREE_TYPE (instance), instance, ctor);
|
|
TREE_SIDE_EFFECTS (ctor) = true;
|
|
return ctor;
|
|
}
|
|
}
|
|
if (complain & tf_error)
|
|
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
|
|
{
|
|
cand = tourney (candidates, complain);
|
|
if (cand == 0)
|
|
{
|
|
char *pretty_name;
|
|
bool free_p;
|
|
tree arglist;
|
|
|
|
if (complain & tf_error)
|
|
{
|
|
pretty_name = name_as_c_string (name, basetype, &free_p);
|
|
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);
|
|
else
|
|
error ("call of overloaded %<%s(%A)%> is ambiguous",
|
|
pretty_name, arglist);
|
|
print_z_candidates (location_of (name), candidates);
|
|
if (free_p)
|
|
free (pretty_name);
|
|
}
|
|
call = error_mark_node;
|
|
if (fn_p)
|
|
*fn_p = error_mark_node;
|
|
}
|
|
else
|
|
{
|
|
fn = cand->fn;
|
|
call = NULL_TREE;
|
|
|
|
if (!(flags & LOOKUP_NONVIRTUAL)
|
|
&& DECL_PURE_VIRTUAL_P (fn)
|
|
&& instance == current_class_ref
|
|
&& (complain & tf_warning))
|
|
{
|
|
/* This is not an error, it is runtime undefined
|
|
behavior. */
|
|
if (!current_function_decl)
|
|
warning (0, "pure virtual %q#D called from "
|
|
"non-static data member initializer", fn);
|
|
else if (DECL_CONSTRUCTOR_P (current_function_decl)
|
|
|| DECL_DESTRUCTOR_P (current_function_decl))
|
|
warning (0, (DECL_CONSTRUCTOR_P (current_function_decl)
|
|
? G_("pure virtual %q#D called from constructor")
|
|
: G_("pure virtual %q#D called from destructor")),
|
|
fn);
|
|
}
|
|
|
|
if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
|
|
&& !DECL_CONSTRUCTOR_P (fn)
|
|
&& is_dummy_object (instance))
|
|
{
|
|
instance = maybe_resolve_dummy (instance, true);
|
|
if (instance == error_mark_node)
|
|
call = error_mark_node;
|
|
else if (!is_dummy_object (instance))
|
|
{
|
|
/* We captured 'this' in the current lambda now that
|
|
we know we really need it. */
|
|
cand->first_arg = instance;
|
|
}
|
|
else if (current_class_ptr && any_dependent_bases_p ())
|
|
/* We can't tell until instantiation time whether we can use
|
|
*this as the implicit object argument. */;
|
|
else
|
|
{
|
|
if (complain & tf_error)
|
|
error ("cannot call member function %qD without object",
|
|
fn);
|
|
call = error_mark_node;
|
|
}
|
|
}
|
|
|
|
if (call != error_mark_node)
|
|
{
|
|
/* Now we know what function is being called. */
|
|
if (fn_p)
|
|
*fn_p = fn;
|
|
/* Build the actual CALL_EXPR. */
|
|
call = build_over_call (cand, flags, complain);
|
|
/* In an expression of the form `a->f()' where `f' turns
|
|
out to be a static member function, `a' is
|
|
none-the-less evaluated. */
|
|
if (TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
|
|
&& !is_dummy_object (instance)
|
|
&& TREE_SIDE_EFFECTS (instance))
|
|
{
|
|
/* But avoid the implicit lvalue-rvalue conversion when 'a'
|
|
is volatile. */
|
|
tree a = instance;
|
|
if (TREE_THIS_VOLATILE (a))
|
|
a = build_this (a);
|
|
if (TREE_SIDE_EFFECTS (a))
|
|
call = build2 (COMPOUND_EXPR, TREE_TYPE (call), a, call);
|
|
}
|
|
else if (call != error_mark_node
|
|
&& DECL_DESTRUCTOR_P (cand->fn)
|
|
&& !VOID_TYPE_P (TREE_TYPE (call)))
|
|
/* An explicit call of the form "x->~X()" has type
|
|
"void". However, on platforms where destructors
|
|
return "this" (i.e., those where
|
|
targetm.cxx.cdtor_returns_this is true), such calls
|
|
will appear to have a return value of pointer type
|
|
to the low-level call machinery. We do not want to
|
|
change the low-level machinery, since we want to be
|
|
able to optimize "delete f()" on such platforms as
|
|
"operator delete(~X(f()))" (rather than generating
|
|
"t = f(), ~X(t), operator delete (t)"). */
|
|
call = build_nop (void_type_node, call);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (processing_template_decl && call != error_mark_node)
|
|
{
|
|
bool cast_to_void = false;
|
|
|
|
if (TREE_CODE (call) == COMPOUND_EXPR)
|
|
call = TREE_OPERAND (call, 1);
|
|
else if (TREE_CODE (call) == NOP_EXPR)
|
|
{
|
|
cast_to_void = true;
|
|
call = TREE_OPERAND (call, 0);
|
|
}
|
|
if (INDIRECT_REF_P (call))
|
|
call = TREE_OPERAND (call, 0);
|
|
|
|
/* Prune all but the selected function from the original overload
|
|
set so that we can avoid some duplicate work at instantiation time. */
|
|
if (really_overloaded_fn (fns))
|
|
{
|
|
if (DECL_TEMPLATE_INFO (fn)
|
|
&& DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (fn)))
|
|
{
|
|
/* Use the selected template, not the specialization, so that
|
|
this looks like an actual lookup result for sake of
|
|
filter_memfn_lookup. */
|
|
|
|
if (OVL_SINGLE_P (fns))
|
|
/* If the original overload set consists of a single function
|
|
template, this isn't beneficial. */
|
|
goto skip_prune;
|
|
|
|
fn = ovl_make (DECL_TI_TEMPLATE (fn));
|
|
if (template_only)
|
|
fn = lookup_template_function (fn, explicit_targs);
|
|
}
|
|
orig_fns = copy_node (orig_fns);
|
|
BASELINK_FUNCTIONS (orig_fns) = fn;
|
|
BASELINK_FUNCTIONS_MAYBE_INCOMPLETE_P (orig_fns) = true;
|
|
}
|
|
|
|
skip_prune:
|
|
call = (build_min_non_dep_call_vec
|
|
(call,
|
|
build_min (COMPONENT_REF, TREE_TYPE (CALL_EXPR_FN (call)),
|
|
orig_instance, orig_fns, NULL_TREE),
|
|
orig_args));
|
|
SET_EXPR_LOCATION (call, input_location);
|
|
call = convert_from_reference (call);
|
|
if (cast_to_void)
|
|
call = build_nop (void_type_node, call);
|
|
}
|
|
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
if (orig_args != NULL)
|
|
release_tree_vector (orig_args);
|
|
|
|
return call;
|
|
}
|
|
|
|
/* Returns true iff standard conversion sequence ICS1 is a proper
|
|
subsequence of ICS2. */
|
|
|
|
static bool
|
|
is_subseq (conversion *ics1, conversion *ics2)
|
|
{
|
|
/* We can assume that a conversion of the same code
|
|
between the same types indicates a subsequence since we only get
|
|
here if the types we are converting from are the same. */
|
|
|
|
while (ics1->kind == ck_rvalue
|
|
|| ics1->kind == ck_lvalue)
|
|
ics1 = next_conversion (ics1);
|
|
|
|
while (1)
|
|
{
|
|
while (ics2->kind == ck_rvalue
|
|
|| ics2->kind == ck_lvalue)
|
|
ics2 = next_conversion (ics2);
|
|
|
|
if (ics2->kind == ck_user
|
|
|| !has_next (ics2->kind))
|
|
/* At this point, ICS1 cannot be a proper subsequence of
|
|
ICS2. We can get a USER_CONV when we are comparing the
|
|
second standard conversion sequence of two user conversion
|
|
sequences. */
|
|
return false;
|
|
|
|
ics2 = next_conversion (ics2);
|
|
|
|
while (ics2->kind == ck_rvalue
|
|
|| ics2->kind == ck_lvalue)
|
|
ics2 = next_conversion (ics2);
|
|
|
|
if (ics2->kind == ics1->kind
|
|
&& same_type_p (ics2->type, ics1->type)
|
|
&& (ics1->kind == ck_identity
|
|
|| same_type_p (next_conversion (ics2)->type,
|
|
next_conversion (ics1)->type)))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/* Returns nonzero iff DERIVED is derived from BASE. The inputs may
|
|
be any _TYPE nodes. */
|
|
|
|
bool
|
|
is_properly_derived_from (tree derived, tree base)
|
|
{
|
|
if (!CLASS_TYPE_P (derived) || !CLASS_TYPE_P (base))
|
|
return false;
|
|
|
|
/* We only allow proper derivation here. The DERIVED_FROM_P macro
|
|
considers every class derived from itself. */
|
|
return (!same_type_ignoring_top_level_qualifiers_p (derived, base)
|
|
&& DERIVED_FROM_P (base, derived));
|
|
}
|
|
|
|
/* We build the ICS for an implicit object parameter as a pointer
|
|
conversion sequence. However, such a sequence should be compared
|
|
as if it were a reference conversion sequence. If ICS is the
|
|
implicit conversion sequence for an implicit object parameter,
|
|
modify it accordingly. */
|
|
|
|
static void
|
|
maybe_handle_implicit_object (conversion **ics)
|
|
{
|
|
if ((*ics)->this_p)
|
|
{
|
|
/* [over.match.funcs]
|
|
|
|
For non-static member functions, the type of the
|
|
implicit object parameter is "reference to cv X"
|
|
where X is the class of which the function is a
|
|
member and cv is the cv-qualification on the member
|
|
function declaration. */
|
|
conversion *t = *ics;
|
|
tree reference_type;
|
|
|
|
/* The `this' parameter is a pointer to a class type. Make the
|
|
implicit conversion talk about a reference to that same class
|
|
type. */
|
|
reference_type = TREE_TYPE (t->type);
|
|
reference_type = build_reference_type (reference_type);
|
|
|
|
if (t->kind == ck_qual)
|
|
t = next_conversion (t);
|
|
if (t->kind == ck_ptr)
|
|
t = next_conversion (t);
|
|
t = build_identity_conv (TREE_TYPE (t->type), NULL_TREE);
|
|
t = direct_reference_binding (reference_type, t);
|
|
t->this_p = 1;
|
|
t->rvaluedness_matches_p = 0;
|
|
*ics = t;
|
|
}
|
|
}
|
|
|
|
/* If *ICS is a REF_BIND set *ICS to the remainder of the conversion,
|
|
and return the initial reference binding conversion. Otherwise,
|
|
leave *ICS unchanged and return NULL. */
|
|
|
|
static conversion *
|
|
maybe_handle_ref_bind (conversion **ics)
|
|
{
|
|
if ((*ics)->kind == ck_ref_bind)
|
|
{
|
|
conversion *old_ics = *ics;
|
|
*ics = next_conversion (old_ics);
|
|
(*ics)->user_conv_p = old_ics->user_conv_p;
|
|
return old_ics;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Get the expression at the beginning of the conversion chain C. */
|
|
|
|
static tree
|
|
conv_get_original_expr (conversion *c)
|
|
{
|
|
for (; c; c = next_conversion (c))
|
|
if (c->kind == ck_identity || c->kind == ck_ambig || c->kind == ck_aggr)
|
|
return c->u.expr;
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Return a tree representing the number of elements initialized by the
|
|
list-initialization C. The caller must check that C converts to an
|
|
array type. */
|
|
|
|
static tree
|
|
nelts_initialized_by_list_init (conversion *c)
|
|
{
|
|
/* If the array we're converting to has a dimension, we'll use that. */
|
|
if (TYPE_DOMAIN (c->type))
|
|
return array_type_nelts_top (c->type);
|
|
else
|
|
{
|
|
/* Otherwise, we look at how many elements the constructor we're
|
|
initializing from has. */
|
|
tree ctor = conv_get_original_expr (c);
|
|
return size_int (CONSTRUCTOR_NELTS (ctor));
|
|
}
|
|
}
|
|
|
|
/* True iff C is a conversion that binds a reference or a pointer to
|
|
an array of unknown bound. */
|
|
|
|
static inline bool
|
|
conv_binds_to_array_of_unknown_bound (conversion *c)
|
|
{
|
|
/* ck_ref_bind won't have the reference stripped. */
|
|
tree type = non_reference (c->type);
|
|
/* ck_qual won't have the pointer stripped. */
|
|
type = strip_pointer_operator (type);
|
|
return (TREE_CODE (type) == ARRAY_TYPE
|
|
&& TYPE_DOMAIN (type) == NULL_TREE);
|
|
}
|
|
|
|
/* Compare two implicit conversion sequences according to the rules set out in
|
|
[over.ics.rank]. Return values:
|
|
|
|
1: ics1 is better than ics2
|
|
-1: ics2 is better than ics1
|
|
0: ics1 and ics2 are indistinguishable */
|
|
|
|
static int
|
|
compare_ics (conversion *ics1, conversion *ics2)
|
|
{
|
|
tree from_type1;
|
|
tree from_type2;
|
|
tree to_type1;
|
|
tree to_type2;
|
|
tree deref_from_type1 = NULL_TREE;
|
|
tree deref_from_type2 = NULL_TREE;
|
|
tree deref_to_type1 = NULL_TREE;
|
|
tree deref_to_type2 = NULL_TREE;
|
|
conversion_rank rank1, rank2;
|
|
|
|
/* REF_BINDING is nonzero if the result of the conversion sequence
|
|
is a reference type. In that case REF_CONV is the reference
|
|
binding conversion. */
|
|
conversion *ref_conv1;
|
|
conversion *ref_conv2;
|
|
|
|
/* Compare badness before stripping the reference conversion. */
|
|
if (ics1->bad_p > ics2->bad_p)
|
|
return -1;
|
|
else if (ics1->bad_p < ics2->bad_p)
|
|
return 1;
|
|
|
|
/* Handle implicit object parameters. */
|
|
maybe_handle_implicit_object (&ics1);
|
|
maybe_handle_implicit_object (&ics2);
|
|
|
|
/* Handle reference parameters. */
|
|
ref_conv1 = maybe_handle_ref_bind (&ics1);
|
|
ref_conv2 = maybe_handle_ref_bind (&ics2);
|
|
|
|
/* List-initialization sequence L1 is a better conversion sequence than
|
|
list-initialization sequence L2 if L1 converts to
|
|
std::initializer_list<X> for some X and L2 does not. */
|
|
if (ics1->kind == ck_list && ics2->kind != ck_list)
|
|
return 1;
|
|
if (ics2->kind == ck_list && ics1->kind != ck_list)
|
|
return -1;
|
|
|
|
/* [over.ics.rank]
|
|
|
|
When comparing the basic forms of implicit conversion sequences (as
|
|
defined in _over.best.ics_)
|
|
|
|
--a standard conversion sequence (_over.ics.scs_) is a better
|
|
conversion sequence than a user-defined conversion sequence
|
|
or an ellipsis conversion sequence, and
|
|
|
|
--a user-defined conversion sequence (_over.ics.user_) is a
|
|
better conversion sequence than an ellipsis conversion sequence
|
|
(_over.ics.ellipsis_). */
|
|
/* Use BAD_CONVERSION_RANK because we already checked for a badness
|
|
mismatch. If both ICS are bad, we try to make a decision based on
|
|
what would have happened if they'd been good. This is not an
|
|
extension, we'll still give an error when we build up the call; this
|
|
just helps us give a more helpful error message. */
|
|
rank1 = BAD_CONVERSION_RANK (ics1);
|
|
rank2 = BAD_CONVERSION_RANK (ics2);
|
|
|
|
if (rank1 > rank2)
|
|
return -1;
|
|
else if (rank1 < rank2)
|
|
return 1;
|
|
|
|
if (ics1->ellipsis_p)
|
|
/* Both conversions are ellipsis conversions. */
|
|
return 0;
|
|
|
|
/* User-defined conversion sequence U1 is a better conversion sequence
|
|
than another user-defined conversion sequence U2 if they contain the
|
|
same user-defined conversion operator or constructor and if the sec-
|
|
ond standard conversion sequence of U1 is better than the second
|
|
standard conversion sequence of U2. */
|
|
|
|
/* Handle list-conversion with the same code even though it isn't always
|
|
ranked as a user-defined conversion and it doesn't have a second
|
|
standard conversion sequence; it will still have the desired effect.
|
|
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 || ics2->kind == ck_aggr)
|
|
{
|
|
conversion *t1 = strip_standard_conversion (ics1);
|
|
conversion *t2 = strip_standard_conversion (ics2);
|
|
|
|
if (!t1 || !t2 || t1->kind != t2->kind)
|
|
return 0;
|
|
else if (t1->kind == ck_user)
|
|
{
|
|
tree f1 = t1->cand ? t1->cand->fn : t1->type;
|
|
tree f2 = t2->cand ? t2->cand->fn : t2->type;
|
|
if (f1 != f2)
|
|
return 0;
|
|
}
|
|
/* List-initialization sequence L1 is a better conversion sequence than
|
|
list-initialization sequence L2 if
|
|
|
|
-- L1 and L2 convert to arrays of the same element type, and either
|
|
the number of elements n1 initialized by L1 is less than the number
|
|
of elements n2 initialized by L2, or n1=n2 and L2 converts to an array
|
|
of unknown bound and L1 does not. (Added in CWG 1307 and extended by
|
|
P0388R4.) */
|
|
else if (t1->kind == ck_aggr
|
|
&& TREE_CODE (t1->type) == ARRAY_TYPE
|
|
&& TREE_CODE (t2->type) == ARRAY_TYPE
|
|
&& same_type_p (TREE_TYPE (t1->type), TREE_TYPE (t2->type)))
|
|
{
|
|
tree n1 = nelts_initialized_by_list_init (t1);
|
|
tree n2 = nelts_initialized_by_list_init (t2);
|
|
if (tree_int_cst_lt (n1, n2))
|
|
return 1;
|
|
else if (tree_int_cst_lt (n2, n1))
|
|
return -1;
|
|
/* The n1 == n2 case. */
|
|
bool c1 = conv_binds_to_array_of_unknown_bound (t1);
|
|
bool c2 = conv_binds_to_array_of_unknown_bound (t2);
|
|
if (c1 && !c2)
|
|
return -1;
|
|
else if (!c1 && c2)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
/* For ambiguous or aggregate conversions, use the target type as
|
|
a proxy for the conversion function. */
|
|
if (!same_type_ignoring_top_level_qualifiers_p (t1->type, t2->type))
|
|
return 0;
|
|
}
|
|
|
|
/* We can just fall through here, after setting up
|
|
FROM_TYPE1 and FROM_TYPE2. */
|
|
from_type1 = t1->type;
|
|
from_type2 = t2->type;
|
|
}
|
|
else
|
|
{
|
|
conversion *t1;
|
|
conversion *t2;
|
|
|
|
/* We're dealing with two standard conversion sequences.
|
|
|
|
[over.ics.rank]
|
|
|
|
Standard conversion sequence S1 is a better conversion
|
|
sequence than standard conversion sequence S2 if
|
|
|
|
--S1 is a proper subsequence of S2 (comparing the conversion
|
|
sequences in the canonical form defined by _over.ics.scs_,
|
|
excluding any Lvalue Transformation; the identity
|
|
conversion sequence is considered to be a subsequence of
|
|
any non-identity conversion sequence */
|
|
|
|
t1 = ics1;
|
|
while (t1->kind != ck_identity)
|
|
t1 = next_conversion (t1);
|
|
from_type1 = t1->type;
|
|
|
|
t2 = ics2;
|
|
while (t2->kind != ck_identity)
|
|
t2 = next_conversion (t2);
|
|
from_type2 = t2->type;
|
|
}
|
|
|
|
/* One sequence can only be a subsequence of the other if they start with
|
|
the same type. They can start with different types when comparing the
|
|
second standard conversion sequence in two user-defined conversion
|
|
sequences. */
|
|
if (same_type_p (from_type1, from_type2))
|
|
{
|
|
if (is_subseq (ics1, ics2))
|
|
return 1;
|
|
if (is_subseq (ics2, ics1))
|
|
return -1;
|
|
}
|
|
|
|
/* [over.ics.rank]
|
|
|
|
Or, if not that,
|
|
|
|
--the rank of S1 is better than the rank of S2 (by the rules
|
|
defined below):
|
|
|
|
Standard conversion sequences are ordered by their ranks: an Exact
|
|
Match is a better conversion than a Promotion, which is a better
|
|
conversion than a Conversion.
|
|
|
|
Two conversion sequences with the same rank are indistinguishable
|
|
unless one of the following rules applies:
|
|
|
|
--A conversion that does not a convert a pointer, pointer to member,
|
|
or std::nullptr_t to bool is better than one that does.
|
|
|
|
The ICS_STD_RANK automatically handles the pointer-to-bool rule,
|
|
so that we do not have to check it explicitly. */
|
|
if (ics1->rank < ics2->rank)
|
|
return 1;
|
|
else if (ics2->rank < ics1->rank)
|
|
return -1;
|
|
|
|
to_type1 = ics1->type;
|
|
to_type2 = ics2->type;
|
|
|
|
/* A conversion from scalar arithmetic type to complex is worse than a
|
|
conversion between scalar arithmetic types. */
|
|
if (same_type_p (from_type1, from_type2)
|
|
&& ARITHMETIC_TYPE_P (from_type1)
|
|
&& ARITHMETIC_TYPE_P (to_type1)
|
|
&& ARITHMETIC_TYPE_P (to_type2)
|
|
&& ((TREE_CODE (to_type1) == COMPLEX_TYPE)
|
|
!= (TREE_CODE (to_type2) == COMPLEX_TYPE)))
|
|
{
|
|
if (TREE_CODE (to_type1) == COMPLEX_TYPE)
|
|
return -1;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
if (TYPE_PTR_P (from_type1)
|
|
&& TYPE_PTR_P (from_type2)
|
|
&& TYPE_PTR_P (to_type1)
|
|
&& TYPE_PTR_P (to_type2))
|
|
{
|
|
deref_from_type1 = TREE_TYPE (from_type1);
|
|
deref_from_type2 = TREE_TYPE (from_type2);
|
|
deref_to_type1 = TREE_TYPE (to_type1);
|
|
deref_to_type2 = TREE_TYPE (to_type2);
|
|
}
|
|
/* The rules for pointers to members A::* are just like the rules
|
|
for pointers A*, except opposite: if B is derived from A then
|
|
A::* converts to B::*, not vice versa. For that reason, we
|
|
switch the from_ and to_ variables here. */
|
|
else if ((TYPE_PTRDATAMEM_P (from_type1) && TYPE_PTRDATAMEM_P (from_type2)
|
|
&& TYPE_PTRDATAMEM_P (to_type1) && TYPE_PTRDATAMEM_P (to_type2))
|
|
|| (TYPE_PTRMEMFUNC_P (from_type1)
|
|
&& TYPE_PTRMEMFUNC_P (from_type2)
|
|
&& TYPE_PTRMEMFUNC_P (to_type1)
|
|
&& TYPE_PTRMEMFUNC_P (to_type2)))
|
|
{
|
|
deref_to_type1 = TYPE_PTRMEM_CLASS_TYPE (from_type1);
|
|
deref_to_type2 = TYPE_PTRMEM_CLASS_TYPE (from_type2);
|
|
deref_from_type1 = TYPE_PTRMEM_CLASS_TYPE (to_type1);
|
|
deref_from_type2 = TYPE_PTRMEM_CLASS_TYPE (to_type2);
|
|
}
|
|
|
|
if (deref_from_type1 != NULL_TREE
|
|
&& RECORD_OR_UNION_CODE_P (TREE_CODE (deref_from_type1))
|
|
&& RECORD_OR_UNION_CODE_P (TREE_CODE (deref_from_type2)))
|
|
{
|
|
/* This was one of the pointer or pointer-like conversions.
|
|
|
|
[over.ics.rank]
|
|
|
|
--If class B is derived directly or indirectly from class A,
|
|
conversion of B* to A* is better than conversion of B* to
|
|
void*, and conversion of A* to void* is better than
|
|
conversion of B* to void*. */
|
|
if (VOID_TYPE_P (deref_to_type1)
|
|
&& VOID_TYPE_P (deref_to_type2))
|
|
{
|
|
if (is_properly_derived_from (deref_from_type1,
|
|
deref_from_type2))
|
|
return -1;
|
|
else if (is_properly_derived_from (deref_from_type2,
|
|
deref_from_type1))
|
|
return 1;
|
|
}
|
|
else if (VOID_TYPE_P (deref_to_type1)
|
|
|| VOID_TYPE_P (deref_to_type2))
|
|
{
|
|
if (same_type_p (deref_from_type1, deref_from_type2))
|
|
{
|
|
if (VOID_TYPE_P (deref_to_type2))
|
|
{
|
|
if (is_properly_derived_from (deref_from_type1,
|
|
deref_to_type1))
|
|
return 1;
|
|
}
|
|
/* We know that DEREF_TO_TYPE1 is `void' here. */
|
|
else if (is_properly_derived_from (deref_from_type1,
|
|
deref_to_type2))
|
|
return -1;
|
|
}
|
|
}
|
|
else if (RECORD_OR_UNION_CODE_P (TREE_CODE (deref_to_type1))
|
|
&& RECORD_OR_UNION_CODE_P (TREE_CODE (deref_to_type2)))
|
|
{
|
|
/* [over.ics.rank]
|
|
|
|
--If class B is derived directly or indirectly from class A
|
|
and class C is derived directly or indirectly from B,
|
|
|
|
--conversion of C* to B* is better than conversion of C* to
|
|
A*,
|
|
|
|
--conversion of B* to A* is better than conversion of C* to
|
|
A* */
|
|
if (same_type_p (deref_from_type1, deref_from_type2))
|
|
{
|
|
if (is_properly_derived_from (deref_to_type1,
|
|
deref_to_type2))
|
|
return 1;
|
|
else if (is_properly_derived_from (deref_to_type2,
|
|
deref_to_type1))
|
|
return -1;
|
|
}
|
|
else if (same_type_p (deref_to_type1, deref_to_type2))
|
|
{
|
|
if (is_properly_derived_from (deref_from_type2,
|
|
deref_from_type1))
|
|
return 1;
|
|
else if (is_properly_derived_from (deref_from_type1,
|
|
deref_from_type2))
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
else if (CLASS_TYPE_P (non_reference (from_type1))
|
|
&& same_type_p (from_type1, from_type2))
|
|
{
|
|
tree from = non_reference (from_type1);
|
|
|
|
/* [over.ics.rank]
|
|
|
|
--binding of an expression of type C to a reference of type
|
|
B& is better than binding an expression of type C to a
|
|
reference of type A&
|
|
|
|
--conversion of C to B is better than conversion of C to A, */
|
|
if (is_properly_derived_from (from, to_type1)
|
|
&& is_properly_derived_from (from, to_type2))
|
|
{
|
|
if (is_properly_derived_from (to_type1, to_type2))
|
|
return 1;
|
|
else if (is_properly_derived_from (to_type2, to_type1))
|
|
return -1;
|
|
}
|
|
}
|
|
else if (CLASS_TYPE_P (non_reference (to_type1))
|
|
&& same_type_p (to_type1, to_type2))
|
|
{
|
|
tree to = non_reference (to_type1);
|
|
|
|
/* [over.ics.rank]
|
|
|
|
--binding of an expression of type B to a reference of type
|
|
A& is better than binding an expression of type C to a
|
|
reference of type A&,
|
|
|
|
--conversion of B to A is better than conversion of C to A */
|
|
if (is_properly_derived_from (from_type1, to)
|
|
&& is_properly_derived_from (from_type2, to))
|
|
{
|
|
if (is_properly_derived_from (from_type2, from_type1))
|
|
return 1;
|
|
else if (is_properly_derived_from (from_type1, from_type2))
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* [over.ics.rank]
|
|
|
|
--S1 and S2 differ only in their qualification conversion and yield
|
|
similar types T1 and T2 (_conv.qual_), respectively, and the cv-
|
|
qualification signature of type T1 is a proper subset of the cv-
|
|
qualification signature of type T2 */
|
|
if (ics1->kind == ck_qual
|
|
&& ics2->kind == ck_qual
|
|
&& same_type_p (from_type1, from_type2))
|
|
{
|
|
int result = comp_cv_qual_signature (to_type1, to_type2);
|
|
if (result != 0)
|
|
return result;
|
|
}
|
|
|
|
/* [over.ics.rank]
|
|
|
|
--S1 and S2 are reference bindings (_dcl.init.ref_) and neither refers
|
|
to an implicit object parameter of a non-static member function
|
|
declared without a ref-qualifier, and either S1 binds an lvalue
|
|
reference to an lvalue and S2 binds an rvalue reference or S1 binds an
|
|
rvalue reference to an rvalue and S2 binds an lvalue reference (C++0x
|
|
draft standard, 13.3.3.2)
|
|
|
|
--S1 and S2 are reference bindings (_dcl.init.ref_), and the
|
|
types to which the references refer are the same type except for
|
|
top-level cv-qualifiers, and the type to which the reference
|
|
initialized by S2 refers is more cv-qualified than the type to
|
|
which the reference initialized by S1 refers.
|
|
|
|
DR 1328 [over.match.best]: the context is an initialization by
|
|
conversion function for direct reference binding (13.3.1.6) of a
|
|
reference to function type, the return type of F1 is the same kind of
|
|
reference (i.e. lvalue or rvalue) as the reference being initialized,
|
|
and the return type of F2 is not. */
|
|
|
|
if (ref_conv1 && ref_conv2)
|
|
{
|
|
if (!ref_conv1->this_p && !ref_conv2->this_p
|
|
&& (ref_conv1->rvaluedness_matches_p
|
|
!= ref_conv2->rvaluedness_matches_p)
|
|
&& (same_type_p (ref_conv1->type, ref_conv2->type)
|
|
|| (TYPE_REF_IS_RVALUE (ref_conv1->type)
|
|
!= TYPE_REF_IS_RVALUE (ref_conv2->type))))
|
|
{
|
|
if (ref_conv1->bad_p
|
|
&& !same_type_p (TREE_TYPE (ref_conv1->type),
|
|
TREE_TYPE (ref_conv2->type)))
|
|
/* Don't prefer a bad conversion that drops cv-quals to a bad
|
|
conversion with the wrong rvalueness. */
|
|
return 0;
|
|
return (ref_conv1->rvaluedness_matches_p
|
|
- ref_conv2->rvaluedness_matches_p);
|
|
}
|
|
|
|
if (same_type_ignoring_top_level_qualifiers_p (to_type1, to_type2))
|
|
{
|
|
/* Per P0388R4:
|
|
|
|
void f (int(&)[]), // (1)
|
|
f (int(&)[1]), // (2)
|
|
f (int*); // (3)
|
|
|
|
(2) is better than (1), but (3) should be equal to (1) and to
|
|
(2). For that reason we don't use ck_qual for (1) which would
|
|
give it the cr_exact rank while (3) remains ck_identity.
|
|
Therefore we compare (1) and (2) here. For (1) we'll have
|
|
|
|
ck_ref_bind <- ck_identity
|
|
int[] & int[1]
|
|
|
|
so to handle this we must look at ref_conv. */
|
|
bool c1 = conv_binds_to_array_of_unknown_bound (ref_conv1);
|
|
bool c2 = conv_binds_to_array_of_unknown_bound (ref_conv2);
|
|
if (c1 && !c2)
|
|
return -1;
|
|
else if (!c1 && c2)
|
|
return 1;
|
|
|
|
int q1 = cp_type_quals (TREE_TYPE (ref_conv1->type));
|
|
int q2 = cp_type_quals (TREE_TYPE (ref_conv2->type));
|
|
if (ref_conv1->bad_p)
|
|
{
|
|
/* Prefer the one that drops fewer cv-quals. */
|
|
tree ftype = next_conversion (ref_conv1)->type;
|
|
int fquals = cp_type_quals (ftype);
|
|
q1 ^= fquals;
|
|
q2 ^= fquals;
|
|
}
|
|
return comp_cv_qualification (q2, q1);
|
|
}
|
|
}
|
|
|
|
/* [over.ics.rank]
|
|
|
|
Per CWG 1601:
|
|
-- A conversion that promotes an enumeration whose underlying type
|
|
is fixed to its underlying type is better than one that promotes to
|
|
the promoted underlying type, if the two are different. */
|
|
if (ics1->rank == cr_promotion
|
|
&& ics2->rank == cr_promotion
|
|
&& UNSCOPED_ENUM_P (from_type1)
|
|
&& ENUM_FIXED_UNDERLYING_TYPE_P (from_type1)
|
|
&& same_type_p (from_type1, from_type2))
|
|
{
|
|
tree utype = ENUM_UNDERLYING_TYPE (from_type1);
|
|
tree prom = type_promotes_to (from_type1);
|
|
if (!same_type_p (utype, prom))
|
|
{
|
|
if (same_type_p (to_type1, utype)
|
|
&& same_type_p (to_type2, prom))
|
|
return 1;
|
|
else if (same_type_p (to_type2, utype)
|
|
&& same_type_p (to_type1, prom))
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Neither conversion sequence is better than the other. */
|
|
return 0;
|
|
}
|
|
|
|
/* The source type for this standard conversion sequence. */
|
|
|
|
static tree
|
|
source_type (conversion *t)
|
|
{
|
|
return strip_standard_conversion (t)->type;
|
|
}
|
|
|
|
/* Note a warning about preferring WINNER to LOSER. We do this by storing
|
|
a pointer to LOSER and re-running joust to produce the warning if WINNER
|
|
is actually used. */
|
|
|
|
static void
|
|
add_warning (struct z_candidate *winner, struct z_candidate *loser)
|
|
{
|
|
candidate_warning *cw = (candidate_warning *)
|
|
conversion_obstack_alloc (sizeof (candidate_warning));
|
|
cw->loser = loser;
|
|
cw->next = winner->warnings;
|
|
winner->warnings = cw;
|
|
}
|
|
|
|
/* CAND is a constructor candidate in joust in C++17 and up. If it copies a
|
|
prvalue returned from a conversion function, replace CAND with the candidate
|
|
for the conversion and return true. Otherwise, return false. */
|
|
|
|
static bool
|
|
joust_maybe_elide_copy (z_candidate *&cand)
|
|
{
|
|
tree fn = cand->fn;
|
|
if (!DECL_COPY_CONSTRUCTOR_P (fn) && !DECL_MOVE_CONSTRUCTOR_P (fn))
|
|
return false;
|
|
conversion *conv = cand->convs[0];
|
|
gcc_checking_assert (conv->kind == ck_ref_bind);
|
|
conv = next_conversion (conv);
|
|
if (conv->kind == ck_user && !TYPE_REF_P (conv->type))
|
|
{
|
|
gcc_checking_assert (same_type_ignoring_top_level_qualifiers_p
|
|
(conv->type, DECL_CONTEXT (fn)));
|
|
z_candidate *uc = conv->cand;
|
|
if (DECL_CONV_FN_P (uc->fn))
|
|
{
|
|
cand = uc;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* True if the defining declarations of the two candidates have equivalent
|
|
parameters. */
|
|
|
|
static bool
|
|
cand_parms_match (z_candidate *c1, z_candidate *c2)
|
|
{
|
|
tree fn1 = c1->fn;
|
|
tree fn2 = c2->fn;
|
|
if (fn1 == fn2)
|
|
return true;
|
|
if (identifier_p (fn1) || identifier_p (fn2))
|
|
return false;
|
|
/* We don't look at c1->template_decl because that's only set for primary
|
|
templates, not e.g. non-template member functions of class templates. */
|
|
tree t1 = most_general_template (fn1);
|
|
tree t2 = most_general_template (fn2);
|
|
if (t1 || t2)
|
|
{
|
|
if (!t1 || !t2)
|
|
return false;
|
|
if (t1 == t2)
|
|
return true;
|
|
fn1 = DECL_TEMPLATE_RESULT (t1);
|
|
fn2 = DECL_TEMPLATE_RESULT (t2);
|
|
}
|
|
tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn1));
|
|
tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (fn2));
|
|
if (DECL_FUNCTION_MEMBER_P (fn1)
|
|
&& DECL_FUNCTION_MEMBER_P (fn2)
|
|
&& (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn1)
|
|
!= DECL_NONSTATIC_MEMBER_FUNCTION_P (fn2)))
|
|
{
|
|
/* Ignore 'this' when comparing the parameters of a static member
|
|
function with those of a non-static one. */
|
|
parms1 = skip_artificial_parms_for (fn1, parms1);
|
|
parms2 = skip_artificial_parms_for (fn2, parms2);
|
|
}
|
|
return compparms (parms1, parms2);
|
|
}
|
|
|
|
/* Compare two candidates for overloading as described in
|
|
[over.match.best]. Return values:
|
|
|
|
1: cand1 is better than cand2
|
|
-1: cand2 is better than cand1
|
|
0: cand1 and cand2 are indistinguishable */
|
|
|
|
static int
|
|
joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
|
|
tsubst_flags_t complain)
|
|
{
|
|
int winner = 0;
|
|
int off1 = 0, off2 = 0;
|
|
size_t i;
|
|
size_t len;
|
|
|
|
/* Candidates that involve bad conversions are always worse than those
|
|
that don't. */
|
|
if (cand1->viable > cand2->viable)
|
|
return 1;
|
|
if (cand1->viable < cand2->viable)
|
|
return -1;
|
|
|
|
/* If we have two pseudo-candidates for conversions to the same type,
|
|
or two candidates for the same function, arbitrarily pick one. */
|
|
if (cand1->fn == cand2->fn
|
|
&& cand1->reversed () == cand2->reversed ()
|
|
&& (IS_TYPE_OR_DECL_P (cand1->fn)))
|
|
return 1;
|
|
|
|
/* Prefer a non-deleted function over an implicitly deleted move
|
|
constructor or assignment operator. This differs slightly from the
|
|
wording for issue 1402 (which says the move op is ignored by overload
|
|
resolution), but this way produces better error messages. */
|
|
if (TREE_CODE (cand1->fn) == FUNCTION_DECL
|
|
&& TREE_CODE (cand2->fn) == FUNCTION_DECL
|
|
&& DECL_DELETED_FN (cand1->fn) != DECL_DELETED_FN (cand2->fn))
|
|
{
|
|
if (DECL_DELETED_FN (cand1->fn) && DECL_DEFAULTED_FN (cand1->fn)
|
|
&& move_fn_p (cand1->fn))
|
|
return -1;
|
|
if (DECL_DELETED_FN (cand2->fn) && DECL_DEFAULTED_FN (cand2->fn)
|
|
&& move_fn_p (cand2->fn))
|
|
return 1;
|
|
}
|
|
|
|
/* a viable function F1
|
|
is defined to be a better function than another viable function F2 if
|
|
for all arguments i, ICSi(F1) is not a worse conversion sequence than
|
|
ICSi(F2), and then */
|
|
|
|
/* for some argument j, ICSj(F1) is a better conversion sequence than
|
|
ICSj(F2) */
|
|
|
|
/* For comparing static and non-static member functions, we ignore
|
|
the implicit object parameter of the non-static function. The
|
|
standard says to pretend that the static function has an object
|
|
parm, but that won't work with operator overloading. */
|
|
len = cand1->num_convs;
|
|
if (len != cand2->num_convs)
|
|
{
|
|
int static_1 = DECL_STATIC_FUNCTION_P (cand1->fn);
|
|
int static_2 = DECL_STATIC_FUNCTION_P (cand2->fn);
|
|
|
|
if (DECL_CONSTRUCTOR_P (cand1->fn)
|
|
&& is_list_ctor (cand1->fn) != is_list_ctor (cand2->fn))
|
|
/* We're comparing a near-match list constructor and a near-match
|
|
non-list constructor. Just treat them as unordered. */
|
|
return 0;
|
|
|
|
gcc_assert (static_1 != static_2);
|
|
|
|
if (static_1)
|
|
off2 = 1;
|
|
else
|
|
{
|
|
off1 = 1;
|
|
--len;
|
|
}
|
|
}
|
|
|
|
/* Handle C++17 copy elision in [over.match.ctor] (direct-init) context. The
|
|
standard currently says that only constructors are candidates, but if one
|
|
copies a prvalue returned by a conversion function we want to treat the
|
|
conversion as the candidate instead.
|
|
|
|
Clang does something similar, as discussed at
|
|
http://lists.isocpp.org/core/2017/10/3166.php
|
|
http://lists.isocpp.org/core/2019/03/5721.php */
|
|
int elided_tiebreaker = 0;
|
|
if (len == 1 && cxx_dialect >= cxx17
|
|
&& DECL_P (cand1->fn)
|
|
&& DECL_COMPLETE_CONSTRUCTOR_P (cand1->fn)
|
|
&& !(cand1->flags & LOOKUP_ONLYCONVERTING))
|
|
{
|
|
bool elided1 = joust_maybe_elide_copy (cand1);
|
|
bool elided2 = joust_maybe_elide_copy (cand2);
|
|
/* As a tiebreaker below we will prefer a constructor to a conversion
|
|
operator exposed this way. */
|
|
elided_tiebreaker = elided2 - elided1;
|
|
}
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
conversion *t1 = cand1->convs[i + off1];
|
|
conversion *t2 = cand2->convs[i + off2];
|
|
int comp = compare_ics (t1, t2);
|
|
|
|
if (comp != 0)
|
|
{
|
|
if ((complain & tf_warning)
|
|
&& warn_sign_promo
|
|
&& (CONVERSION_RANK (t1) + CONVERSION_RANK (t2)
|
|
== cr_std + cr_promotion)
|
|
&& t1->kind == ck_std
|
|
&& t2->kind == ck_std
|
|
&& TREE_CODE (t1->type) == INTEGER_TYPE
|
|
&& TREE_CODE (t2->type) == INTEGER_TYPE
|
|
&& (TYPE_PRECISION (t1->type)
|
|
== TYPE_PRECISION (t2->type))
|
|
&& (TYPE_UNSIGNED (next_conversion (t1)->type)
|
|
|| (TREE_CODE (next_conversion (t1)->type)
|
|
== ENUMERAL_TYPE)))
|
|
{
|
|
tree type = next_conversion (t1)->type;
|
|
tree type1, type2;
|
|
struct z_candidate *w, *l;
|
|
if (comp > 0)
|
|
type1 = t1->type, type2 = t2->type,
|
|
w = cand1, l = cand2;
|
|
else
|
|
type1 = t2->type, type2 = t1->type,
|
|
w = cand2, l = cand1;
|
|
|
|
if (warn)
|
|
{
|
|
warning (OPT_Wsign_promo, "passing %qT chooses %qT over %qT",
|
|
type, type1, type2);
|
|
warning (OPT_Wsign_promo, " in call to %qD", w->fn);
|
|
}
|
|
else
|
|
add_warning (w, l);
|
|
}
|
|
|
|
if (winner && comp != winner)
|
|
{
|
|
/* Ambiguity between normal and reversed comparison operators
|
|
with the same parameter types; prefer the normal one. */
|
|
if ((cand1->reversed () != cand2->reversed ())
|
|
&& cand_parms_match (cand1, cand2))
|
|
return cand1->reversed () ? -1 : 1;
|
|
|
|
winner = 0;
|
|
goto tweak;
|
|
}
|
|
winner = comp;
|
|
}
|
|
}
|
|
|
|
/* warn about confusing overload resolution for user-defined conversions,
|
|
either between a constructor and a conversion op, or between two
|
|
conversion ops. */
|
|
if ((complain & tf_warning)
|
|
/* In C++17, the constructor might have been elided, which means that
|
|
an originally null ->second_conv could become non-null. */
|
|
&& winner && warn_conversion && cand1->second_conv && cand2->second_conv
|
|
&& (!DECL_CONSTRUCTOR_P (cand1->fn) || !DECL_CONSTRUCTOR_P (cand2->fn))
|
|
&& winner != compare_ics (cand1->second_conv, cand2->second_conv))
|
|
{
|
|
struct z_candidate *w, *l;
|
|
bool give_warning = false;
|
|
|
|
if (winner == 1)
|
|
w = cand1, l = cand2;
|
|
else
|
|
w = cand2, l = cand1;
|
|
|
|
/* We don't want to complain about `X::operator T1 ()'
|
|
beating `X::operator T2 () const', when T2 is a no less
|
|
cv-qualified version of T1. */
|
|
if (DECL_CONTEXT (w->fn) == DECL_CONTEXT (l->fn)
|
|
&& !DECL_CONSTRUCTOR_P (w->fn) && !DECL_CONSTRUCTOR_P (l->fn))
|
|
{
|
|
tree t = TREE_TYPE (TREE_TYPE (l->fn));
|
|
tree f = TREE_TYPE (TREE_TYPE (w->fn));
|
|
|
|
if (TREE_CODE (t) == TREE_CODE (f) && INDIRECT_TYPE_P (t))
|
|
{
|
|
t = TREE_TYPE (t);
|
|
f = TREE_TYPE (f);
|
|
}
|
|
if (!comp_ptr_ttypes (t, f))
|
|
give_warning = true;
|
|
}
|
|
else
|
|
give_warning = true;
|
|
|
|
if (!give_warning)
|
|
/*NOP*/;
|
|
else if (warn)
|
|
{
|
|
tree source = source_type (w->convs[0]);
|
|
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))
|
|
{
|
|
inform (input_location, " because conversion sequence "
|
|
"for the argument is better");
|
|
}
|
|
}
|
|
else
|
|
add_warning (w, l);
|
|
}
|
|
|
|
if (winner)
|
|
return winner;
|
|
|
|
/* Put this tiebreaker first, so that we don't try to look at second_conv of
|
|
a constructor candidate that doesn't have one. */
|
|
if (elided_tiebreaker)
|
|
return elided_tiebreaker;
|
|
|
|
/* DR 495 moved this tiebreaker above the template ones. */
|
|
/* or, if not that,
|
|
the context is an initialization by user-defined conversion (see
|
|
_dcl.init_ and _over.match.user_) and the standard conversion
|
|
sequence from the return type of F1 to the destination type (i.e.,
|
|
the type of the entity being initialized) is a better conversion
|
|
sequence than the standard conversion sequence from the return type
|
|
of F2 to the destination type. */
|
|
|
|
if (cand1->second_conv)
|
|
{
|
|
winner = compare_ics (cand1->second_conv, cand2->second_conv);
|
|
if (winner)
|
|
return winner;
|
|
}
|
|
|
|
/* or, if not that,
|
|
F1 is a non-template function and F2 is a template function
|
|
specialization. */
|
|
|
|
if (!cand1->template_decl && cand2->template_decl)
|
|
return 1;
|
|
else if (cand1->template_decl && !cand2->template_decl)
|
|
return -1;
|
|
|
|
/* or, if not that,
|
|
F1 and F2 are template functions and the function template for F1 is
|
|
more specialized than the template for F2 according to the partial
|
|
ordering rules. */
|
|
|
|
if (cand1->template_decl && cand2->template_decl)
|
|
{
|
|
winner = more_specialized_fn
|
|
(TI_TEMPLATE (cand1->template_decl),
|
|
TI_TEMPLATE (cand2->template_decl),
|
|
/* [temp.func.order]: The presence of unused ellipsis and default
|
|
arguments has no effect on the partial ordering of function
|
|
templates. add_function_candidate() will not have
|
|
counted the "this" argument for constructors. */
|
|
cand1->num_convs + DECL_CONSTRUCTOR_P (cand1->fn));
|
|
if (winner)
|
|
return winner;
|
|
}
|
|
|
|
/* Concepts: F1 and F2 are non-template functions with the same
|
|
parameter-type-lists, and F1 is more constrained than F2 according to the
|
|
partial ordering of constraints described in 13.5.4. */
|
|
|
|
if (flag_concepts && DECL_P (cand1->fn) && DECL_P (cand2->fn)
|
|
&& !cand1->template_decl && !cand2->template_decl
|
|
&& cand_parms_match (cand1, cand2))
|
|
{
|
|
winner = more_constrained (cand1->fn, cand2->fn);
|
|
if (winner)
|
|
return winner;
|
|
}
|
|
|
|
/* F2 is a rewritten candidate (12.4.1.2) and F1 is not, or F1 and F2 are
|
|
rewritten candidates, and F2 is a synthesized candidate with reversed
|
|
order of parameters and F1 is not. */
|
|
if (cand1->rewritten ())
|
|
{
|
|
if (!cand2->rewritten ())
|
|
return -1;
|
|
if (!cand1->reversed () && cand2->reversed ())
|
|
return 1;
|
|
if (cand1->reversed () && !cand2->reversed ())
|
|
return -1;
|
|
}
|
|
else if (cand2->rewritten ())
|
|
return 1;
|
|
|
|
/* F1 is generated from a deduction-guide (13.3.1.8) and F2 is not */
|
|
if (deduction_guide_p (cand1->fn))
|
|
{
|
|
gcc_assert (deduction_guide_p (cand2->fn));
|
|
/* We distinguish between candidates from an explicit deduction guide and
|
|
candidates built from a constructor based on DECL_ARTIFICIAL. */
|
|
int art1 = DECL_ARTIFICIAL (cand1->fn);
|
|
int art2 = DECL_ARTIFICIAL (cand2->fn);
|
|
if (art1 != art2)
|
|
return art2 - art1;
|
|
|
|
if (art1)
|
|
{
|
|
/* Prefer the special copy guide over a declared copy/move
|
|
constructor. */
|
|
if (copy_guide_p (cand1->fn))
|
|
return 1;
|
|
if (copy_guide_p (cand2->fn))
|
|
return -1;
|
|
|
|
/* Prefer a candidate generated from a non-template constructor. */
|
|
int tg1 = template_guide_p (cand1->fn);
|
|
int tg2 = template_guide_p (cand2->fn);
|
|
if (tg1 != tg2)
|
|
return tg2 - tg1;
|
|
}
|
|
}
|
|
|
|
/* F1 is a member of a class D, F2 is a member of a base class B of D, and
|
|
for all arguments the corresponding parameters of F1 and F2 have the same
|
|
type (CWG 2273/2277). */
|
|
if (DECL_P (cand1->fn) && DECL_CLASS_SCOPE_P (cand1->fn)
|
|
&& !DECL_CONV_FN_P (cand1->fn)
|
|
&& DECL_P (cand2->fn) && DECL_CLASS_SCOPE_P (cand2->fn)
|
|
&& !DECL_CONV_FN_P (cand2->fn))
|
|
{
|
|
tree base1 = DECL_CONTEXT (strip_inheriting_ctors (cand1->fn));
|
|
tree base2 = DECL_CONTEXT (strip_inheriting_ctors (cand2->fn));
|
|
|
|
bool used1 = false;
|
|
bool used2 = false;
|
|
if (base1 == base2)
|
|
/* No difference. */;
|
|
else if (DERIVED_FROM_P (base1, base2))
|
|
used1 = true;
|
|
else if (DERIVED_FROM_P (base2, base1))
|
|
used2 = true;
|
|
|
|
if (int diff = used2 - used1)
|
|
{
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
conversion *t1 = cand1->convs[i + off1];
|
|
conversion *t2 = cand2->convs[i + off2];
|
|
if (!same_type_p (t1->type, t2->type))
|
|
break;
|
|
}
|
|
if (i == len)
|
|
return diff;
|
|
}
|
|
}
|
|
|
|
/* Check whether we can discard a builtin candidate, either because we
|
|
have two identical ones or matching builtin and non-builtin candidates.
|
|
|
|
(Pedantically in the latter case the builtin which matched the user
|
|
function should not be added to the overload set, but we spot it here.
|
|
|
|
[over.match.oper]
|
|
... the builtin candidates include ...
|
|
- do not have the same parameter type list as any non-template
|
|
non-member candidate. */
|
|
|
|
if (identifier_p (cand1->fn) || identifier_p (cand2->fn))
|
|
{
|
|
for (i = 0; i < len; ++i)
|
|
if (!same_type_p (cand1->convs[i]->type,
|
|
cand2->convs[i]->type))
|
|
break;
|
|
if (i == cand1->num_convs)
|
|
{
|
|
if (cand1->fn == cand2->fn)
|
|
/* Two built-in candidates; arbitrarily pick one. */
|
|
return 1;
|
|
else if (identifier_p (cand1->fn))
|
|
/* cand1 is built-in; prefer cand2. */
|
|
return -1;
|
|
else
|
|
/* cand2 is built-in; prefer cand1. */
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* For candidates of a multi-versioned function, make the version with
|
|
the highest priority win. This version will be checked for dispatching
|
|
first. If this version can be inlined into the caller, the front-end
|
|
will simply make a direct call to this function. */
|
|
|
|
if (TREE_CODE (cand1->fn) == FUNCTION_DECL
|
|
&& DECL_FUNCTION_VERSIONED (cand1->fn)
|
|
&& TREE_CODE (cand2->fn) == FUNCTION_DECL
|
|
&& DECL_FUNCTION_VERSIONED (cand2->fn))
|
|
{
|
|
tree f1 = TREE_TYPE (cand1->fn);
|
|
tree f2 = TREE_TYPE (cand2->fn);
|
|
tree p1 = TYPE_ARG_TYPES (f1);
|
|
tree p2 = TYPE_ARG_TYPES (f2);
|
|
|
|
/* Check if cand1->fn and cand2->fn are versions of the same function. It
|
|
is possible that cand1->fn and cand2->fn are function versions but of
|
|
different functions. Check types to see if they are versions of the same
|
|
function. */
|
|
if (compparms (p1, p2)
|
|
&& same_type_p (TREE_TYPE (f1), TREE_TYPE (f2)))
|
|
{
|
|
/* Always make the version with the higher priority, more
|
|
specialized, win. */
|
|
gcc_assert (targetm.compare_version_priority);
|
|
if (targetm.compare_version_priority (cand1->fn, cand2->fn) >= 0)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* If the two function declarations represent the same function (this can
|
|
happen with declarations in multiple scopes and arg-dependent lookup),
|
|
arbitrarily choose one. But first make sure the default args we're
|
|
using match. */
|
|
if (DECL_P (cand1->fn) && DECL_P (cand2->fn)
|
|
&& equal_functions (cand1->fn, cand2->fn))
|
|
{
|
|
tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (cand1->fn));
|
|
tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (cand2->fn));
|
|
|
|
gcc_assert (!DECL_CONSTRUCTOR_P (cand1->fn));
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
/* Don't crash if the fn is variadic. */
|
|
if (!parms1)
|
|
break;
|
|
parms1 = TREE_CHAIN (parms1);
|
|
parms2 = TREE_CHAIN (parms2);
|
|
}
|
|
|
|
if (off1)
|
|
parms1 = TREE_CHAIN (parms1);
|
|
else if (off2)
|
|
parms2 = TREE_CHAIN (parms2);
|
|
|
|
for (; parms1; ++i)
|
|
{
|
|
if (!cp_tree_equal (TREE_PURPOSE (parms1),
|
|
TREE_PURPOSE (parms2)))
|
|
{
|
|
if (warn)
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
auto_diagnostic_group d;
|
|
if (permerror (input_location,
|
|
"default argument mismatch in "
|
|
"overload resolution"))
|
|
{
|
|
inform (DECL_SOURCE_LOCATION (cand1->fn),
|
|
" candidate 1: %q#F", cand1->fn);
|
|
inform (DECL_SOURCE_LOCATION (cand2->fn),
|
|
" candidate 2: %q#F", cand2->fn);
|
|
}
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
else
|
|
add_warning (cand1, cand2);
|
|
break;
|
|
}
|
|
parms1 = TREE_CHAIN (parms1);
|
|
parms2 = TREE_CHAIN (parms2);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
tweak:
|
|
|
|
/* 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))
|
|
{
|
|
conversion_rank rank1 = cr_identity, rank2 = cr_identity;
|
|
struct z_candidate *w = 0, *l = 0;
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
if (CONVERSION_RANK (cand1->convs[i+off1]) > rank1)
|
|
rank1 = CONVERSION_RANK (cand1->convs[i+off1]);
|
|
if (CONVERSION_RANK (cand2->convs[i + off2]) > rank2)
|
|
rank2 = CONVERSION_RANK (cand2->convs[i + off2]);
|
|
}
|
|
if (rank1 < rank2)
|
|
winner = 1, w = cand1, l = cand2;
|
|
if (rank1 > rank2)
|
|
winner = -1, w = cand2, l = cand1;
|
|
if (winner)
|
|
{
|
|
/* Don't choose a deleted function over ambiguity. */
|
|
if (DECL_P (w->fn) && DECL_DELETED_FN (w->fn))
|
|
return 0;
|
|
if (warn)
|
|
{
|
|
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, N_("candidate 1:"), w);
|
|
print_z_candidate (input_location, N_("candidate 2:"), l);
|
|
}
|
|
}
|
|
else
|
|
add_warning (w, l);
|
|
return winner;
|
|
}
|
|
}
|
|
|
|
gcc_assert (!winner);
|
|
return 0;
|
|
}
|
|
|
|
/* Given a list of candidates for overloading, find the best one, if any.
|
|
This algorithm has a worst case of O(2n) (winner is last), and a best
|
|
case of O(n/2) (totally ambiguous); much better than a sorting
|
|
algorithm. */
|
|
|
|
static struct z_candidate *
|
|
tourney (struct z_candidate *candidates, tsubst_flags_t complain)
|
|
{
|
|
struct z_candidate *champ = candidates, *challenger;
|
|
int fate;
|
|
int champ_compared_to_predecessor = 0;
|
|
|
|
/* Walk through the list once, comparing each current champ to the next
|
|
candidate, knocking out a candidate or two with each comparison. */
|
|
|
|
for (challenger = champ->next; challenger; )
|
|
{
|
|
fate = joust (champ, challenger, 0, complain);
|
|
if (fate == 1)
|
|
challenger = challenger->next;
|
|
else
|
|
{
|
|
if (fate == 0)
|
|
{
|
|
champ = challenger->next;
|
|
if (champ == 0)
|
|
return NULL;
|
|
champ_compared_to_predecessor = 0;
|
|
}
|
|
else
|
|
{
|
|
champ = challenger;
|
|
champ_compared_to_predecessor = 1;
|
|
}
|
|
|
|
challenger = champ->next;
|
|
}
|
|
}
|
|
|
|
/* Make sure the champ is better than all the candidates it hasn't yet
|
|
been compared to. */
|
|
|
|
for (challenger = candidates;
|
|
challenger != champ
|
|
&& !(champ_compared_to_predecessor && challenger->next == champ);
|
|
challenger = challenger->next)
|
|
{
|
|
fate = joust (champ, challenger, 0, complain);
|
|
if (fate != 1)
|
|
return NULL;
|
|
}
|
|
|
|
return champ;
|
|
}
|
|
|
|
/* Returns nonzero if things of type FROM can be converted to TO. */
|
|
|
|
bool
|
|
can_convert (tree to, tree from, tsubst_flags_t complain)
|
|
{
|
|
tree arg = NULL_TREE;
|
|
/* implicit_conversion only considers user-defined conversions
|
|
if it has an expression for the call argument list. */
|
|
if (CLASS_TYPE_P (from) || CLASS_TYPE_P (to))
|
|
arg = build_stub_object (from);
|
|
return can_convert_arg (to, from, arg, LOOKUP_IMPLICIT, complain);
|
|
}
|
|
|
|
/* Returns nonzero if things of type FROM can be converted to TO with a
|
|
standard conversion. */
|
|
|
|
bool
|
|
can_convert_standard (tree to, tree from, tsubst_flags_t complain)
|
|
{
|
|
return can_convert_arg (to, from, NULL_TREE, LOOKUP_IMPLICIT, complain);
|
|
}
|
|
|
|
/* Returns nonzero if ARG (of type FROM) can be converted to TO. */
|
|
|
|
bool
|
|
can_convert_arg (tree to, tree from, tree arg, int flags,
|
|
tsubst_flags_t complain)
|
|
{
|
|
conversion *t;
|
|
void *p;
|
|
bool ok_p;
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
p = conversion_obstack_alloc (0);
|
|
/* We want to discard any access checks done for this test,
|
|
as we might not be in the appropriate access context and
|
|
we'll do the check again when we actually perform the
|
|
conversion. */
|
|
push_deferring_access_checks (dk_deferred);
|
|
|
|
t = implicit_conversion (to, from, arg, /*c_cast_p=*/false,
|
|
flags, complain);
|
|
ok_p = (t && !t->bad_p);
|
|
|
|
/* Discard the access checks now. */
|
|
pop_deferring_access_checks ();
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
return ok_p;
|
|
}
|
|
|
|
/* Like can_convert_arg, but allows dubious conversions as well. */
|
|
|
|
bool
|
|
can_convert_arg_bad (tree to, tree from, tree arg, int flags,
|
|
tsubst_flags_t complain)
|
|
{
|
|
conversion *t;
|
|
void *p;
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
p = conversion_obstack_alloc (0);
|
|
/* Try to perform the conversion. */
|
|
t = implicit_conversion (to, from, arg, /*c_cast_p=*/false,
|
|
flags, complain);
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
return t != NULL;
|
|
}
|
|
|
|
/* Return an IMPLICIT_CONV_EXPR from EXPR to TYPE with bits set from overload
|
|
resolution FLAGS. */
|
|
|
|
tree
|
|
build_implicit_conv_flags (tree type, tree expr, int flags)
|
|
{
|
|
/* In a template, we are only concerned about determining the
|
|
type of non-dependent expressions, so we do not have to
|
|
perform the actual conversion. But for initializers, we
|
|
need to be able to perform it at instantiation
|
|
(or instantiate_non_dependent_expr) time. */
|
|
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;
|
|
return expr;
|
|
}
|
|
|
|
/* Convert EXPR to TYPE. Return the converted expression.
|
|
|
|
Note that we allow bad conversions here because by the time we get to
|
|
this point we are committed to doing the conversion. If we end up
|
|
doing a bad conversion, convert_like will complain. */
|
|
|
|
tree
|
|
perform_implicit_conversion_flags (tree type, tree expr,
|
|
tsubst_flags_t complain, int flags)
|
|
{
|
|
conversion *conv;
|
|
void *p;
|
|
location_t loc = cp_expr_loc_or_input_loc (expr);
|
|
|
|
if (TYPE_REF_P (type))
|
|
expr = mark_lvalue_use (expr);
|
|
else
|
|
expr = mark_rvalue_use (expr);
|
|
|
|
if (error_operand_p (expr))
|
|
return error_mark_node;
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
p = conversion_obstack_alloc (0);
|
|
|
|
conv = implicit_conversion (type, TREE_TYPE (expr), expr,
|
|
/*c_cast_p=*/false,
|
|
flags, complain);
|
|
|
|
if (!conv)
|
|
{
|
|
if (complain & tf_error)
|
|
implicit_conversion_error (loc, type, expr);
|
|
expr = error_mark_node;
|
|
}
|
|
else if (processing_template_decl && conv->kind != ck_identity)
|
|
expr = build_implicit_conv_flags (type, expr, flags);
|
|
else
|
|
{
|
|
/* Give a conversion call the same location as expr. */
|
|
iloc_sentinel il (loc);
|
|
expr = convert_like (conv, expr, complain);
|
|
}
|
|
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
return expr;
|
|
}
|
|
|
|
tree
|
|
perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain)
|
|
{
|
|
return perform_implicit_conversion_flags (type, expr, complain,
|
|
LOOKUP_IMPLICIT);
|
|
}
|
|
|
|
/* Convert EXPR to TYPE (as a direct-initialization) if that is
|
|
permitted. If the conversion is valid, the converted expression is
|
|
returned. Otherwise, NULL_TREE is returned, except in the case
|
|
that TYPE is a class type; in that case, an error is issued. If
|
|
C_CAST_P is true, then this direct-initialization is taking
|
|
place as part of a static_cast being attempted as part of a C-style
|
|
cast. */
|
|
|
|
tree
|
|
perform_direct_initialization_if_possible (tree type,
|
|
tree expr,
|
|
bool c_cast_p,
|
|
tsubst_flags_t complain)
|
|
{
|
|
conversion *conv;
|
|
void *p;
|
|
|
|
if (type == error_mark_node || error_operand_p (expr))
|
|
return error_mark_node;
|
|
/* [dcl.init]
|
|
|
|
If the destination type is a (possibly cv-qualified) class type:
|
|
|
|
-- If the initialization is direct-initialization ...,
|
|
constructors are considered.
|
|
|
|
-- If overload resolution is successful, the selected constructor
|
|
is called to initialize the object, with the initializer expression
|
|
or expression-list as its argument(s).
|
|
|
|
-- Otherwise, if no constructor is viable, the destination type is
|
|
a (possibly cv-qualified) aggregate class A, and the initializer is
|
|
a parenthesized expression-list, the object is initialized as
|
|
follows... */
|
|
if (CLASS_TYPE_P (type))
|
|
{
|
|
releasing_vec args (make_tree_vector_single (expr));
|
|
expr = build_special_member_call (NULL_TREE, complete_ctor_identifier,
|
|
&args, type, LOOKUP_NORMAL, complain);
|
|
return build_cplus_new (type, expr, complain);
|
|
}
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
p = conversion_obstack_alloc (0);
|
|
|
|
conv = implicit_conversion (type, TREE_TYPE (expr), expr,
|
|
c_cast_p,
|
|
LOOKUP_NORMAL, complain);
|
|
if (!conv || conv->bad_p)
|
|
expr = NULL_TREE;
|
|
else if (processing_template_decl && conv->kind != ck_identity)
|
|
{
|
|
/* In a template, we are only concerned about determining the
|
|
type of non-dependent expressions, so we do not have to
|
|
perform the actual conversion. But for initializers, we
|
|
need to be able to perform it at instantiation
|
|
(or instantiate_non_dependent_expr) time. */
|
|
expr = build1 (IMPLICIT_CONV_EXPR, type, expr);
|
|
IMPLICIT_CONV_EXPR_DIRECT_INIT (expr) = true;
|
|
}
|
|
else
|
|
expr = convert_like (conv, expr, NULL_TREE, 0,
|
|
/*issue_conversion_warnings=*/false,
|
|
c_cast_p, complain);
|
|
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
return expr;
|
|
}
|
|
|
|
/* When initializing a reference that lasts longer than a full-expression,
|
|
this special rule applies:
|
|
|
|
[class.temporary]
|
|
|
|
The temporary to which the reference is bound or the temporary
|
|
that is the complete object to which the reference is bound
|
|
persists for the lifetime of the reference.
|
|
|
|
The temporaries created during the evaluation of the expression
|
|
initializing the reference, except the temporary to which the
|
|
reference is bound, are destroyed at the end of the
|
|
full-expression in which they are created.
|
|
|
|
In that case, we store the converted expression into a new
|
|
VAR_DECL in a new scope.
|
|
|
|
However, we want to be careful not to create temporaries when
|
|
they are not required. For example, given:
|
|
|
|
struct B {};
|
|
struct D : public B {};
|
|
D f();
|
|
const B& b = f();
|
|
|
|
there is no need to copy the return value from "f"; we can just
|
|
extend its lifetime. Similarly, given:
|
|
|
|
struct S {};
|
|
struct T { operator S(); };
|
|
T t;
|
|
const S& s = t;
|
|
|
|
we can extend the lifetime of the return value of the conversion
|
|
operator.
|
|
|
|
The next several functions are involved in this lifetime extension. */
|
|
|
|
/* DECL is a VAR_DECL or FIELD_DECL whose type is a REFERENCE_TYPE. The
|
|
reference is being bound to a temporary. Create and return a new
|
|
VAR_DECL with the indicated TYPE; this variable will store the value to
|
|
which the reference is bound. */
|
|
|
|
tree
|
|
make_temporary_var_for_ref_to_temp (tree decl, tree type)
|
|
{
|
|
tree var = create_temporary_var (type);
|
|
|
|
/* Register the variable. */
|
|
if (VAR_P (decl)
|
|
&& (TREE_STATIC (decl) || CP_DECL_THREAD_LOCAL_P (decl)))
|
|
{
|
|
/* Namespace-scope or local static; give it a mangled name. */
|
|
|
|
/* 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. */
|
|
copy_linkage (var, decl);
|
|
|
|
tree name = mangle_ref_init_variable (decl);
|
|
DECL_NAME (var) = name;
|
|
SET_DECL_ASSEMBLER_NAME (var, name);
|
|
}
|
|
else
|
|
/* Create a new cleanup level if necessary. */
|
|
maybe_push_cleanup_level (type);
|
|
|
|
return pushdecl (var);
|
|
}
|
|
|
|
/* EXPR is the initializer for a variable DECL of reference or
|
|
std::initializer_list type. Create, push and return a new VAR_DECL
|
|
for the initializer so that it will live as long as DECL. Any
|
|
cleanup for the new variable is returned through CLEANUP, and the
|
|
code to initialize the new variable is returned through INITP. */
|
|
|
|
static tree
|
|
set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups,
|
|
tree *initp, tree *cond_guard)
|
|
{
|
|
tree init;
|
|
tree type;
|
|
tree var;
|
|
|
|
/* Create the temporary variable. */
|
|
type = TREE_TYPE (expr);
|
|
var = make_temporary_var_for_ref_to_temp (decl, type);
|
|
layout_decl (var, 0);
|
|
/* If the rvalue is the result of a function call it will be
|
|
a TARGET_EXPR. If it is some other construct (such as a
|
|
member access expression where the underlying object is
|
|
itself the result of a function call), turn it into a
|
|
TARGET_EXPR here. It is important that EXPR be a
|
|
TARGET_EXPR below since otherwise the INIT_EXPR will
|
|
attempt to make a bitwise copy of EXPR to initialize
|
|
VAR. */
|
|
if (TREE_CODE (expr) != TARGET_EXPR)
|
|
expr = get_target_expr (expr);
|
|
else if (TREE_ADDRESSABLE (expr))
|
|
TREE_ADDRESSABLE (var) = 1;
|
|
|
|
if (TREE_CODE (decl) == FIELD_DECL
|
|
&& extra_warnings && !warning_suppressed_p (decl))
|
|
{
|
|
warning (OPT_Wextra, "a temporary bound to %qD only persists "
|
|
"until the constructor exits", decl);
|
|
suppress_warning (decl);
|
|
}
|
|
|
|
/* Recursively extend temps in this initializer. */
|
|
TARGET_EXPR_INITIAL (expr)
|
|
= extend_ref_init_temps (decl, TARGET_EXPR_INITIAL (expr), cleanups,
|
|
cond_guard);
|
|
|
|
/* Any reference temp has a non-trivial initializer. */
|
|
DECL_NONTRIVIALLY_INITIALIZED_P (var) = true;
|
|
|
|
/* If the initializer is constant, put it in DECL_INITIAL so we get
|
|
static initialization and use in constant expressions. */
|
|
init = maybe_constant_init (expr);
|
|
/* As in store_init_value. */
|
|
init = cp_fully_fold (init);
|
|
if (TREE_CONSTANT (init))
|
|
{
|
|
if (literal_type_p (type) && CP_TYPE_CONST_NON_VOLATILE_P (type))
|
|
{
|
|
/* 5.19 says that a constant expression can include an
|
|
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. */
|
|
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;
|
|
}
|
|
else
|
|
/* Create the INIT_EXPR that will initialize the temporary
|
|
variable. */
|
|
init = split_nonconstant_init (var, expr);
|
|
if (at_function_scope_p ())
|
|
{
|
|
add_decl_expr (var);
|
|
|
|
if (TREE_STATIC (var))
|
|
init = add_stmt_to_compound (init, register_dtor_fn (var));
|
|
else
|
|
{
|
|
tree cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error);
|
|
if (cleanup)
|
|
{
|
|
if (cond_guard && cleanup != error_mark_node)
|
|
{
|
|
if (*cond_guard == NULL_TREE)
|
|
{
|
|
*cond_guard = build_local_temp (boolean_type_node);
|
|
add_decl_expr (*cond_guard);
|
|
tree set = cp_build_modify_expr (UNKNOWN_LOCATION,
|
|
*cond_guard, NOP_EXPR,
|
|
boolean_false_node,
|
|
tf_warning_or_error);
|
|
finish_expr_stmt (set);
|
|
}
|
|
cleanup = build3 (COND_EXPR, void_type_node,
|
|
*cond_guard, cleanup, NULL_TREE);
|
|
}
|
|
vec_safe_push (*cleanups, cleanup);
|
|
}
|
|
}
|
|
|
|
/* We must be careful to destroy the temporary only
|
|
after its initialization has taken place. If the
|
|
initialization throws an exception, then the
|
|
destructor should not be run. We cannot simply
|
|
transform INIT into something like:
|
|
|
|
(INIT, ({ CLEANUP_STMT; }))
|
|
|
|
because emit_local_var always treats the
|
|
initializer as a full-expression. Thus, the
|
|
destructor would run too early; it would run at the
|
|
end of initializing the reference variable, rather
|
|
than at the end of the block enclosing the
|
|
reference variable.
|
|
|
|
The solution is to pass back a cleanup expression
|
|
which the caller is responsible for attaching to
|
|
the statement tree. */
|
|
}
|
|
else
|
|
{
|
|
rest_of_decl_compilation (var, /*toplev=*/1, at_eof);
|
|
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
|
|
{
|
|
if (CP_DECL_THREAD_LOCAL_P (var))
|
|
tls_aggregates = tree_cons (NULL_TREE, var,
|
|
tls_aggregates);
|
|
else
|
|
static_aggregates = tree_cons (NULL_TREE, var,
|
|
static_aggregates);
|
|
}
|
|
else
|
|
/* Check whether the dtor is callable. */
|
|
cxx_maybe_build_cleanup (var, tf_warning_or_error);
|
|
}
|
|
/* Avoid -Wunused-variable warning (c++/38958). */
|
|
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
|
|
&& VAR_P (decl))
|
|
TREE_USED (decl) = DECL_READ_P (decl) = true;
|
|
|
|
*initp = init;
|
|
return var;
|
|
}
|
|
|
|
/* Convert EXPR to the indicated reference TYPE, in a way suitable for
|
|
initializing a variable of that TYPE. */
|
|
|
|
tree
|
|
initialize_reference (tree type, tree expr,
|
|
int flags, tsubst_flags_t complain)
|
|
{
|
|
conversion *conv;
|
|
void *p;
|
|
location_t loc = cp_expr_loc_or_input_loc (expr);
|
|
|
|
if (type == error_mark_node || error_operand_p (expr))
|
|
return error_mark_node;
|
|
|
|
/* Get the high-water mark for the CONVERSION_OBSTACK. */
|
|
p = conversion_obstack_alloc (0);
|
|
|
|
conv = reference_binding (type, TREE_TYPE (expr), expr, /*c_cast_p=*/false,
|
|
flags, complain);
|
|
/* If this conversion failed, we're in C++20, and we have something like
|
|
A& a(b) where A is an aggregate, try again, this time as A& a{b}. */
|
|
if ((!conv || conv->bad_p)
|
|
&& (flags & LOOKUP_AGGREGATE_PAREN_INIT))
|
|
{
|
|
tree e = build_constructor_single (init_list_type_node, NULL_TREE, expr);
|
|
CONSTRUCTOR_IS_DIRECT_INIT (e) = true;
|
|
CONSTRUCTOR_IS_PAREN_INIT (e) = true;
|
|
conversion *c = reference_binding (type, TREE_TYPE (e), e,
|
|
/*c_cast_p=*/false, flags, complain);
|
|
/* If this worked, use it. */
|
|
if (c && !c->bad_p)
|
|
expr = e, conv = c;
|
|
}
|
|
if (!conv || conv->bad_p)
|
|
{
|
|
if (complain & tf_error)
|
|
{
|
|
if (conv)
|
|
convert_like (conv, expr, complain);
|
|
else if (!CP_TYPE_CONST_P (TREE_TYPE (type))
|
|
&& !TYPE_REF_IS_RVALUE (type)
|
|
&& !lvalue_p (expr))
|
|
error_at (loc, "invalid initialization of non-const reference of "
|
|
"type %qH from an rvalue of type %qI",
|
|
type, TREE_TYPE (expr));
|
|
else
|
|
error_at (loc, "invalid initialization of reference of type "
|
|
"%qH from expression of type %qI", type,
|
|
TREE_TYPE (expr));
|
|
}
|
|
return error_mark_node;
|
|
}
|
|
|
|
if (conv->kind == ck_ref_bind)
|
|
/* Perform the conversion. */
|
|
expr = convert_like (conv, expr, complain);
|
|
else if (conv->kind == ck_ambig)
|
|
/* We gave an error in build_user_type_conversion_1. */
|
|
expr = error_mark_node;
|
|
else
|
|
gcc_unreachable ();
|
|
|
|
/* Free all the conversions we allocated. */
|
|
obstack_free (&conversion_obstack, p);
|
|
|
|
return expr;
|
|
}
|
|
|
|
/* If *P is an xvalue expression, prevent temporary lifetime extension if it
|
|
gets used to initialize a reference. */
|
|
|
|
static tree
|
|
prevent_lifetime_extension (tree t)
|
|
{
|
|
tree *p = &t;
|
|
while (TREE_CODE (*p) == COMPOUND_EXPR)
|
|
p = &TREE_OPERAND (*p, 1);
|
|
while (handled_component_p (*p))
|
|
p = &TREE_OPERAND (*p, 0);
|
|
/* Change a TARGET_EXPR from prvalue to xvalue. */
|
|
if (TREE_CODE (*p) == TARGET_EXPR)
|
|
*p = build2 (COMPOUND_EXPR, TREE_TYPE (*p), *p,
|
|
move (TARGET_EXPR_SLOT (*p)));
|
|
return t;
|
|
}
|
|
|
|
/* Subroutine of extend_ref_init_temps. Possibly extend one initializer,
|
|
which is bound either to a reference or a std::initializer_list. */
|
|
|
|
static tree
|
|
extend_ref_init_temps_1 (tree decl, tree init, vec<tree, va_gc> **cleanups,
|
|
tree *cond_guard)
|
|
{
|
|
tree sub = init;
|
|
tree *p;
|
|
STRIP_NOPS (sub);
|
|
if (TREE_CODE (sub) == COMPOUND_EXPR)
|
|
{
|
|
TREE_OPERAND (sub, 1)
|
|
= extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 1), cleanups,
|
|
cond_guard);
|
|
return init;
|
|
}
|
|
if (TREE_CODE (sub) == COND_EXPR)
|
|
{
|
|
tree cur_cond_guard = NULL_TREE;
|
|
if (TREE_OPERAND (sub, 1))
|
|
TREE_OPERAND (sub, 1)
|
|
= extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 1), cleanups,
|
|
&cur_cond_guard);
|
|
if (cur_cond_guard)
|
|
{
|
|
tree set = cp_build_modify_expr (UNKNOWN_LOCATION, cur_cond_guard,
|
|
NOP_EXPR, boolean_true_node,
|
|
tf_warning_or_error);
|
|
TREE_OPERAND (sub, 1)
|
|
= cp_build_compound_expr (set, TREE_OPERAND (sub, 1),
|
|
tf_warning_or_error);
|
|
}
|
|
cur_cond_guard = NULL_TREE;
|
|
if (TREE_OPERAND (sub, 2))
|
|
TREE_OPERAND (sub, 2)
|
|
= extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 2), cleanups,
|
|
&cur_cond_guard);
|
|
if (cur_cond_guard)
|
|
{
|
|
tree set = cp_build_modify_expr (UNKNOWN_LOCATION, cur_cond_guard,
|
|
NOP_EXPR, boolean_true_node,
|
|
tf_warning_or_error);
|
|
TREE_OPERAND (sub, 2)
|
|
= cp_build_compound_expr (set, TREE_OPERAND (sub, 2),
|
|
tf_warning_or_error);
|
|
}
|
|
return init;
|
|
}
|
|
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 || TREE_CODE (*p) == ARRAY_REF; )
|
|
p = &TREE_OPERAND (*p, 0);
|
|
if (TREE_CODE (*p) == TARGET_EXPR)
|
|
{
|
|
tree subinit = NULL_TREE;
|
|
*p = set_up_extended_ref_temp (decl, *p, cleanups, &subinit, cond_guard);
|
|
recompute_tree_invariant_for_addr_expr (sub);
|
|
if (init != sub)
|
|
init = fold_convert (TREE_TYPE (init), sub);
|
|
if (subinit)
|
|
init = build2 (COMPOUND_EXPR, TREE_TYPE (init), subinit, init);
|
|
}
|
|
return init;
|
|
}
|
|
|
|
/* INIT is part of the initializer for DECL. If there are any
|
|
reference or initializer lists being initialized, extend their
|
|
lifetime to match that of DECL. */
|
|
|
|
tree
|
|
extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups,
|
|
tree *cond_guard)
|
|
{
|
|
tree type = TREE_TYPE (init);
|
|
if (processing_template_decl)
|
|
return init;
|
|
if (TYPE_REF_P (type))
|
|
init = extend_ref_init_temps_1 (decl, init, cleanups, cond_guard);
|
|
else
|
|
{
|
|
tree ctor = init;
|
|
if (TREE_CODE (ctor) == TARGET_EXPR)
|
|
ctor = TARGET_EXPR_INITIAL (ctor);
|
|
if (TREE_CODE (ctor) == CONSTRUCTOR)
|
|
{
|
|
/* [dcl.init] When initializing an aggregate from a parenthesized list
|
|
of values... a temporary object bound to a reference does not have
|
|
its lifetime extended. */
|
|
if (CONSTRUCTOR_IS_PAREN_INIT (ctor))
|
|
return init;
|
|
|
|
if (is_std_init_list (type))
|
|
{
|
|
/* The temporary array underlying a std::initializer_list
|
|
is handled like a reference temporary. */
|
|
tree array = CONSTRUCTOR_ELT (ctor, 0)->value;
|
|
array = extend_ref_init_temps_1 (decl, array, cleanups,
|
|
cond_guard);
|
|
CONSTRUCTOR_ELT (ctor, 0)->value = array;
|
|
}
|
|
else
|
|
{
|
|
unsigned i;
|
|
constructor_elt *p;
|
|
vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (ctor);
|
|
FOR_EACH_VEC_SAFE_ELT (elts, i, p)
|
|
p->value = extend_ref_init_temps (decl, p->value, cleanups,
|
|
cond_guard);
|
|
}
|
|
recompute_constructor_flags (ctor);
|
|
if (decl_maybe_constant_var_p (decl) && TREE_CONSTANT (ctor))
|
|
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true;
|
|
}
|
|
}
|
|
|
|
return init;
|
|
}
|
|
|
|
/* Returns true iff an initializer for TYPE could contain temporaries that
|
|
need to be extended because they are bound to references or
|
|
std::initializer_list. */
|
|
|
|
bool
|
|
type_has_extended_temps (tree type)
|
|
{
|
|
type = strip_array_types (type);
|
|
if (TYPE_REF_P (type))
|
|
return true;
|
|
if (CLASS_TYPE_P (type))
|
|
{
|
|
if (is_std_init_list (type))
|
|
return true;
|
|
for (tree f = next_initializable_field (TYPE_FIELDS (type));
|
|
f; f = next_initializable_field (DECL_CHAIN (f)))
|
|
if (type_has_extended_temps (TREE_TYPE (f)))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Returns true iff TYPE is some variant of std::initializer_list. */
|
|
|
|
bool
|
|
is_std_init_list (tree type)
|
|
{
|
|
if (!TYPE_P (type))
|
|
return false;
|
|
if (cxx_dialect == cxx98)
|
|
return false;
|
|
/* Look through typedefs. */
|
|
type = TYPE_MAIN_VARIANT (type);
|
|
return (CLASS_TYPE_P (type)
|
|
&& CP_TYPE_CONTEXT (type) == std_node
|
|
&& init_list_identifier == DECL_NAME (TYPE_NAME (type)));
|
|
}
|
|
|
|
/* Returns true iff DECL is a list constructor: i.e. a constructor which
|
|
will accept an argument list of a single std::initializer_list<T>. */
|
|
|
|
bool
|
|
is_list_ctor (tree decl)
|
|
{
|
|
tree args = FUNCTION_FIRST_USER_PARMTYPE (decl);
|
|
tree arg;
|
|
|
|
if (!args || args == void_list_node)
|
|
return false;
|
|
|
|
arg = non_reference (TREE_VALUE (args));
|
|
if (!is_std_init_list (arg))
|
|
return false;
|
|
|
|
args = TREE_CHAIN (args);
|
|
|
|
if (args && args != void_list_node && !TREE_PURPOSE (args))
|
|
/* There are more non-defaulted parms. */
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
#include "gt-cp-call.h"
|