diff options
42 files changed, 613 insertions, 114 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 8e763a02af3..508903049db 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -21,6 +21,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_infer::infer::{ InferCtxt, InferOk, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin, }; +use rustc_infer::traits::ObligationCause; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::AssertKind; @@ -224,6 +225,26 @@ pub(crate) fn type_check<'mir, 'tcx>( ) .unwrap(); let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); + // Check that RPITs are only constrained in their outermost + // function, otherwise report a mismatched types error. + if let OpaqueTyOrigin::FnReturn(parent) | OpaqueTyOrigin::AsyncFn(parent) + = infcx.opaque_ty_origin_unchecked(opaque_type_key.def_id, hidden_type.span) + && parent.to_def_id() != body.source.def_id() + { + infcx + .report_mismatched_types( + &ObligationCause::misc( + hidden_type.span, + infcx.tcx.hir().local_def_id_to_hir_id( + body.source.def_id().expect_local(), + ), + ), + infcx.tcx.mk_opaque(opaque_type_key.def_id.to_def_id(), opaque_type_key.substs), + hidden_type.ty, + ty::error::TypeError::Mismatch, + ) + .emit(); + } trace!( "finalized opaque type {:?} to {:#?}", opaque_type_key, diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 3db2f822c1c..7b0ff9552a3 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -438,7 +438,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } #[instrument(skip(self), level = "trace")] - fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin { + pub fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin { let origin = match self.tcx.hir().expect_item(def_id).kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin, ref itemkind => { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index a0472f98d72..9e4dc702f07 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2858,9 +2858,10 @@ impl ClashingExternDeclarations { let a_poly_sig = a.fn_sig(tcx); let b_poly_sig = b.fn_sig(tcx); - // As we don't compare regions, skip_binder is fine. - let a_sig = a_poly_sig.skip_binder(); - let b_sig = b_poly_sig.skip_binder(); + // We don't compare regions, but leaving bound regions around ICEs, so + // we erase them. + let a_sig = tcx.erase_late_bound_regions(a_poly_sig); + let b_sig = tcx.erase_late_bound_regions(b_poly_sig); (a_sig.abi, a_sig.unsafety, a_sig.c_variadic) == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 41c38f558b6..e6fa95b91e9 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -31,9 +31,7 @@ use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, Span}; -use rustc_trait_selection::traits::{ - self, ObligationCauseCode, SelectionContext, StatementAsExpression, -}; +use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; use std::iter; use std::slice; @@ -1410,7 +1408,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self.misc(sp), &mut |err| { if let Some(expected_ty) = expected.only_has_type(self) { - self.consider_hint_about_removing_semicolon(blk, expected_ty, err); + if !self.consider_removing_semicolon(blk, expected_ty, err) { + self.consider_returning_binding(blk, expected_ty, err); + } if expected_ty == self.tcx.types.bool { // If this is caused by a missing `let` in a `while let`, // silence this redundant error, as we already emit E0070. @@ -1478,42 +1478,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - /// A common error is to add an extra semicolon: - /// - /// ```compile_fail,E0308 - /// fn foo() -> usize { - /// 22; - /// } - /// ``` - /// - /// This routine checks if the final statement in a block is an - /// expression with an explicit semicolon whose type is compatible - /// with `expected_ty`. If so, it suggests removing the semicolon. - fn consider_hint_about_removing_semicolon( - &self, - blk: &'tcx hir::Block<'tcx>, - expected_ty: Ty<'tcx>, - err: &mut Diagnostic, - ) { - if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) { - if let StatementAsExpression::NeedsBoxing = boxed { - err.span_suggestion_verbose( - span_semi, - "consider removing this semicolon and boxing the expression", - "", - Applicability::HasPlaceholders, - ); - } else { - err.span_suggestion_short( - span_semi, - "remove this semicolon", - "", - Applicability::MachineApplicable, - ); - } - } - } - fn parent_item_span(&self, id: hir::HirId) -> Option<Span> { let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id)); match node { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 80feac18412..d5ee299c0f9 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -3,6 +3,7 @@ use crate::astconv::AstConv; use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel}; use rustc_ast::util::parser::ExprPrecedence; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{Applicability, Diagnostic, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; @@ -11,12 +12,12 @@ use rustc_hir::{ Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate, }; use rustc_infer::infer::{self, TyCtxtInferExt}; -use rustc_infer::traits; +use rustc_infer::traits::{self, StatementAsExpression}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty}; +use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty, TypeVisitable}; use rustc_span::symbol::sym; use rustc_span::Span; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) { @@ -864,4 +865,156 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } + + /// A common error is to add an extra semicolon: + /// + /// ```compile_fail,E0308 + /// fn foo() -> usize { + /// 22; + /// } + /// ``` + /// + /// This routine checks if the final statement in a block is an + /// expression with an explicit semicolon whose type is compatible + /// with `expected_ty`. If so, it suggests removing the semicolon. + pub(crate) fn consider_removing_semicolon( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + err: &mut Diagnostic, + ) -> bool { + if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) { + if let StatementAsExpression::NeedsBoxing = boxed { + err.span_suggestion_verbose( + span_semi, + "consider removing this semicolon and boxing the expression", + "", + Applicability::HasPlaceholders, + ); + } else { + err.span_suggestion_short( + span_semi, + "remove this semicolon", + "", + Applicability::MachineApplicable, + ); + } + true + } else { + false + } + } + + pub(crate) fn consider_returning_binding( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + err: &mut Diagnostic, + ) { + let mut shadowed = FxHashSet::default(); + let mut candidate_idents = vec![]; + let mut find_compatible_candidates = |pat: &hir::Pat<'_>| { + if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind + && let Some(pat_ty) = self.typeck_results.borrow().node_type_opt(*hir_id) + { + let pat_ty = self.resolve_vars_if_possible(pat_ty); + if self.can_coerce(pat_ty, expected_ty) + && !(pat_ty, expected_ty).references_error() + && shadowed.insert(ident.name) + { + candidate_idents.push((*ident, pat_ty)); + } + } + true + }; + + let hir = self.tcx.hir(); + for stmt in blk.stmts.iter().rev() { + let StmtKind::Local(local) = &stmt.kind else { continue; }; + local.pat.walk(&mut find_compatible_candidates); + } + match hir.find(hir.get_parent_node(blk.hir_id)) { + Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => { + match hir.find(hir.get_parent_node(*hir_id)) { + Some(hir::Node::Arm(hir::Arm { pat, .. })) => { + pat.walk(&mut find_compatible_candidates); + } + Some( + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. }) + | hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(_, body), + .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)), + .. + }) + | hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(hir::Closure { body, .. }), + .. + }), + ) => { + for param in hir.body(*body).params { + param.pat.walk(&mut find_compatible_candidates); + } + } + Some(hir::Node::Expr(hir::Expr { + kind: + hir::ExprKind::If( + hir::Expr { kind: hir::ExprKind::Let(let_), .. }, + then_block, + _, + ), + .. + })) if then_block.hir_id == *hir_id => { + let_.pat.walk(&mut find_compatible_candidates); + } + _ => {} + } + } + _ => {} + } + + match &candidate_idents[..] { + [(ident, _ty)] => { + let sm = self.tcx.sess.source_map(); + if let Some(stmt) = blk.stmts.last() { + let stmt_span = sm.stmt_span(stmt.span, blk.span); + let sugg = if sm.is_multiline(blk.span) + && let Some(spacing) = sm.indentation_before(stmt_span) + { + format!("\n{spacing}{ident}") + } else { + format!(" {ident}") + }; + err.span_suggestion_verbose( + stmt_span.shrink_to_hi(), + format!("consider returning the local binding `{ident}`"), + sugg, + Applicability::MachineApplicable, + ); + } else { + let sugg = if sm.is_multiline(blk.span) + && let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo()) + { + format!("\n{spacing} {ident}\n{spacing}") + } else { + format!(" {ident} ") + }; + let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi(); + err.span_suggestion_verbose( + sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span), + format!("consider returning the local binding `{ident}`"), + sugg, + Applicability::MachineApplicable, + ); + } + } + values if (1..3).contains(&values.len()) => { + let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>(); + err.span_note(spans, "consider returning one of these bindings"); + } + _ => {} + } + } } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 147f04a3f12..eb458f3866e 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2612,7 +2612,7 @@ macro_rules! int_impl { /// Create an integer value from its representation as a byte array in /// big endian. /// - #[doc = $to_xe_bytes_doc] + #[doc = $from_xe_bytes_doc] /// /// # Examples /// @@ -2641,7 +2641,7 @@ macro_rules! int_impl { /// Create an integer value from its representation as a byte array in /// little endian. /// - #[doc = $to_xe_bytes_doc] + #[doc = $from_xe_bytes_doc] /// /// # Examples /// @@ -2677,7 +2677,7 @@ macro_rules! int_impl { /// [`from_be_bytes`]: Self::from_be_bytes /// [`from_le_bytes`]: Self::from_le_bytes /// - #[doc = $to_xe_bytes_doc] + #[doc = $from_xe_bytes_doc] /// /// # Examples /// diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index a0297b4b2f5..057e47bfdd1 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -131,7 +131,7 @@ const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c cfg_if::cfg_if! { - if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "netbsd")))] { + if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "watchos"), not(target_os = "netbsd")))] { // ARM EHABI personality routine. // https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf // diff --git a/library/std/build.rs b/library/std/build.rs index bffbe802fd0..8b1a06ee750 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -15,6 +15,7 @@ fn main() { || target.contains("illumos") || target.contains("apple-darwin") || target.contains("apple-ios") + || target.contains("apple-watchos") || target.contains("uwp") || target.contains("windows") || target.contains("fuchsia") diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index e8d0132f4b9..b8959316de1 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1534,3 +1534,20 @@ fn read_large_dir() { entry.unwrap(); } } + +/// Test the fallback for getting the metadata of files like hiberfil.sys that +/// Windows holds a special lock on, preventing normal means of querying +/// metadata. See #96980. +/// +/// Note this fails in CI because `hiberfil.sys` does not actually exist there. +/// Therefore it's marked as ignored. +#[test] +#[ignore] +#[cfg(windows)] +fn hiberfil_sys() { + let hiberfil = Path::new(r"C:\hiberfil.sys"); + assert_eq!(true, hiberfil.try_exists().unwrap()); + fs::symlink_metadata(hiberfil).unwrap(); + fs::metadata(hiberfil).unwrap(); + assert_eq!(true, hiberfil.exists()); +} diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index a1df72a8a04..6fbaa42c768 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -141,7 +141,6 @@ pub mod openbsd; pub mod redox; #[cfg(target_os = "solaris")] pub mod solaris; - #[cfg(target_os = "solid_asp3")] pub mod solid; #[cfg(target_os = "vxworks")] diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index cef546487f3..411cc0925c4 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -90,6 +90,7 @@ pub mod thread; target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "watchos", target_os = "macos", target_os = "netbsd", target_os = "openbsd" diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 1d6083e66e1..cc3a8858793 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -12,6 +12,7 @@ use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, Owned target_os = "freebsd", target_os = "ios", target_os = "macos", + target_os = "watchos", target_os = "netbsd", target_os = "openbsd" ))] @@ -30,6 +31,7 @@ use crate::time::Duration; target_os = "freebsd", target_os = "ios", target_os = "macos", + target_os = "watchos", target_os = "netbsd", target_os = "openbsd" ))] @@ -238,6 +240,7 @@ impl UnixStream { target_os = "freebsd", target_os = "ios", target_os = "macos", + target_os = "watchos", target_os = "netbsd", target_os = "openbsd" ))] diff --git a/library/std/src/os/unix/ucred.rs b/library/std/src/os/unix/ucred.rs index 32e6430d3f6..ae4faf27b4d 100644 --- a/library/std/src/os/unix/ucred.rs +++ b/library/std/src/os/unix/ucred.rs @@ -36,7 +36,7 @@ pub use self::impl_linux::peer_cred; ))] pub use self::impl_bsd::peer_cred; -#[cfg(any(target_os = "macos", target_os = "ios",))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] pub use self::impl_mac::peer_cred; #[cfg(any(target_os = "linux", target_os = "android"))] @@ -97,7 +97,7 @@ pub mod impl_bsd { } } -#[cfg(any(target_os = "macos", target_os = "ios",))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] pub mod impl_mac { use super::UCred; use crate::os::unix::io::AsRawFd; diff --git a/library/std/src/os/unix/ucred/tests.rs b/library/std/src/os/unix/ucred/tests.rs index 42d79418cf7..e63a2fc248e 100644 --- a/library/std/src/os/unix/ucred/tests.rs +++ b/library/std/src/os/unix/ucred/tests.rs @@ -9,6 +9,7 @@ use libc::{getegid, geteuid, getpid}; target_os = "freebsd", target_os = "ios", target_os = "macos", + target_os = "watchos", target_os = "openbsd" ))] fn test_socket_pair() { @@ -25,7 +26,7 @@ fn test_socket_pair() { } #[test] -#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos",))] +#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos", target_os = "watchos"))] fn test_socket_pair_pids(arg: Type) -> RetType { // Create two connected sockets and get their peer credentials. let (sock_a, sock_b) = UnixStream::pair().unwrap(); diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index 79964e2b238..a342f0f5e85 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -151,7 +151,7 @@ mod imp { } } -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] mod imp { use super::Args; use crate::ffi::CStr; @@ -192,7 +192,7 @@ mod imp { // for i in (0..[args count]) // res.push([args objectAtIndex:i]) // res - #[cfg(target_os = "ios")] + #[cfg(any(target_os = "ios", target_os = "watchos"))] pub fn args() -> Args { use crate::ffi::OsString; use crate::mem; diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs index 4d8391656a4..c9ba661c829 100644 --- a/library/std/src/sys/unix/env.rs +++ b/library/std/src/sys/unix/env.rs @@ -31,6 +31,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "watchos")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "watchos"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".dylib"; + pub const DLL_EXTENSION: &str = "dylib"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "freebsd")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 137ca3a7633..30812dabb4e 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -47,6 +47,7 @@ const READ_LIMIT: usize = libc::ssize_t::MAX as usize; target_os = "macos", target_os = "netbsd", target_os = "openbsd", + target_os = "watchos", ))] const fn max_iov() -> usize { libc::IOV_MAX as usize @@ -67,7 +68,8 @@ const fn max_iov() -> usize { target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "horizon" + target_os = "horizon", + target_os = "watchos", )))] const fn max_iov() -> usize { 16 // The minimum value required by POSIX. diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 8b0bbd6a55c..7c882469440 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -17,6 +17,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; all(target_os = "linux", target_env = "gnu"), target_os = "macos", target_os = "ios", + target_os = "watchos", ))] use crate::sys::weak::syscall; #[cfg(target_os = "macos")] @@ -27,6 +28,7 @@ use libc::{c_int, mode_t}; #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "watchos", all(target_os = "linux", target_env = "gnu") ))] use libc::c_char; @@ -443,7 +445,8 @@ impl FileAttr { target_os = "freebsd", target_os = "openbsd", target_os = "macos", - target_os = "ios" + target_os = "ios", + target_os = "watchos", ))] pub fn created(&self) -> io::Result<SystemTime> { Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64)) @@ -453,7 +456,8 @@ impl FileAttr { target_os = "freebsd", target_os = "openbsd", target_os = "macos", - target_os = "ios" + target_os = "ios", + target_os = "watchos", )))] pub fn created(&self) -> io::Result<SystemTime> { cfg_has_statx! { @@ -707,6 +711,7 @@ impl DirEntry { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "watchos", target_os = "linux", target_os = "emscripten", target_os = "android", @@ -737,6 +742,7 @@ impl DirEntry { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "watchos", target_os = "netbsd", target_os = "openbsd", target_os = "freebsd", @@ -754,6 +760,7 @@ impl DirEntry { #[cfg(not(any( target_os = "macos", target_os = "ios", + target_os = "watchos", target_os = "netbsd", target_os = "openbsd", target_os = "freebsd", @@ -911,11 +918,11 @@ impl File { cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?; return Ok(()); - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] unsafe fn os_fsync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) } - #[cfg(not(any(target_os = "macos", target_os = "ios")))] + #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos")))] unsafe fn os_fsync(fd: c_int) -> c_int { libc::fsync(fd) } @@ -925,7 +932,7 @@ impl File { cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?; return Ok(()); - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) } @@ -946,7 +953,8 @@ impl File { target_os = "linux", target_os = "macos", target_os = "netbsd", - target_os = "openbsd" + target_os = "openbsd", + target_os = "watchos", )))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) @@ -1396,7 +1404,8 @@ fn open_to_and_set_permissions( target_os = "linux", target_os = "android", target_os = "macos", - target_os = "ios" + target_os = "ios", + target_os = "watchos", )))] pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { let (mut reader, reader_metadata) = open_from(from)?; @@ -1423,7 +1432,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { } } -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { use crate::sync::atomic::{AtomicBool, Ordering}; diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs index 78f10f0534c..abf27e7db78 100644 --- a/library/std/src/sys/unix/locks/pthread_condvar.rs +++ b/library/std/src/sys/unix/locks/pthread_condvar.rs @@ -37,6 +37,7 @@ impl Condvar { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "watchos", target_os = "l4re", target_os = "android", target_os = "redox" @@ -58,6 +59,7 @@ impl Condvar { #[cfg(not(any( target_os = "macos", target_os = "ios", + target_os = "watchos", target_os = "l4re", target_os = "android", target_os = "redox", @@ -102,6 +104,7 @@ impl Condvar { #[cfg(not(any( target_os = "macos", target_os = "ios", + target_os = "watchos", target_os = "android", target_os = "espidf", target_os = "horizon" @@ -135,6 +138,7 @@ impl Condvar { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "watchos", target_os = "android", target_os = "espidf", target_os = "horizon" diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 34a023b02c4..3d0d91460f7 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -86,6 +86,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { // The poll on Darwin doesn't set POLLNVAL for closed fds. target_os = "macos", target_os = "ios", + target_os = "watchos", target_os = "redox", target_os = "l4re", target_os = "horizon", @@ -329,7 +330,7 @@ cfg_if::cfg_if! { // See #41582 and https://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html #[link(name = "resolv")] extern "C" {} - } else if #[cfg(target_os = "ios")] { + } else if #[cfg(any(target_os = "ios", target_os = "watchos"))] { #[link(name = "System")] #[link(name = "objc")] #[link(name = "Security", kind = "framework")] diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 7252ad32184..46545a0839f 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -61,7 +61,7 @@ extern "C" { )] #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")] #[cfg_attr( - any(target_os = "macos", target_os = "ios", target_os = "freebsd"), + any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "watchos"), link_name = "__error" )] #[cfg_attr(target_os = "haiku", link_name = "_errnop")] @@ -361,7 +361,7 @@ pub fn current_exe() -> io::Result<PathBuf> { } } -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] pub fn current_exe() -> io::Result<PathBuf> { unsafe { let mut sz: u32 = 0; @@ -598,6 +598,7 @@ pub fn home_dir() -> Option<PathBuf> { #[cfg(any( target_os = "android", target_os = "ios", + target_os = "watchos", target_os = "emscripten", target_os = "redox", target_os = "vxworks", @@ -610,6 +611,7 @@ pub fn home_dir() -> Option<PathBuf> { #[cfg(not(any( target_os = "android", target_os = "ios", + target_os = "watchos", target_os = "emscripten", target_os = "redox", target_os = "vxworks", diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index 56d01074c20..bf49204881d 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -14,6 +14,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { unix, not(target_os = "macos"), not(target_os = "ios"), + not(target_os = "watchos"), not(target_os = "openbsd"), not(target_os = "freebsd"), not(target_os = "netbsd"), @@ -195,7 +196,7 @@ mod imp { // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is // only used on iOS where direct access to `/dev/urandom` is blocked by the // sandbox. -#[cfg(target_os = "ios")] +#[cfg(any(target_os = "ios", target_os = "watchos"))] mod imp { use crate::io; use crate::ptr; diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index d191e1fe7a6..6533625876f 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -139,7 +139,7 @@ impl Thread { } } - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] pub fn set_name(name: &CStr) { unsafe { libc::pthread_setname_np(name.as_ptr()); diff --git a/library/std/src/sys/unix/thread_parker.rs b/library/std/src/sys/unix/thread_parker.rs index 9f4d4f7e736..ca1a7138fde 100644 --- a/library/std/src/sys/unix/thread_parker.rs +++ b/library/std/src/sys/unix/thread_parker.rs @@ -52,7 +52,12 @@ unsafe fn wait_timeout( ) { // Use the system clock on systems that do not support pthread_condattr_setclock. // This unfortunately results in problems when the system time changes. - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "espidf"))] + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "espidf" + ))] let (now, dur) = { use super::time::SystemTime; use crate::cmp::min; @@ -73,7 +78,12 @@ unsafe fn wait_timeout( (now, dur) }; // Use the monotonic clock on other systems. - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "espidf")))] + #[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "espidf" + )))] let (now, dur) = { use super::time::Timespec; @@ -111,6 +121,7 @@ impl Parker { if #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "watchos", target_os = "l4re", target_os = "android", target_os = "redox" diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index d114af49d26..dff973f59d1 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -141,7 +141,7 @@ impl From<libc::timespec> for Timespec { } } -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] mod inner { use crate::sync::atomic::{AtomicU64, Ordering}; use crate::sys::cvt; @@ -257,7 +257,7 @@ mod inner { } } -#[cfg(not(any(target_os = "macos", target_os = "ios")))] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos")))] mod inner { use crate::fmt; use crate::mem::MaybeUninit; diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index e9b10069077..4d3162f1254 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -155,22 +155,7 @@ impl DirEntry { } pub fn metadata(&self) -> io::Result<FileAttr> { - Ok(FileAttr { - attributes: self.data.dwFileAttributes, - creation_time: self.data.ftCreationTime, - last_access_time: self.data.ftLastAccessTime, - last_write_time: self.data.ftLastWriteTime, - file_size: ((self.data.nFileSizeHigh as u64) << 32) | (self.data.nFileSizeLow as u64), - reparse_tag: if self.data.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - // reserved unless this is a reparse point - self.data.dwReserved0 - } else { - 0 - }, - volume_serial_number: None, - number_of_links: None, - file_index: None, - }) + Ok(self.data.into()) } } @@ -879,6 +864,26 @@ impl FileAttr { self.file_index } } +impl From<c::WIN32_FIND_DATAW> for FileAttr { + fn from(wfd: c::WIN32_FIND_DATAW) -> Self { + FileAttr { + attributes: wfd.dwFileAttributes, + creation_time: wfd.ftCreationTime, + last_access_time: wfd.ftLastAccessTime, + last_write_time: wfd.ftLastWriteTime, + file_size: ((wfd.nFileSizeHigh as u64) << 32) | (wfd.nFileSizeLow as u64), + reparse_tag: if wfd.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + // reserved unless this is a reparse point + wfd.dwReserved0 + } else { + 0 + }, + volume_serial_number: None, + number_of_links: None, + file_index: None, + } + } +} fn to_u64(ft: &c::FILETIME) -> u64 { (ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32) @@ -1145,22 +1150,73 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { } pub fn stat(path: &Path) -> io::Result<FileAttr> { - let mut opts = OpenOptions::new(); - // No read or write permissions are necessary - opts.access_mode(0); - // This flag is so we can open directories too - opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); - let file = File::open(path, &opts)?; - file.file_attr() + metadata(path, ReparsePoint::Follow) } pub fn lstat(path: &Path) -> io::Result<FileAttr> { + metadata(path, ReparsePoint::Open) +} + +#[repr(u32)] +#[derive(Clone, Copy, PartialEq, Eq)] +enum ReparsePoint { + Follow = 0, + Open = c::FILE_FLAG_OPEN_REPARSE_POINT, +} +impl ReparsePoint { + fn as_flag(self) -> u32 { + self as u32 + } +} + +fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> { let mut opts = OpenOptions::new(); // No read or write permissions are necessary opts.access_mode(0); - opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT); - let file = File::open(path, &opts)?; - file.file_attr() + opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | reparse.as_flag()); + + // Attempt to open the file normally. + // If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileW`. + // If the fallback fails for any reason we return the original error. + match File::open(path, &opts) { + Ok(file) => file.file_attr(), + Err(e) if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _) => { + // `ERROR_SHARING_VIOLATION` will almost never be returned. + // Usually if a file is locked you can still read some metadata. + // However, there are special system files, such as + // `C:\hiberfil.sys`, that are locked in a way that denies even that. + unsafe { + let path = maybe_verbatim(path)?; + + // `FindFirstFileW` accepts wildcard file names. + // Fortunately wildcards are not valid file names and + // `ERROR_SHARING_VIOLATION` means the file exists (but is locked) + // therefore it's safe to assume the file name given does not + // include wildcards. + let mut wfd = mem::zeroed(); + let handle = c::FindFirstFileW(path.as_ptr(), &mut wfd); + + if handle == c::INVALID_HANDLE_VALUE { + // This can fail if the user does not have read access to the + // directory. + Err(e) + } else { + // We no longer need the find handle. + c::FindClose(handle); + + // `FindFirstFileW` reads the cached file information from the + // directory. The downside is that this metadata may be outdated. + let attrs = FileAttr::from(wfd); + if reparse == ReparsePoint::Follow && attrs.file_type().is_symlink() { + Err(e) + } else { + Ok(attrs) + } + } + } + } + Err(e) => Err(e), + } } pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index f5730a2cea5..c13bda32823 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -18,7 +18,7 @@ use libc::{c_int, c_void}; cfg_if::cfg_if! { if #[cfg(any( target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", + target_os = "ios", target_os = "macos", target_os = "watchos", target_os = "openbsd", target_os = "netbsd", target_os = "illumos", target_os = "solaris", target_os = "haiku", target_os = "l4re"))] { use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 7b78bda424b..a5b6193b086 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -30,10 +30,10 @@ pub const unwinder_private_data_size: usize = 5; #[cfg(target_arch = "x86_64")] pub const unwinder_private_data_size: usize = 6; -#[cfg(all(target_arch = "arm", not(target_os = "ios")))] +#[cfg(all(target_arch = "arm", not(any(target_os = "ios", target_os = "watchos"))))] pub const unwinder_private_data_size: usize = 20; -#[cfg(all(target_arch = "arm", target_os = "ios"))] +#[cfg(all(target_arch = "arm", any(target_os = "ios", target_os = "watchos")))] pub const unwinder_private_data_size: usize = 5; #[cfg(all(target_arch = "aarch64", target_pointer_width = "64"))] @@ -105,7 +105,7 @@ extern "C" { } cfg_if::cfg_if! { -if #[cfg(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm")))] { +if #[cfg(any(target_os = "ios", target_os = "watchos", target_os = "netbsd", not(target_arch = "arm")))] { // Not ARM EHABI #[repr(C)] #[derive(Copy, Clone, PartialEq)] diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index e5887689690..ada6e357aea 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -18,6 +18,14 @@ LL | | break 0u8; LL | | }; | |_________- enclosing `async` block +error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()` + --> $DIR/async-block-control-flow-static-semantics.rs:26:39 + | +LL | let _: &dyn Future<Output = ()> = █ + | ^^^^^^ expected `()`, found `u8` + | + = note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>` + error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:21:58 | @@ -32,7 +40,7 @@ LL | | } | |_^ expected `u8`, found `()` error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()` - --> $DIR/async-block-control-flow-static-semantics.rs:26:39 + --> $DIR/async-block-control-flow-static-semantics.rs:17:39 | LL | let _: &dyn Future<Output = ()> = █ | ^^^^^^ expected `()`, found `u8` @@ -47,14 +55,6 @@ LL | fn return_targets_async_block_not_fn() -> u8 { | | | implicitly returns `()` as its body has no tail or `return` expression -error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()` - --> $DIR/async-block-control-flow-static-semantics.rs:17:39 - | -LL | let _: &dyn Future<Output = ()> = █ - | ^^^^^^ expected `()`, found `u8` - | - = note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>` - error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:47:44 | diff --git a/src/test/ui/const-generics/issues/issue-71547.rs b/src/test/ui/const-generics/issues/issue-71547.rs new file mode 100644 index 00000000000..60776a1a985 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71547.rs @@ -0,0 +1,18 @@ +// check-pass + +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +pub trait GetType<const N: &'static str> { + type Ty; + fn get(&self) -> &Self::Ty; +} + +pub fn get_val<T>(value: &T) -> &T::Ty +where + T: GetType<"hello">, +{ + value.get() +} + +fn main() {} diff --git a/src/test/ui/foreign/issue-99276-same-type-lifetimes.rs b/src/test/ui/foreign/issue-99276-same-type-lifetimes.rs new file mode 100644 index 00000000000..fce603c801f --- /dev/null +++ b/src/test/ui/foreign/issue-99276-same-type-lifetimes.rs @@ -0,0 +1,24 @@ +// Check that we do not ICE when structurally comparing types with lifetimes present. +// check-pass + +pub struct Record<'a> { + pub args: &'a [(usize, &'a str)], +} + +mod a { + extern "Rust" { + fn foo<'a, 'b>(record: &'a super::Record<'b>); + + fn bar<'a, 'b>(record: &'a super::Record<'b>); + } +} + +mod b { + extern "Rust" { + fn foo<'a, 'b>(record: &'a super::Record<'b>); + + fn bar<'a, 'b>(record: &'a super::Record<'b>); + } +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-99073-2.rs b/src/test/ui/impl-trait/issue-99073-2.rs new file mode 100644 index 00000000000..bebd8286de9 --- /dev/null +++ b/src/test/ui/impl-trait/issue-99073-2.rs @@ -0,0 +1,17 @@ +use std::fmt::Display; + +fn main() { + test("hi", true); +} + +fn test<T: Display>(t: T, recurse: bool) -> impl Display { + let f = || { + let i: u32 = test::<i32>(-1, false); + //~^ ERROR mismatched types + println!("{i}"); + }; + if recurse { + f(); + } + t +} diff --git a/src/test/ui/impl-trait/issue-99073-2.stderr b/src/test/ui/impl-trait/issue-99073-2.stderr new file mode 100644 index 00000000000..c1e4b823c08 --- /dev/null +++ b/src/test/ui/impl-trait/issue-99073-2.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-99073-2.rs:9:22 + | +LL | fn test<T: Display>(t: T, recurse: bool) -> impl Display { + | ------------ the expected opaque type +LL | let f = || { +LL | let i: u32 = test::<i32>(-1, false); + | ^^^^^^^^^^^^^^^^^^^^^^ types differ + | + = note: expected opaque type `impl std::fmt::Display` + found type `u32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/impl-trait/issue-99073.rs b/src/test/ui/impl-trait/issue-99073.rs new file mode 100644 index 00000000000..1d75f608666 --- /dev/null +++ b/src/test/ui/impl-trait/issue-99073.rs @@ -0,0 +1,8 @@ +fn main() { + let _ = fix(|_: &dyn Fn()| {}); +} + +fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() { + move || f(fix(&f)) + //~^ ERROR mismatched types +} diff --git a/src/test/ui/impl-trait/issue-99073.stderr b/src/test/ui/impl-trait/issue-99073.stderr new file mode 100644 index 00000000000..b35d58093d5 --- /dev/null +++ b/src/test/ui/impl-trait/issue-99073.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-99073.rs:6:13 + | +LL | fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() { + | --------- the expected opaque type +LL | move || f(fix(&f)) + | ^^^^^^^^^^ types differ + | + = note: expected opaque type `impl Fn()` + found type parameter `G` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/liveness/liveness-forgot-ret.stderr b/src/test/ui/liveness/liveness-forgot-ret.stderr index 95070322bdd..ddbdbdb0fd0 100644 --- a/src/test/ui/liveness/liveness-forgot-ret.stderr +++ b/src/test/ui/liveness/liveness-forgot-ret.stderr @@ -5,6 +5,11 @@ LL | fn f(a: isize) -> isize { if god_exists(a) { return 5; }; } | - ^^^^^ expected `isize`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression + | +help: consider returning the local binding `a` + | +LL | fn f(a: isize) -> isize { if god_exists(a) { return 5; }; a } + | + error: aborting due to previous error diff --git a/src/test/ui/parser/issues/issue-33413.stderr b/src/test/ui/parser/issues/issue-33413.stderr index ac320f095a2..b7250f3b0b5 100644 --- a/src/test/ui/parser/issues/issue-33413.stderr +++ b/src/test/ui/parser/issues/issue-33413.stderr @@ -11,6 +11,11 @@ LL | fn f(*, a: u8) -> u8 {} | - ^^ expected `u8`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression + | +help: consider returning the local binding `a` + | +LL | fn f(*, a: u8) -> u8 { a } + | + error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/return-bindings-multi.rs b/src/test/ui/suggestions/return-bindings-multi.rs new file mode 100644 index 00000000000..8c3bd641e97 --- /dev/null +++ b/src/test/ui/suggestions/return-bindings-multi.rs @@ -0,0 +1,9 @@ +fn a(i: i32) -> i32 { + //~^ ERROR mismatched types + let j = 2i32; +} + +fn b(i: i32, j: i32) -> i32 {} +//~^ ERROR mismatched types + +fn main() {} diff --git a/src/test/ui/suggestions/return-bindings-multi.stderr b/src/test/ui/suggestions/return-bindings-multi.stderr new file mode 100644 index 00000000000..738e3f2f4be --- /dev/null +++ b/src/test/ui/suggestions/return-bindings-multi.stderr @@ -0,0 +1,34 @@ +error[E0308]: mismatched types + --> $DIR/return-bindings-multi.rs:1:17 + | +LL | fn a(i: i32) -> i32 { + | - ^^^ expected `i32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | +note: consider returning one of these bindings + --> $DIR/return-bindings-multi.rs:1:6 + | +LL | fn a(i: i32) -> i32 { + | ^ +LL | +LL | let j = 2i32; + | ^ + +error[E0308]: mismatched types + --> $DIR/return-bindings-multi.rs:6:25 + | +LL | fn b(i: i32, j: i32) -> i32 {} + | - ^^^ expected `i32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | +note: consider returning one of these bindings + --> $DIR/return-bindings-multi.rs:6:6 + | +LL | fn b(i: i32, j: i32) -> i32 {} + | ^ ^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/return-bindings.fixed b/src/test/ui/suggestions/return-bindings.fixed new file mode 100644 index 00000000000..4fabc411abc --- /dev/null +++ b/src/test/ui/suggestions/return-bindings.fixed @@ -0,0 +1,23 @@ +// run-rustfix + +#![allow(unused)] + +fn a(i: i32) -> i32 { i } +//~^ ERROR mismatched types + +fn b(opt_str: Option<String>) { + let s: String = if let Some(s) = opt_str { + s + //~^ ERROR mismatched types + } else { + String::new() + }; +} + +fn c() -> Option<i32> { + //~^ ERROR mismatched types + let x = Some(1); + x +} + +fn main() {} diff --git a/src/test/ui/suggestions/return-bindings.rs b/src/test/ui/suggestions/return-bindings.rs new file mode 100644 index 00000000000..d05b4ba27d6 --- /dev/null +++ b/src/test/ui/suggestions/return-bindings.rs @@ -0,0 +1,21 @@ +// run-rustfix + +#![allow(unused)] + +fn a(i: i32) -> i32 {} +//~^ ERROR mismatched types + +fn b(opt_str: Option<String>) { + let s: String = if let Some(s) = opt_str { + //~^ ERROR mismatched types + } else { + String::new() + }; +} + +fn c() -> Option<i32> { + //~^ ERROR mismatched types + let x = Some(1); +} + +fn main() {} diff --git a/src/test/ui/suggestions/return-bindings.stderr b/src/test/ui/suggestions/return-bindings.stderr new file mode 100644 index 00000000000..e5d49255005 --- /dev/null +++ b/src/test/ui/suggestions/return-bindings.stderr @@ -0,0 +1,48 @@ +error[E0308]: mismatched types + --> $DIR/return-bindings.rs:5:17 + | +LL | fn a(i: i32) -> i32 {} + | - ^^^ expected `i32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | +help: consider returning the local binding `i` + | +LL | fn a(i: i32) -> i32 { i } + | + + +error[E0308]: mismatched types + --> $DIR/return-bindings.rs:9:46 + | +LL | let s: String = if let Some(s) = opt_str { + | ______________________________________________^ +LL | | +LL | | } else { + | |_____^ expected struct `String`, found `()` + | +help: consider returning the local binding `s` + | +LL ~ let s: String = if let Some(s) = opt_str { +LL + s +LL ~ + | + +error[E0308]: mismatched types + --> $DIR/return-bindings.rs:16:11 + | +LL | fn c() -> Option<i32> { + | - ^^^^^^^^^^^ expected enum `Option`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | + = note: expected enum `Option<i32>` + found unit type `()` +help: consider returning the local binding `x` + | +LL ~ let x = Some(1); +LL + x + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. |
