aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/method.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/method.cc')
-rw-r--r--gcc/cp/method.cc243
1 files changed, 174 insertions, 69 deletions
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index a4089c5..62f8d80 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1187,15 +1187,15 @@ early_check_defaulted_comparison (tree fn)
if (!DECL_OVERLOADED_OPERATOR_IS (fn, SPACESHIP_EXPR)
&& !same_type_p (TREE_TYPE (TREE_TYPE (fn)), boolean_type_node))
{
- diagnostic_t kind = DK_UNSPECIFIED;
+ enum diagnostics::kind kind = diagnostics::kind::unspecified;
int opt = 0;
if (is_auto (TREE_TYPE (fn)))
- kind = DK_PEDWARN;
+ kind = diagnostics::kind::pedwarn;
else
- kind = DK_ERROR;
+ kind = diagnostics::kind::error;
emit_diagnostic (kind, loc, opt,
"defaulted %qD must return %<bool%>", fn);
- if (kind == DK_ERROR)
+ if (kind == diagnostics::kind::error)
ok = false;
}
@@ -1928,8 +1928,8 @@ is_stub_object (tree expr)
/* Build a std::declval<TYPE>() expression and return it. */
-tree
-build_trait_object (tree type)
+static tree
+build_trait_object (tree type, tsubst_flags_t complain)
{
/* TYPE can't be a function with cv-/ref-qualifiers: std::declval is
defined as
@@ -1942,7 +1942,11 @@ build_trait_object (tree type)
if (FUNC_OR_METHOD_TYPE_P (type)
&& (type_memfn_quals (type) != TYPE_UNQUALIFIED
|| type_memfn_rqual (type) != REF_QUAL_NONE))
- return error_mark_node;
+ {
+ if (complain & tf_error)
+ error ("object cannot have qualified function type %qT", type);
+ return error_mark_node;
+ }
return build_stub_object (type);
}
@@ -2036,22 +2040,26 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
const_tree name = DECL_NAME (datum_decl);
if (name && (id_equal (name, "reference_wrapper")))
{
- /* 1.2 & 1.5: Retrieve T from std::reference_wrapper<T>,
+ /* 1.2 & 1.5: Retrieve T& from std::reference_wrapper<T>,
i.e., decltype(datum.get()). */
datum_type =
TREE_VEC_ELT (TYPE_TI_ARGS (non_ref_datum_type), 0);
+ datum_type = cp_build_reference_type (datum_type, false);
datum_is_refwrap = true;
}
}
}
- tree datum_expr = build_trait_object (datum_type);
+ tree datum_expr = build_trait_object (datum_type, complain);
if (!ptrmem_is_same_or_base_of_datum && !datum_is_refwrap)
/* 1.3 & 1.6: Try to dereference datum_expr. */
datum_expr = build_x_indirect_ref (UNKNOWN_LOCATION, datum_expr,
RO_UNARY_STAR, NULL_TREE, complain);
- tree fn_expr = build_trait_object (fn_type);
+ if (error_operand_p (datum_expr))
+ return error_mark_node;
+
+ tree fn_expr = build_trait_object (fn_type, complain);
ptrmem_expr = build_m_component_ref (datum_expr, fn_expr, complain);
if (error_operand_p (ptrmem_expr))
@@ -2068,7 +2076,9 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
for (int i = is_ptrmemfunc ? 1 : 0; i < TREE_VEC_LENGTH (arg_types); ++i)
{
tree arg_type = TREE_VEC_ELT (arg_types, i);
- tree arg = build_trait_object (arg_type);
+ tree arg = build_trait_object (arg_type, complain);
+ if (error_operand_p (arg))
+ return error_mark_node;
vec_safe_push (args, arg);
}
@@ -2077,8 +2087,8 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
invoke_expr = build_offset_ref_call_from_tree (ptrmem_expr, &args,
complain);
else /* 1.7. */
- invoke_expr = finish_call_expr (build_trait_object (fn_type), &args, false,
- false, complain);
+ invoke_expr = finish_call_expr (build_trait_object (fn_type, complain),
+ &args, false, false, complain);
return invoke_expr;
}
@@ -2227,12 +2237,20 @@ check_nontriv (tree *tp, int *, void *)
/* Return declval<T>() = declval<U>() treated as an unevaluated operand. */
static tree
-assignable_expr (tree to, tree from)
+assignable_expr (tree to, tree from, bool explain)
{
cp_unevaluated cp_uneval_guard;
- to = build_trait_object (to);
- from = build_trait_object (from);
- tree r = cp_build_modify_expr (input_location, to, NOP_EXPR, from, tf_none);
+ tsubst_flags_t complain = explain ? tf_error : tf_none;
+
+ to = build_trait_object (to, complain);
+ if (to == error_mark_node)
+ return error_mark_node;
+
+ from = build_trait_object (from, complain);
+ if (from == error_mark_node)
+ return error_mark_node;
+
+ tree r = cp_build_modify_expr (input_location, to, NOP_EXPR, from, complain);
return r;
}
@@ -2244,10 +2262,11 @@ assignable_expr (tree to, tree from)
Return something equivalent in well-formedness and triviality. */
static tree
-constructible_expr (tree to, tree from)
+constructible_expr (tree to, tree from, bool explain)
{
tree expr;
cp_unevaluated cp_uneval_guard;
+ tsubst_flags_t complain = explain ? tf_error : tf_none;
const int len = TREE_VEC_LENGTH (from);
if (CLASS_TYPE_P (to))
{
@@ -2259,14 +2278,14 @@ constructible_expr (tree to, tree from)
to = cp_build_reference_type (to, /*rval*/false);
tree ob = build_stub_object (to);
if (len == 0)
- expr = build_value_init (ctype, tf_none);
+ expr = build_value_init (ctype, complain);
else
{
vec_alloc (args, len);
for (tree arg : tree_vec_range (from))
args->quick_push (build_stub_object (arg));
expr = build_special_member_call (ob, complete_ctor_identifier, &args,
- ctype, LOOKUP_NORMAL, tf_none);
+ ctype, LOOKUP_NORMAL, complain);
}
if (expr == error_mark_node)
return error_mark_node;
@@ -2276,7 +2295,7 @@ constructible_expr (tree to, tree from)
{
tree dtor = build_special_member_call (ob, complete_dtor_identifier,
NULL, ctype, LOOKUP_NORMAL,
- tf_none);
+ complain);
if (dtor == error_mark_node)
return error_mark_node;
if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (ctype))
@@ -2286,12 +2305,15 @@ constructible_expr (tree to, tree from)
else
{
if (len == 0)
- return build_value_init (strip_array_types (to), tf_none);
+ return build_value_init (strip_array_types (to), complain);
if (len > 1)
{
if (cxx_dialect < cxx20)
- /* Too many initializers. */
- return error_mark_node;
+ {
+ if (explain)
+ error ("too many initializers for non-class type %qT", to);
+ return error_mark_node;
+ }
/* In C++20 this is well-formed:
using T = int[2];
@@ -2312,9 +2334,11 @@ constructible_expr (tree to, tree from)
}
else
from = build_stub_object (TREE_VEC_ELT (from, 0));
+
+ tree orig_from = from;
expr = perform_direct_initialization_if_possible (to, from,
/*cast*/false,
- tf_none);
+ complain);
/* If t(e) didn't work, maybe t{e} will. */
if (expr == NULL_TREE
&& len == 1
@@ -2326,7 +2350,24 @@ constructible_expr (tree to, tree from)
CONSTRUCTOR_IS_PAREN_INIT (from) = true;
expr = perform_direct_initialization_if_possible (to, from,
/*cast*/false,
- tf_none);
+ complain);
+ }
+
+ if (expr == NULL_TREE && explain)
+ {
+ if (len > 1)
+ error ("too many initializers for non-class type %qT", to);
+ else
+ {
+ /* Redo the implicit conversion for diagnostics. */
+ int count = errorcount + warningcount;
+ perform_implicit_conversion_flags (to, orig_from, complain,
+ LOOKUP_NORMAL);
+ if (count == errorcount + warningcount)
+ /* The message may have been suppressed due to -w + -fpermissive,
+ emit a generic response instead. */
+ error ("the conversion is invalid");
+ }
}
}
return expr;
@@ -2340,20 +2381,25 @@ constructible_expr (tree to, tree from)
valid or error_mark_node if not. */
static tree
-destructible_expr (tree to)
+destructible_expr (tree to, bool explain)
{
cp_unevaluated cp_uneval_guard;
+ tsubst_flags_t complain = explain ? tf_error : tf_none;
int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
if (TYPE_REF_P (to))
return void_node;
if (!COMPLETE_TYPE_P (complete_type (to)))
- return error_mark_node;
+ {
+ if (explain)
+ error_at (location_of (to), "%qT is incomplete", to);
+ return error_mark_node;
+ }
to = strip_array_types (to);
if (CLASS_TYPE_P (to))
{
- to = build_trait_object (to);
+ to = build_trait_object (to, complain);
return build_delete (input_location, TREE_TYPE (to), to,
- sfk_complete_destructor, flags, 0, tf_none);
+ sfk_complete_destructor, flags, 0, complain);
}
/* [expr.prim.id.dtor] If the id-expression names a pseudo-destructor, T
shall be a scalar type.... */
@@ -2365,70 +2411,109 @@ destructible_expr (tree to)
/* Returns a tree iff TO is assignable (if CODE is MODIFY_EXPR) or
constructible (otherwise) from FROM, which is a single type for
- assignment or a list of types for construction. */
+ assignment or a list of types for construction. If EXPLAIN is
+ set, emit a diagnostic explaining why the operation failed. */
static tree
-is_xible_helper (enum tree_code code, tree to, tree from, bool trivial)
+is_xible_helper (enum tree_code code, tree to, tree from, bool explain)
{
to = complete_type (to);
deferring_access_check_sentinel acs (dk_no_deferred);
- if (VOID_TYPE_P (to)
- || (from && FUNC_OR_METHOD_TYPE_P (from)
- && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from))))
- return error_mark_node;
+
+ if (VOID_TYPE_P (to))
+ {
+ if (explain)
+ error_at (location_of (to), "%qT is incomplete", to);
+ return error_mark_node;
+ }
+ if (from
+ && FUNC_OR_METHOD_TYPE_P (from)
+ && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from)))
+ {
+ if (explain)
+ error ("%qT is a qualified function type", from);
+ return error_mark_node;
+ }
+
tree expr;
if (code == MODIFY_EXPR)
- expr = assignable_expr (to, from);
+ expr = assignable_expr (to, from, explain);
else if (code == BIT_NOT_EXPR)
- expr = destructible_expr (to);
- else if (trivial && TREE_VEC_LENGTH (from) > 1
- && cxx_dialect < cxx20)
- return error_mark_node; // only 0- and 1-argument ctors can be trivial
- // before C++20 aggregate paren init
+ expr = destructible_expr (to, explain);
else if (TREE_CODE (to) == ARRAY_TYPE && !TYPE_DOMAIN (to))
- return error_mark_node; // can't construct an array of unknown bound
+ {
+ if (explain)
+ error ("cannot construct an array of unknown bound");
+ return error_mark_node;
+ }
else
- expr = constructible_expr (to, from);
+ expr = constructible_expr (to, from, explain);
return expr;
}
/* Returns true iff TO is trivially assignable (if CODE is MODIFY_EXPR) or
constructible (otherwise) from FROM, which is a single type for
- assignment or a list of types for construction. */
+ assignment or a list of types for construction. If EXPLAIN, diagnose
+ why we returned false. */
bool
-is_trivially_xible (enum tree_code code, tree to, tree from)
+is_trivially_xible (enum tree_code code, tree to, tree from,
+ bool explain/*=false*/)
{
- tree expr = is_xible_helper (code, to, from, /*trivial*/true);
+ /* In some cases, when producing errors is_xible_helper may not return
+ error_mark_node, so check if it looks like we've already emitted any
+ diagnostics to ensure we don't do so multiple times. */
+ int errs = errorcount + sorrycount;
+
+ tree expr = is_xible_helper (code, to, from, explain);
if (expr == NULL_TREE || expr == error_mark_node)
return false;
+
tree nt = cp_walk_tree_without_duplicates (&expr, check_nontriv, NULL);
+ if (explain && errs == (errorcount + sorrycount))
+ {
+ gcc_assert (nt);
+ inform (location_of (nt), "%qE is non-trivial", nt);
+ }
return !nt;
}
/* Returns true iff TO is nothrow assignable (if CODE is MODIFY_EXPR) or
constructible (otherwise) from FROM, which is a single type for
- assignment or a list of types for construction. */
+ assignment or a list of types for construction. If EXPLAIN, diagnose
+ why we returned false. */
bool
-is_nothrow_xible (enum tree_code code, tree to, tree from)
+is_nothrow_xible (enum tree_code code, tree to, tree from,
+ bool explain/*=false*/)
{
+ /* As with is_trivially_xible. */
+ int errs = errorcount + sorrycount;
+
++cp_noexcept_operand;
- tree expr = is_xible_helper (code, to, from, /*trivial*/false);
+ tree expr = is_xible_helper (code, to, from, explain);
--cp_noexcept_operand;
if (expr == NULL_TREE || expr == error_mark_node)
return false;
- return expr_noexcept_p (expr, tf_none);
+
+ bool is_noexcept = expr_noexcept_p (expr, tf_none);
+ if (explain && errs == (errorcount + sorrycount))
+ {
+ gcc_assert (!is_noexcept);
+ explain_not_noexcept (expr);
+ }
+ return is_noexcept;
}
/* Returns true iff TO is assignable (if CODE is MODIFY_EXPR) or
constructible (otherwise) from FROM, which is a single type for
- assignment or a list of types for construction. */
+ assignment or a list of types for construction. If EXPLAIN, diagnose
+ why we returned false. */
bool
-is_xible (enum tree_code code, tree to, tree from)
+is_xible (enum tree_code code, tree to, tree from, bool explain/*=false*/)
{
- tree expr = is_xible_helper (code, to, from, /*trivial*/false);
+ tree expr = is_xible_helper (code, to, from, explain);
if (expr == error_mark_node)
return false;
return !!expr;
@@ -2453,7 +2538,7 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p)
return false;
/* We don't check is_constructible<T, U>: if T isn't constructible
from U, we won't be able to create a conversion. */
- tree val = build_trait_object (from);
+ tree val = build_trait_object (from, tf_none);
if (val == error_mark_node)
return false;
if (!TYPE_REF_P (from) && TREE_CODE (from) != FUNCTION_TYPE)
@@ -2462,25 +2547,36 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p)
}
/* Worker for is_{,nothrow_}convertible. Attempt to perform an implicit
- conversion from FROM to TO and return the result. */
+ conversion from FROM to TO and return the result. If EXPLAIN, emit a
+ diagnostic about why the conversion failed. */
static tree
-is_convertible_helper (tree from, tree to)
+is_convertible_helper (tree from, tree to, bool explain)
{
if (VOID_TYPE_P (from) && VOID_TYPE_P (to))
return integer_one_node;
cp_unevaluated u;
- tree expr = build_trait_object (from);
+ tsubst_flags_t complain = explain ? tf_error : tf_none;
+
/* std::is_{,nothrow_}convertible test whether the imaginary function
definition
To test() { return std::declval<From>(); }
is well-formed. A function can't return a function. */
- if (FUNC_OR_METHOD_TYPE_P (to) || expr == error_mark_node)
+ if (FUNC_OR_METHOD_TYPE_P (to))
+ {
+ if (explain)
+ error ("%qT is a function type", to);
+ return error_mark_node;
+ }
+
+ tree expr = build_trait_object (from, complain);
+ if (expr == error_mark_node)
return error_mark_node;
+
deferring_access_check_sentinel acs (dk_no_deferred);
- return perform_implicit_conversion (to, expr, tf_none);
+ return perform_implicit_conversion (to, expr, complain);
}
/* Return true if FROM can be converted to TO using implicit conversions,
@@ -2489,9 +2585,9 @@ is_convertible_helper (tree from, tree to)
to either type" restriction. */
bool
-is_convertible (tree from, tree to)
+is_convertible (tree from, tree to, bool explain/*=false*/)
{
- tree expr = is_convertible_helper (from, to);
+ tree expr = is_convertible_helper (from, to, explain);
if (expr == error_mark_node)
return false;
return !!expr;
@@ -2500,12 +2596,18 @@ is_convertible (tree from, tree to)
/* Like is_convertible, but the conversion is also noexcept. */
bool
-is_nothrow_convertible (tree from, tree to)
+is_nothrow_convertible (tree from, tree to, bool explain/*=false*/)
{
- tree expr = is_convertible_helper (from, to);
+ tree expr = is_convertible_helper (from, to, explain);
if (expr == NULL_TREE || expr == error_mark_node)
return false;
- return expr_noexcept_p (expr, tf_none);
+ bool is_noexcept = expr_noexcept_p (expr, tf_none);
+ if (explain)
+ {
+ gcc_assert (!is_noexcept);
+ explain_not_noexcept (expr);
+ }
+ return is_noexcept;
}
/* Categorize various special_function_kinds. */
@@ -3586,21 +3688,24 @@ maybe_delete_defaulted_fn (tree fn, tree implicit_fn)
the program is ill-formed" */
|| !TYPE_REF_P (parmtype)));
/* Decide if we want to emit a pedwarn, error, or a warning. */
- diagnostic_t diag_kind;
+ enum diagnostics::kind diag_kind;
int opt;
if (illformed_p)
{
- diag_kind = DK_ERROR;
+ diag_kind = diagnostics::kind::error;
opt = 0;
}
else
{
- diag_kind = cxx_dialect >= cxx20 ? DK_WARNING : DK_PEDWARN;
+ diag_kind = (cxx_dialect >= cxx20
+ ? diagnostics::kind::warning
+ : diagnostics::kind::pedwarn);
opt = OPT_Wdefaulted_function_deleted;
}
/* Don't warn for template instantiations. */
- if (DECL_TEMPLATE_INSTANTIATION (fn) && diag_kind == DK_WARNING)
+ if (DECL_TEMPLATE_INSTANTIATION (fn)
+ && diag_kind == diagnostics::kind::warning)
return;
const char *wmsg;