inform (loc, "%qT is not invocable, because", t1);
else
inform (loc, "%qT is not invocable by %qT, because", t1, t2);
- tree call = build_invoke (t1, t2, tf_error);
- gcc_assert (call == error_mark_node);
+ build_invoke (t1, t2, tf_error);
}
break;
case CPTK_IS_LAYOUT_COMPATIBLE:
return true;
}
-/* Explain why EXPR is not noexcept. */
+/* If EXPR is not noexcept, explain why. */
-void explain_not_noexcept (tree expr)
+void
+explain_not_noexcept (tree expr)
{
tree fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0);
- gcc_assert (fn);
- if (DECL_P (fn))
+ if (!fn)
+ /* The call was noexcept, nothing to do. */;
+ else if (DECL_P (fn))
inform (DECL_SOURCE_LOCATION (fn), "%qD is not %<noexcept%>", fn);
else
inform (location_of (fn), "%qT is not %<noexcept%>", TREE_TYPE (fn));
}
/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...). If the
- given is not invocable, returns error_mark_node. */
+ given is not invocable, returns error_mark_node, unless COMPLAIN includes
+ tf_error. */
tree
build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
is_trivially_xible (enum tree_code code, tree to, tree from,
bool explain/*=false*/)
{
- /* 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);
- }
+ if (explain && nt)
+ inform (location_of (nt), "%qE is non-trivial", nt);
return !nt;
}
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, explain);
--cp_noexcept_operand;
return false;
bool is_noexcept = expr_noexcept_p (expr, tf_none);
- if (explain && errs == (errorcount + sorrycount))
- {
- gcc_assert (!is_noexcept);
- explain_not_noexcept (expr);
- }
+ if (explain && !is_noexcept)
+ explain_not_noexcept (expr);
return is_noexcept;
}
tree expr = is_convertible_helper (from, to, explain);
if (expr == NULL_TREE || expr == error_mark_node)
return false;
+
bool is_noexcept = expr_noexcept_p (expr, tf_none);
- if (explain)
- {
- gcc_assert (!is_noexcept);
- explain_not_noexcept (expr);
- }
+ if (explain && !is_noexcept)
+ explain_not_noexcept (expr);
return is_noexcept;
}
--- /dev/null
+// PR c++/121291
+// { dg-do compile { target c++17 } }
+
+template <typename T>
+constexpr bool is_invocable = __is_invocable(T);
+
+template <typename T>
+constexpr bool is_nothrow_invocable = __is_nothrow_invocable(T);
+
+struct S {
+private:
+ int operator()() noexcept; // { dg-message "here" }
+};
+
+static_assert(is_invocable<S>); // { dg-error "assert" }
+// { dg-message "not invocable" "" { target *-*-* } .-1 }
+// { dg-error "private within this context" "" { target *-*-* } .-2 }
+
+static_assert(is_nothrow_invocable<S>); // { dg-error "assert" }
+// { dg-message "not nothrow invocable" "" { target *-*-* } .-1 }
+// { dg-error "private within this context" "" { target *-*-* } .-2 }
--- /dev/null
+// PR c++/121291
+// { dg-do compile { target c++17 } }
+
+template <typename T, typename U>
+constexpr bool is_nothrow_convertible = __is_nothrow_convertible(T, U);
+
+struct A {};
+struct B {
+private:
+ operator A() noexcept; // { dg-message "here" }
+};
+
+static_assert(is_nothrow_convertible<B, A>); // { dg-error "assert" }
+// { dg-message "not nothrow convertible" "" { target *-*-* } .-1 }
+// { dg-error "private within this context" "" { target *-*-* } .-2 }