Auto merge of #109453 - matthiaskrgr:rollup-odn02wu, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #96391 (Windows: make `Command` prefer non-verbatim paths) - #108164 (Drop all messages in bounded channel when destroying the last receiver) - #108729 (fix: modify the condition that `resolve_imports` stops) - #109336 (Constrain const vars to error if const types are mismatched) - #109403 (Avoid ICE of attempt to add with overflow in emitter) - #109415 (Refactor `handle_missing_lit`.) - #109441 (Only implement Fn* traits for extern "Rust" safe function pointers and items) - #109446 (Do not suggest bounds restrictions for synthesized RPITITs) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
1db9c061d3
@ -331,7 +331,7 @@ fn push_trailing(
|
||||
});
|
||||
buf.push_str(&part.snippet);
|
||||
let cur_hi = sm.lookup_char_pos(part.span.hi());
|
||||
if cur_hi.line == cur_lo.line {
|
||||
if cur_hi.line == cur_lo.line && !part.snippet.is_empty() {
|
||||
// Account for the difference between the width of the current code and the
|
||||
// snippet being suggested, so that the *later* suggestions are correctly
|
||||
// aligned on the screen.
|
||||
|
@ -189,10 +189,19 @@ pub fn super_combine_consts<R>(
|
||||
// the expected const's type. Specifically, we don't want const infer vars
|
||||
// to do any type shapeshifting before and after resolution.
|
||||
if let Err(guar) = compatible_types {
|
||||
return Ok(self.tcx.const_error_with_guaranteed(
|
||||
if relation.a_is_expected() { a.ty() } else { b.ty() },
|
||||
guar,
|
||||
));
|
||||
// HACK: equating both sides with `[const error]` eagerly prevents us
|
||||
// from leaving unconstrained inference vars during things like impl
|
||||
// matching in the solver.
|
||||
let a_error = self.tcx.const_error_with_guaranteed(a.ty(), guar);
|
||||
if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() {
|
||||
return self.unify_const_variable(vid, a_error);
|
||||
}
|
||||
let b_error = self.tcx.const_error_with_guaranteed(b.ty(), guar);
|
||||
if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() {
|
||||
return self.unify_const_variable(vid, b_error);
|
||||
}
|
||||
|
||||
return Ok(if relation.a_is_expected() { a_error } else { b_error });
|
||||
}
|
||||
|
||||
match (a.kind(), b.kind()) {
|
||||
|
@ -23,7 +23,7 @@
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::VariantIdx;
|
||||
use rustc_target::spec::abi;
|
||||
use rustc_target::spec::abi::{self, Abi};
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
@ -1403,6 +1403,18 @@ pub fn unsafety(&self) -> hir::Unsafety {
|
||||
pub fn abi(&self) -> abi::Abi {
|
||||
self.skip_binder().abi
|
||||
}
|
||||
|
||||
pub fn is_fn_trait_compatible(&self) -> bool {
|
||||
matches!(
|
||||
self.skip_binder(),
|
||||
ty::FnSig {
|
||||
unsafety: rustc_hir::Unsafety::Normal,
|
||||
abi: Abi::Rust,
|
||||
c_variadic: false,
|
||||
..
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>;
|
||||
|
@ -1843,20 +1843,14 @@ fn handle_missing_lit<L>(
|
||||
&mut self,
|
||||
mk_lit_char: impl FnOnce(Symbol, Span) -> L,
|
||||
) -> PResult<'a, L> {
|
||||
if let token::Interpolated(inner) = &self.token.kind {
|
||||
let expr = match inner.as_ref() {
|
||||
token::NtExpr(expr) => Some(expr),
|
||||
token::NtLiteral(expr) => Some(expr),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(expr) = expr {
|
||||
if matches!(expr.kind, ExprKind::Err) {
|
||||
let mut err = errors::InvalidInterpolatedExpression { span: self.token.span }
|
||||
.into_diagnostic(&self.sess.span_diagnostic);
|
||||
err.downgrade_to_delayed_bug();
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
if let token::Interpolated(nt) = &self.token.kind
|
||||
&& let token::NtExpr(e) | token::NtLiteral(e) = &**nt
|
||||
&& matches!(e.kind, ExprKind::Err)
|
||||
{
|
||||
let mut err = errors::InvalidInterpolatedExpression { span: self.token.span }
|
||||
.into_diagnostic(&self.sess.span_diagnostic);
|
||||
err.downgrade_to_delayed_bug();
|
||||
return Err(err);
|
||||
}
|
||||
let token = self.token.clone();
|
||||
let err = |self_: &Self| {
|
||||
|
@ -423,13 +423,17 @@ fn import_dummy_binding(&mut self, import: &'a Import<'a>) {
|
||||
/// Resolves all imports for the crate. This method performs the fixed-
|
||||
/// point iteration.
|
||||
pub(crate) fn resolve_imports(&mut self) {
|
||||
let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1;
|
||||
while self.indeterminate_imports.len() < prev_num_indeterminates {
|
||||
prev_num_indeterminates = self.indeterminate_imports.len();
|
||||
let mut prev_indeterminate_count = usize::MAX;
|
||||
let mut indeterminate_count = self.indeterminate_imports.len() * 3;
|
||||
while indeterminate_count < prev_indeterminate_count {
|
||||
prev_indeterminate_count = indeterminate_count;
|
||||
indeterminate_count = 0;
|
||||
for import in mem::take(&mut self.indeterminate_imports) {
|
||||
match self.resolve_import(&import) {
|
||||
true => self.determined_imports.push(import),
|
||||
false => self.indeterminate_imports.push(import),
|
||||
let import_indeterminate_count = self.resolve_import(&import);
|
||||
indeterminate_count += import_indeterminate_count;
|
||||
match import_indeterminate_count {
|
||||
0 => self.determined_imports.push(import),
|
||||
_ => self.indeterminate_imports.push(import),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -581,9 +585,13 @@ fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImpo
|
||||
diag.emit();
|
||||
}
|
||||
|
||||
/// Attempts to resolve the given import, returning true if its resolution is determined.
|
||||
/// If successful, the resolved bindings are written into the module.
|
||||
fn resolve_import(&mut self, import: &'a Import<'a>) -> bool {
|
||||
/// Attempts to resolve the given import, returning:
|
||||
/// - `0` means its resolution is determined.
|
||||
/// - Other values mean that indeterminate exists under certain namespaces.
|
||||
///
|
||||
/// Meanwhile, if resolve successful, the resolved bindings are written
|
||||
/// into the module.
|
||||
fn resolve_import(&mut self, import: &'a Import<'a>) -> usize {
|
||||
debug!(
|
||||
"(resolving import for module) resolving import `{}::...` in `{}`",
|
||||
Segment::names_to_string(&import.module_path),
|
||||
@ -601,8 +609,8 @@ fn resolve_import(&mut self, import: &'a Import<'a>) -> bool {
|
||||
|
||||
match path_res {
|
||||
PathResult::Module(module) => module,
|
||||
PathResult::Indeterminate => return false,
|
||||
PathResult::NonModule(..) | PathResult::Failed { .. } => return true,
|
||||
PathResult::Indeterminate => return 3,
|
||||
PathResult::NonModule(..) | PathResult::Failed { .. } => return 0,
|
||||
}
|
||||
};
|
||||
|
||||
@ -618,12 +626,12 @@ fn resolve_import(&mut self, import: &'a Import<'a>) -> bool {
|
||||
} => (source, target, source_bindings, target_bindings, type_ns_only),
|
||||
ImportKind::Glob { .. } => {
|
||||
self.resolve_glob_import(import);
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let mut indeterminate = false;
|
||||
let mut indeterminate_count = 0;
|
||||
self.per_ns(|this, ns| {
|
||||
if !type_ns_only || ns == TypeNS {
|
||||
if let Err(Undetermined) = source_bindings[ns].get() {
|
||||
@ -646,7 +654,7 @@ fn resolve_import(&mut self, import: &'a Import<'a>) -> bool {
|
||||
|
||||
let parent = import.parent_scope.module;
|
||||
match source_bindings[ns].get() {
|
||||
Err(Undetermined) => indeterminate = true,
|
||||
Err(Undetermined) => indeterminate_count += 1,
|
||||
// Don't update the resolution, because it was never added.
|
||||
Err(Determined) if target.name == kw::Underscore => {}
|
||||
Ok(binding) if binding.is_importable() => {
|
||||
@ -670,7 +678,7 @@ fn resolve_import(&mut self, import: &'a Import<'a>) -> bool {
|
||||
}
|
||||
});
|
||||
|
||||
!indeterminate
|
||||
indeterminate_count
|
||||
}
|
||||
|
||||
/// Performs final import resolution, consistency checks and error reporting.
|
||||
|
@ -189,12 +189,28 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
||||
goal_kind: ty::ClosureKind,
|
||||
) -> Result<Option<ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>)>>, NoSolution> {
|
||||
match *self_ty.kind() {
|
||||
ty::FnDef(def_id, substs) => Ok(Some(
|
||||
tcx.fn_sig(def_id)
|
||||
.subst(tcx, substs)
|
||||
.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())),
|
||||
)),
|
||||
ty::FnPtr(sig) => Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())))),
|
||||
// keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
|
||||
ty::FnDef(def_id, substs) => {
|
||||
let sig = tcx.fn_sig(def_id);
|
||||
if sig.skip_binder().is_fn_trait_compatible()
|
||||
&& tcx.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
{
|
||||
Ok(Some(
|
||||
sig.subst(tcx, substs)
|
||||
.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())),
|
||||
))
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
}
|
||||
// keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
|
||||
ty::FnPtr(sig) => {
|
||||
if sig.is_fn_trait_compatible() {
|
||||
Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output()))))
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
}
|
||||
ty::Closure(_, substs) => {
|
||||
let closure_substs = substs.as_closure();
|
||||
match closure_substs.kind_ty().to_opt_closure_kind() {
|
||||
|
@ -420,6 +420,7 @@ fn suggest_restriction<'tcx>(
|
||||
) {
|
||||
if hir_generics.where_clause_span.from_expansion()
|
||||
|| hir_generics.where_clause_span.desugaring_kind().is_some()
|
||||
|| projection.map_or(false, |projection| tcx.opt_rpitit_info(projection.def_id).is_some())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
|
||||
use rustc_middle::ty::fast_reject::TreatProjections;
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::traits;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
@ -291,6 +290,9 @@ fn assemble_fn_pointer_candidates(
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep this funtion in sync with extract_tupled_inputs_and_output_from_callable
|
||||
// until the old solver (and thus this function) is removed.
|
||||
|
||||
// Okay to skip binder because what we are inspecting doesn't involve bound regions.
|
||||
let self_ty = obligation.self_ty().skip_binder();
|
||||
match *self_ty.kind() {
|
||||
@ -299,31 +301,19 @@ fn assemble_fn_pointer_candidates(
|
||||
candidates.ambiguous = true; // Could wind up being a fn() type.
|
||||
}
|
||||
// Provide an impl, but only for suitable `fn` pointers.
|
||||
ty::FnPtr(_) => {
|
||||
if let ty::FnSig {
|
||||
unsafety: hir::Unsafety::Normal,
|
||||
abi: Abi::Rust,
|
||||
c_variadic: false,
|
||||
..
|
||||
} = self_ty.fn_sig(self.tcx()).skip_binder()
|
||||
{
|
||||
ty::FnPtr(sig) => {
|
||||
if sig.is_fn_trait_compatible() {
|
||||
candidates.vec.push(FnPointerCandidate { is_const: false });
|
||||
}
|
||||
}
|
||||
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
|
||||
ty::FnDef(def_id, _) => {
|
||||
if let ty::FnSig {
|
||||
unsafety: hir::Unsafety::Normal,
|
||||
abi: Abi::Rust,
|
||||
c_variadic: false,
|
||||
..
|
||||
} = self_ty.fn_sig(self.tcx()).skip_binder()
|
||||
if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible()
|
||||
&& self.tcx().codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
{
|
||||
if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() {
|
||||
candidates
|
||||
.vec
|
||||
.push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
|
||||
}
|
||||
candidates
|
||||
.vec
|
||||
.push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -22,7 +22,7 @@
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{error_code, DelayDm, Diagnostic};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{InternalSubsts, SubstsRef};
|
||||
use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
|
||||
use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
|
||||
@ -350,6 +350,10 @@ fn decorate<'tcx>(
|
||||
impl_span: Span,
|
||||
err: &mut Diagnostic,
|
||||
) {
|
||||
if (overlap.trait_ref, overlap.self_ty).references_error() {
|
||||
err.downgrade_to_delayed_bug();
|
||||
}
|
||||
|
||||
match tcx.span_of_impl(overlap.with_impl) {
|
||||
Ok(span) => {
|
||||
err.span_label(span, "first implementation here");
|
||||
|
@ -25,7 +25,8 @@ struct Slot<T> {
|
||||
/// The current stamp.
|
||||
stamp: AtomicUsize,
|
||||
|
||||
/// The message in this slot.
|
||||
/// The message in this slot. Either read out in `read` or dropped through
|
||||
/// `discard_all_messages`.
|
||||
msg: UnsafeCell<MaybeUninit<T>>,
|
||||
}
|
||||
|
||||
@ -439,14 +440,13 @@ pub(crate) fn capacity(&self) -> Option<usize> {
|
||||
Some(self.cap)
|
||||
}
|
||||
|
||||
/// Disconnects the channel and wakes up all blocked senders and receivers.
|
||||
/// Disconnects senders and wakes up all blocked receivers.
|
||||
///
|
||||
/// Returns `true` if this call disconnected the channel.
|
||||
pub(crate) fn disconnect(&self) -> bool {
|
||||
pub(crate) fn disconnect_senders(&self) -> bool {
|
||||
let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst);
|
||||
|
||||
if tail & self.mark_bit == 0 {
|
||||
self.senders.disconnect();
|
||||
self.receivers.disconnect();
|
||||
true
|
||||
} else {
|
||||
@ -454,6 +454,85 @@ pub(crate) fn disconnect(&self) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Disconnects receivers and wakes up all blocked senders.
|
||||
///
|
||||
/// Returns `true` if this call disconnected the channel.
|
||||
///
|
||||
/// # Safety
|
||||
/// May only be called once upon dropping the last receiver. The
|
||||
/// destruction of all other receivers must have been observed with acquire
|
||||
/// ordering or stronger.
|
||||
pub(crate) unsafe fn disconnect_receivers(&self) -> bool {
|
||||
let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst);
|
||||
let disconnected = if tail & self.mark_bit == 0 {
|
||||
self.senders.disconnect();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
self.discard_all_messages(tail);
|
||||
disconnected
|
||||
}
|
||||
|
||||
/// Discards all messages.
|
||||
///
|
||||
/// `tail` should be the current (and therefore last) value of `tail`.
|
||||
///
|
||||
/// # Panicking
|
||||
/// If a destructor panics, the remaining messages are leaked, matching the
|
||||
/// behaviour of the unbounded channel.
|
||||
///
|
||||
/// # Safety
|
||||
/// This method must only be called when dropping the last receiver. The
|
||||
/// destruction of all other receivers must have been observed with acquire
|
||||
/// ordering or stronger.
|
||||
unsafe fn discard_all_messages(&self, tail: usize) {
|
||||
debug_assert!(self.is_disconnected());
|
||||
|
||||
// Only receivers modify `head`, so since we are the last one,
|
||||
// this value will not change and will not be observed (since
|
||||
// no new messages can be sent after disconnection).
|
||||
let mut head = self.head.load(Ordering::Relaxed);
|
||||
let tail = tail & !self.mark_bit;
|
||||
|
||||
let backoff = Backoff::new();
|
||||
loop {
|
||||
// Deconstruct the head.
|
||||
let index = head & (self.mark_bit - 1);
|
||||
let lap = head & !(self.one_lap - 1);
|
||||
|
||||
// Inspect the corresponding slot.
|
||||
debug_assert!(index < self.buffer.len());
|
||||
let slot = unsafe { self.buffer.get_unchecked(index) };
|
||||
let stamp = slot.stamp.load(Ordering::Acquire);
|
||||
|
||||
// If the stamp is ahead of the head by 1, we may drop the message.
|
||||
if head + 1 == stamp {
|
||||
head = if index + 1 < self.cap {
|
||||
// Same lap, incremented index.
|
||||
// Set to `{ lap: lap, mark: 0, index: index + 1 }`.
|
||||
head + 1
|
||||
} else {
|
||||
// One lap forward, index wraps around to zero.
|
||||
// Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`.
|
||||
lap.wrapping_add(self.one_lap)
|
||||
};
|
||||
|
||||
unsafe {
|
||||
(*slot.msg.get()).assume_init_drop();
|
||||
}
|
||||
// If the tail equals the head, that means the channel is empty.
|
||||
} else if tail == head {
|
||||
return;
|
||||
// Otherwise, a sender is about to write into the slot, so we need
|
||||
// to wait for it to update the stamp.
|
||||
} else {
|
||||
backoff.spin_heavy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is disconnected.
|
||||
pub(crate) fn is_disconnected(&self) -> bool {
|
||||
self.tail.load(Ordering::SeqCst) & self.mark_bit != 0
|
||||
@ -483,23 +562,3 @@ pub(crate) fn is_full(&self) -> bool {
|
||||
head.wrapping_add(self.one_lap) == tail & !self.mark_bit
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for Channel<T> {
|
||||
fn drop(&mut self) {
|
||||
// Get the index of the head.
|
||||
let hix = self.head.load(Ordering::Relaxed) & (self.mark_bit - 1);
|
||||
|
||||
// Loop over all slots that hold a message and drop them.
|
||||
for i in 0..self.len() {
|
||||
// Compute the index of the next slot holding a message.
|
||||
let index = if hix + i < self.cap { hix + i } else { hix + i - self.cap };
|
||||
|
||||
unsafe {
|
||||
debug_assert!(index < self.buffer.len());
|
||||
let slot = self.buffer.get_unchecked_mut(index);
|
||||
let msg = &mut *slot.msg.get();
|
||||
msg.as_mut_ptr().drop_in_place();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ impl<T> Drop for Sender<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
match &self.flavor {
|
||||
SenderFlavor::Array(chan) => chan.release(|c| c.disconnect()),
|
||||
SenderFlavor::Array(chan) => chan.release(|c| c.disconnect_senders()),
|
||||
SenderFlavor::List(chan) => chan.release(|c| c.disconnect_senders()),
|
||||
SenderFlavor::Zero(chan) => chan.release(|c| c.disconnect()),
|
||||
}
|
||||
@ -403,7 +403,7 @@ impl<T> Drop for Receiver<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
match &self.flavor {
|
||||
ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect()),
|
||||
ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect_receivers()),
|
||||
ReceiverFlavor::List(chan) => chan.release(|c| c.disconnect_receivers()),
|
||||
ReceiverFlavor::Zero(chan) => chan.release(|c| c.disconnect()),
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::*;
|
||||
use crate::env;
|
||||
use crate::rc::Rc;
|
||||
use crate::sync::mpmc::SendTimeoutError;
|
||||
use crate::thread;
|
||||
use crate::time::Duration;
|
||||
@ -656,3 +657,15 @@ fn repro() {
|
||||
repro()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_unreceived() {
|
||||
let (tx, rx) = sync_channel::<Rc<()>>(1);
|
||||
let msg = Rc::new(());
|
||||
let weak = Rc::downgrade(&msg);
|
||||
assert!(tx.send(msg).is_ok());
|
||||
drop(rx);
|
||||
// Messages should be dropped immediately when the last receiver is destroyed.
|
||||
assert!(weak.upgrade().is_none());
|
||||
drop(tx);
|
||||
}
|
||||
|
@ -11,10 +11,11 @@
|
||||
use crate::io;
|
||||
use crate::num::NonZeroU16;
|
||||
use crate::os::windows::prelude::*;
|
||||
use crate::path::PathBuf;
|
||||
use crate::sys::c;
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::sys::path::get_long_path;
|
||||
use crate::sys::process::ensure_no_nuls;
|
||||
use crate::sys::windows::os::current_exe;
|
||||
use crate::sys::{c, to_u16s};
|
||||
use crate::sys_common::wstr::WStrUnits;
|
||||
use crate::vec;
|
||||
|
||||
@ -311,7 +312,7 @@ pub(crate) fn make_bat_command_line(
|
||||
/// Takes a path and tries to return a non-verbatim path.
|
||||
///
|
||||
/// This is necessary because cmd.exe does not support verbatim paths.
|
||||
pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
|
||||
pub(crate) fn to_user_path(path: &Path) -> io::Result<Vec<u16>> {
|
||||
use crate::ptr;
|
||||
use crate::sys::windows::fill_utf16_buf;
|
||||
|
||||
@ -324,6 +325,8 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
|
||||
const N: u16 = b'N' as _;
|
||||
const C: u16 = b'C' as _;
|
||||
|
||||
let mut path = to_u16s(path)?;
|
||||
|
||||
// Early return if the path is too long to remove the verbatim prefix.
|
||||
const LEGACY_MAX_PATH: usize = 260;
|
||||
if path.len() > LEGACY_MAX_PATH {
|
||||
@ -337,7 +340,13 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
|
||||
fill_utf16_buf(
|
||||
|buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()),
|
||||
|full_path: &[u16]| {
|
||||
if full_path == &path[4..path.len() - 1] { full_path.into() } else { path }
|
||||
if full_path == &path[4..path.len() - 1] {
|
||||
let mut path: Vec<u16> = full_path.into();
|
||||
path.push(0);
|
||||
path
|
||||
} else {
|
||||
path
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
@ -350,7 +359,9 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
|
||||
|buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()),
|
||||
|full_path: &[u16]| {
|
||||
if full_path == &path[6..path.len() - 1] {
|
||||
full_path.into()
|
||||
let mut path: Vec<u16> = full_path.into();
|
||||
path.push(0);
|
||||
path
|
||||
} else {
|
||||
// Restore the 'C' in "UNC".
|
||||
path[6] = b'C' as u16;
|
||||
@ -360,6 +371,6 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
|
||||
)
|
||||
},
|
||||
// For everything else, leave the path unchanged.
|
||||
_ => Ok(path),
|
||||
_ => get_long_path(path, false),
|
||||
}
|
||||
}
|
||||
|
@ -220,6 +220,19 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
|
||||
///
|
||||
/// This path may or may not have a verbatim prefix.
|
||||
pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
|
||||
let path = to_u16s(path)?;
|
||||
get_long_path(path, true)
|
||||
}
|
||||
|
||||
/// Get a normalized absolute path that can bypass path length limits.
|
||||
///
|
||||
/// Setting prefer_verbatim to true suggests a stronger preference for verbatim
|
||||
/// paths even when not strictly necessary. This allows the Windows API to avoid
|
||||
/// repeating our work. However, if the path may be given back to users or
|
||||
/// passed to other application then it's preferable to use non-verbatim paths
|
||||
/// when possible. Non-verbatim paths are better understood by users and handled
|
||||
/// by more software.
|
||||
pub(crate) fn get_long_path(mut path: Vec<u16>, prefer_verbatim: bool) -> io::Result<Vec<u16>> {
|
||||
// Normally the MAX_PATH is 260 UTF-16 code units (including the NULL).
|
||||
// However, for APIs such as CreateDirectory[1], the limit is 248.
|
||||
//
|
||||
@ -243,7 +256,6 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
|
||||
// \\?\UNC\
|
||||
const UNC_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP, U, N, C, SEP];
|
||||
|
||||
let mut path = to_u16s(path)?;
|
||||
if path.starts_with(VERBATIM_PREFIX) || path.starts_with(NT_PREFIX) || path == &[0] {
|
||||
// Early return for paths that are already verbatim or empty.
|
||||
return Ok(path);
|
||||
@ -275,29 +287,34 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
|
||||
|mut absolute| {
|
||||
path.clear();
|
||||
|
||||
// Secondly, add the verbatim prefix. This is easier here because we know the
|
||||
// path is now absolute and fully normalized (e.g. `/` has been changed to `\`).
|
||||
let prefix = match absolute {
|
||||
// C:\ => \\?\C:\
|
||||
[_, COLON, SEP, ..] => VERBATIM_PREFIX,
|
||||
// \\.\ => \\?\
|
||||
[SEP, SEP, DOT, SEP, ..] => {
|
||||
absolute = &absolute[4..];
|
||||
VERBATIM_PREFIX
|
||||
}
|
||||
// Leave \\?\ and \??\ as-is.
|
||||
[SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[],
|
||||
// \\ => \\?\UNC\
|
||||
[SEP, SEP, ..] => {
|
||||
absolute = &absolute[2..];
|
||||
UNC_PREFIX
|
||||
}
|
||||
// Anything else we leave alone.
|
||||
_ => &[],
|
||||
};
|
||||
// Only prepend the prefix if needed.
|
||||
if prefer_verbatim || absolute.len() + 1 >= LEGACY_MAX_PATH {
|
||||
// Secondly, add the verbatim prefix. This is easier here because we know the
|
||||
// path is now absolute and fully normalized (e.g. `/` has been changed to `\`).
|
||||
let prefix = match absolute {
|
||||
// C:\ => \\?\C:\
|
||||
[_, COLON, SEP, ..] => VERBATIM_PREFIX,
|
||||
// \\.\ => \\?\
|
||||
[SEP, SEP, DOT, SEP, ..] => {
|
||||
absolute = &absolute[4..];
|
||||
VERBATIM_PREFIX
|
||||
}
|
||||
// Leave \\?\ and \??\ as-is.
|
||||
[SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[],
|
||||
// \\ => \\?\UNC\
|
||||
[SEP, SEP, ..] => {
|
||||
absolute = &absolute[2..];
|
||||
UNC_PREFIX
|
||||
}
|
||||
// Anything else we leave alone.
|
||||
_ => &[],
|
||||
};
|
||||
|
||||
path.reserve_exact(prefix.len() + absolute.len() + 1);
|
||||
path.extend_from_slice(prefix);
|
||||
path.reserve_exact(prefix.len() + absolute.len() + 1);
|
||||
path.extend_from_slice(prefix);
|
||||
} else {
|
||||
path.reserve_exact(absolute.len() + 1);
|
||||
}
|
||||
path.extend_from_slice(absolute);
|
||||
path.push(0);
|
||||
},
|
||||
|
@ -266,11 +266,7 @@ pub fn spawn(
|
||||
let (program, mut cmd_str) = if is_batch_file {
|
||||
(
|
||||
command_prompt()?,
|
||||
args::make_bat_command_line(
|
||||
&args::to_user_path(program)?,
|
||||
&self.args,
|
||||
self.force_quotes_enabled,
|
||||
)?,
|
||||
args::make_bat_command_line(&program, &self.args, self.force_quotes_enabled)?,
|
||||
)
|
||||
} else {
|
||||
let cmd_str = make_command_line(&self.program, &self.args, self.force_quotes_enabled)?;
|
||||
@ -410,7 +406,7 @@ fn resolve_exe<'a>(
|
||||
if has_exe_suffix {
|
||||
// The application name is a path to a `.exe` file.
|
||||
// Let `CreateProcessW` figure out if it exists or not.
|
||||
return path::maybe_verbatim(Path::new(exe_path));
|
||||
return args::to_user_path(Path::new(exe_path));
|
||||
}
|
||||
let mut path = PathBuf::from(exe_path);
|
||||
|
||||
@ -422,7 +418,7 @@ fn resolve_exe<'a>(
|
||||
// It's ok to use `set_extension` here because the intent is to
|
||||
// remove the extension that was just added.
|
||||
path.set_extension("");
|
||||
return path::maybe_verbatim(&path);
|
||||
return args::to_user_path(&path);
|
||||
}
|
||||
} else {
|
||||
ensure_no_nuls(exe_path)?;
|
||||
@ -510,7 +506,7 @@ fn search_paths<Paths, Exists>(
|
||||
/// Check if a file exists without following symlinks.
|
||||
fn program_exists(path: &Path) -> Option<Vec<u16>> {
|
||||
unsafe {
|
||||
let path = path::maybe_verbatim(path).ok()?;
|
||||
let path = args::to_user_path(path).ok()?;
|
||||
// Getting attributes using `GetFileAttributesW` does not follow symlinks
|
||||
// and it will almost always be successful if the link exists.
|
||||
// There are some exceptions for special system files (e.g. the pagefile)
|
||||
|
@ -1,5 +1,5 @@
|
||||
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/missing-send-bound.rs:3:12
|
||||
--> $DIR/missing-send-bound.rs:5:12
|
||||
|
|
||||
LL | #![feature(async_fn_in_trait)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
@ -8,19 +8,19 @@ LL | #![feature(async_fn_in_trait)]
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: future cannot be sent between threads safely
|
||||
--> $DIR/missing-send-bound.rs:15:20
|
||||
--> $DIR/missing-send-bound.rs:17:20
|
||||
|
|
||||
LL | assert_is_send(test::<T>());
|
||||
| ^^^^^^^^^^^ future returned by `test` is not `Send`
|
||||
|
|
||||
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>`
|
||||
note: future is not `Send` as it awaits another future which is not `Send`
|
||||
--> $DIR/missing-send-bound.rs:11:5
|
||||
--> $DIR/missing-send-bound.rs:13:5
|
||||
|
|
||||
LL | T::bar().await;
|
||||
| ^^^^^^^^ await occurs here on type `impl Future<Output = ()>`, which is not `Send`
|
||||
note: required by a bound in `assert_is_send`
|
||||
--> $DIR/missing-send-bound.rs:19:27
|
||||
--> $DIR/missing-send-bound.rs:21:27
|
||||
|
|
||||
LL | fn assert_is_send(_: impl Send) {}
|
||||
| ^^^^ required by this bound in `assert_is_send`
|
29
tests/ui/async-await/in-trait/missing-send-bound.next.stderr
Normal file
29
tests/ui/async-await/in-trait/missing-send-bound.next.stderr
Normal file
@ -0,0 +1,29 @@
|
||||
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/missing-send-bound.rs:5:12
|
||||
|
|
||||
LL | #![feature(async_fn_in_trait)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: future cannot be sent between threads safely
|
||||
--> $DIR/missing-send-bound.rs:17:20
|
||||
|
|
||||
LL | assert_is_send(test::<T>());
|
||||
| ^^^^^^^^^^^ future returned by `test` is not `Send`
|
||||
|
|
||||
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>`
|
||||
note: future is not `Send` as it awaits another future which is not `Send`
|
||||
--> $DIR/missing-send-bound.rs:13:5
|
||||
|
|
||||
LL | T::bar().await;
|
||||
| ^^^^^^^^ await occurs here on type `impl Future<Output = ()>`, which is not `Send`
|
||||
note: required by a bound in `assert_is_send`
|
||||
--> $DIR/missing-send-bound.rs:21:27
|
||||
|
|
||||
LL | fn assert_is_send(_: impl Send) {}
|
||||
| ^^^^ required by this bound in `assert_is_send`
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
@ -1,4 +1,6 @@
|
||||
// edition:2021
|
||||
// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
|
||||
// revisions: current next
|
||||
|
||||
#![feature(async_fn_in_trait)]
|
||||
//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
|
13
tests/ui/const-generics/bad-subst-const-kind.rs
Normal file
13
tests/ui/const-generics/bad-subst-const-kind.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// incremental
|
||||
#![crate_type = "lib"]
|
||||
|
||||
trait Q {
|
||||
const ASSOC: usize;
|
||||
}
|
||||
|
||||
impl<const N: u64> Q for [u8; N] {
|
||||
//~^ ERROR mismatched types
|
||||
const ASSOC: usize = 1;
|
||||
}
|
||||
|
||||
pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() }
|
9
tests/ui/const-generics/bad-subst-const-kind.stderr
Normal file
9
tests/ui/const-generics/bad-subst-const-kind.stderr
Normal file
@ -0,0 +1,9 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/bad-subst-const-kind.rs:8:31
|
||||
|
|
||||
LL | impl<const N: u64> Q for [u8; N] {
|
||||
| ^ expected `usize`, found `u64`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
83
tests/ui/macros/nested-use-as.rs
Normal file
83
tests/ui/macros/nested-use-as.rs
Normal file
@ -0,0 +1,83 @@
|
||||
// check-pass
|
||||
// edition:2018
|
||||
// issue: https://github.com/rust-lang/rust/issues/97534
|
||||
|
||||
macro_rules! m {
|
||||
() => {
|
||||
macro_rules! foo {
|
||||
() => {}
|
||||
}
|
||||
use foo as bar;
|
||||
}
|
||||
}
|
||||
|
||||
m!{}
|
||||
|
||||
use bar as baz;
|
||||
|
||||
baz!{}
|
||||
|
||||
macro_rules! foo2 {
|
||||
() => {};
|
||||
}
|
||||
|
||||
macro_rules! m2 {
|
||||
() => {
|
||||
use foo2 as bar2;
|
||||
};
|
||||
}
|
||||
|
||||
m2! {}
|
||||
|
||||
use bar2 as baz2;
|
||||
|
||||
baz2! {}
|
||||
|
||||
macro_rules! n1 {
|
||||
() => {
|
||||
macro_rules! n2 {
|
||||
() => {
|
||||
macro_rules! n3 {
|
||||
() => {
|
||||
macro_rules! n4 {
|
||||
() => {}
|
||||
}
|
||||
use n4 as c4;
|
||||
}
|
||||
}
|
||||
use n3 as c3;
|
||||
}
|
||||
}
|
||||
use n2 as c2;
|
||||
}
|
||||
}
|
||||
|
||||
use n1 as c1;
|
||||
c1!{}
|
||||
use c2 as a2;
|
||||
a2!{}
|
||||
use c3 as a3;
|
||||
a3!{}
|
||||
use c4 as a4;
|
||||
a4!{}
|
||||
|
||||
// https://github.com/rust-lang/rust/pull/108729#issuecomment-1474750675
|
||||
// reversed
|
||||
use d5 as d6;
|
||||
use d4 as d5;
|
||||
use d3 as d4;
|
||||
use d2 as d3;
|
||||
use d1 as d2;
|
||||
use foo2 as d1;
|
||||
d6! {}
|
||||
|
||||
// mess
|
||||
use f3 as f4;
|
||||
f5! {}
|
||||
use f1 as f2;
|
||||
use f4 as f5;
|
||||
use f2 as f3;
|
||||
use foo2 as f1;
|
||||
|
||||
fn main() {
|
||||
}
|
@ -2,11 +2,11 @@
|
||||
|
||||
// An impl that has an erroneous const substitution should not specialize one
|
||||
// that is well-formed.
|
||||
|
||||
#[derive(Clone)]
|
||||
struct S<const L: usize>;
|
||||
|
||||
impl<const N: i32> Copy for S<N> {}
|
||||
//~^ ERROR the constant `N` is not of type `usize`
|
||||
impl<const M: usize> Copy for S<M> {}
|
||||
//~^ ERROR conflicting implementations of trait `Copy` for type `S<_>`
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,11 +1,14 @@
|
||||
error[E0119]: conflicting implementations of trait `Copy` for type `S<_>`
|
||||
--> $DIR/bad-const-wf-doesnt-specialize.rs:9:1
|
||||
error: the constant `N` is not of type `usize`
|
||||
--> $DIR/bad-const-wf-doesnt-specialize.rs:8:29
|
||||
|
|
||||
LL | impl<const N: i32> Copy for S<N> {}
|
||||
| -------------------------------- first implementation here
|
||||
LL | impl<const M: usize> Copy for S<M> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>`
|
||||
| ^^^^
|
||||
|
|
||||
note: required by a bound in `S`
|
||||
--> $DIR/bad-const-wf-doesnt-specialize.rs:6:10
|
||||
|
|
||||
LL | struct S<const L: usize>;
|
||||
| ^^^^^^^^^^^^^^ required by this bound in `S`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
||||
|
12
tests/ui/suggestions/issue-109396.rs
Normal file
12
tests/ui/suggestions/issue-109396.rs
Normal file
@ -0,0 +1,12 @@
|
||||
fn main() {
|
||||
{
|
||||
let mut mutex = std::mem::zeroed(
|
||||
//~^ ERROR this function takes 0 arguments but 4 arguments were supplied
|
||||
file.as_raw_fd(),
|
||||
//~^ ERROR expected value, found macro `file`
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
34
tests/ui/suggestions/issue-109396.stderr
Normal file
34
tests/ui/suggestions/issue-109396.stderr
Normal file
@ -0,0 +1,34 @@
|
||||
error[E0423]: expected value, found macro `file`
|
||||
--> $DIR/issue-109396.rs:5:13
|
||||
|
|
||||
LL | file.as_raw_fd(),
|
||||
| ^^^^ not a value
|
||||
|
||||
error[E0061]: this function takes 0 arguments but 4 arguments were supplied
|
||||
--> $DIR/issue-109396.rs:3:25
|
||||
|
|
||||
LL | let mut mutex = std::mem::zeroed(
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | file.as_raw_fd(),
|
||||
| ---------------- unexpected argument
|
||||
LL |
|
||||
LL | 0,
|
||||
| - unexpected argument of type `{integer}`
|
||||
LL | 0,
|
||||
| - unexpected argument of type `{integer}`
|
||||
LL | 0,
|
||||
| - unexpected argument of type `{integer}`
|
||||
|
|
||||
note: function defined here
|
||||
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
||||
help: remove the extra arguments
|
||||
|
|
||||
LL - file.as_raw_fd(),
|
||||
LL + ,
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0061, E0423.
|
||||
For more information about an error, try `rustc --explain E0061`.
|
@ -1,5 +1,4 @@
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
// check-pass
|
||||
|
||||
fn require_fn(_: impl Fn() -> i32) {}
|
||||
|
||||
@ -7,7 +6,27 @@ fn f() -> i32 {
|
||||
1i32
|
||||
}
|
||||
|
||||
extern "C" fn g() -> i32 {
|
||||
2i32
|
||||
}
|
||||
|
||||
unsafe fn h() -> i32 {
|
||||
2i32
|
||||
}
|
||||
|
||||
fn main() {
|
||||
require_fn(f);
|
||||
require_fn(f as fn() -> i32);
|
||||
require_fn(f as unsafe fn() -> i32);
|
||||
//~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32`
|
||||
//~| ERROR: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32`
|
||||
require_fn(g);
|
||||
//~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}`
|
||||
//~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 {g} as FnOnce<()>>::Output == i32`
|
||||
require_fn(g as extern "C" fn() -> i32);
|
||||
//~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32`
|
||||
//~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32`
|
||||
require_fn(h);
|
||||
//~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}`
|
||||
//~| ERROR: type mismatch resolving `<unsafe fn() -> i32 {h} as FnOnce<()>>::Output == i32`
|
||||
}
|
||||
|
124
tests/ui/traits/new-solver/fn-trait.stderr
Normal file
124
tests/ui/traits/new-solver/fn-trait.stderr
Normal file
@ -0,0 +1,124 @@
|
||||
error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32`
|
||||
--> $DIR/fn-trait.rs:20:16
|
||||
|
|
||||
LL | require_fn(f as unsafe fn() -> i32);
|
||||
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `Fn<()>` is not implemented for `unsafe fn() -> i32`
|
||||
= note: wrap the `unsafe fn() -> i32` in a closure with no arguments: `|| { /* code */ }`
|
||||
note: required by a bound in `require_fn`
|
||||
--> $DIR/fn-trait.rs:3:23
|
||||
|
|
||||
LL | fn require_fn(_: impl Fn() -> i32) {}
|
||||
| ^^^^^^^^^^^ required by this bound in `require_fn`
|
||||
|
||||
error[E0271]: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32`
|
||||
--> $DIR/fn-trait.rs:20:16
|
||||
|
|
||||
LL | require_fn(f as unsafe fn() -> i32);
|
||||
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^ types differ
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `require_fn`
|
||||
--> $DIR/fn-trait.rs:3:31
|
||||
|
|
||||
LL | fn require_fn(_: impl Fn() -> i32) {}
|
||||
| ^^^ required by this bound in `require_fn`
|
||||
|
||||
error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}`
|
||||
--> $DIR/fn-trait.rs:23:16
|
||||
|
|
||||
LL | require_fn(g);
|
||||
| ---------- ^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32 {g}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `Fn<()>` is not implemented for fn item `extern "C" fn() -> i32 {g}`
|
||||
= note: wrap the `extern "C" fn() -> i32 {g}` in a closure with no arguments: `|| { /* code */ }`
|
||||
note: required by a bound in `require_fn`
|
||||
--> $DIR/fn-trait.rs:3:23
|
||||
|
|
||||
LL | fn require_fn(_: impl Fn() -> i32) {}
|
||||
| ^^^^^^^^^^^ required by this bound in `require_fn`
|
||||
|
||||
error[E0271]: type mismatch resolving `<extern "C" fn() -> i32 {g} as FnOnce<()>>::Output == i32`
|
||||
--> $DIR/fn-trait.rs:23:16
|
||||
|
|
||||
LL | require_fn(g);
|
||||
| ---------- ^ types differ
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `require_fn`
|
||||
--> $DIR/fn-trait.rs:3:31
|
||||
|
|
||||
LL | fn require_fn(_: impl Fn() -> i32) {}
|
||||
| ^^^ required by this bound in `require_fn`
|
||||
|
||||
error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32`
|
||||
--> $DIR/fn-trait.rs:26:16
|
||||
|
|
||||
LL | require_fn(g as extern "C" fn() -> i32);
|
||||
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `Fn<()>` is not implemented for `extern "C" fn() -> i32`
|
||||
= note: wrap the `extern "C" fn() -> i32` in a closure with no arguments: `|| { /* code */ }`
|
||||
note: required by a bound in `require_fn`
|
||||
--> $DIR/fn-trait.rs:3:23
|
||||
|
|
||||
LL | fn require_fn(_: impl Fn() -> i32) {}
|
||||
| ^^^^^^^^^^^ required by this bound in `require_fn`
|
||||
|
||||
error[E0271]: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32`
|
||||
--> $DIR/fn-trait.rs:26:16
|
||||
|
|
||||
LL | require_fn(g as extern "C" fn() -> i32);
|
||||
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `require_fn`
|
||||
--> $DIR/fn-trait.rs:3:31
|
||||
|
|
||||
LL | fn require_fn(_: impl Fn() -> i32) {}
|
||||
| ^^^ required by this bound in `require_fn`
|
||||
|
||||
error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}`
|
||||
--> $DIR/fn-trait.rs:29:16
|
||||
|
|
||||
LL | require_fn(h);
|
||||
| ---------- ^ call the function in a closure: `|| unsafe { /* code */ }`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() -> i32 {h}`
|
||||
= note: wrap the `unsafe fn() -> i32 {h}` in a closure with no arguments: `|| { /* code */ }`
|
||||
note: required by a bound in `require_fn`
|
||||
--> $DIR/fn-trait.rs:3:23
|
||||
|
|
||||
LL | fn require_fn(_: impl Fn() -> i32) {}
|
||||
| ^^^^^^^^^^^ required by this bound in `require_fn`
|
||||
|
||||
error[E0271]: type mismatch resolving `<unsafe fn() -> i32 {h} as FnOnce<()>>::Output == i32`
|
||||
--> $DIR/fn-trait.rs:29:16
|
||||
|
|
||||
LL | require_fn(h);
|
||||
| ---------- ^ types differ
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `require_fn`
|
||||
--> $DIR/fn-trait.rs:3:31
|
||||
|
|
||||
LL | fn require_fn(_: impl Fn() -> i32) {}
|
||||
| ^^^ required by this bound in `require_fn`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0271, E0277.
|
||||
For more information about an error, try `rustc --explain E0271`.
|
Loading…
Reference in New Issue
Block a user