diff --git a/RELEASES.md b/RELEASES.md index 2e7077ed2065e..dd299ca936ace 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -175,6 +175,7 @@ Compiler - [Improved debugger output for enums on Windows MSVC platforms.][85292] - [Added tier 3\* support for `bpfel-unknown-none` and `bpfeb-unknown-none`.][79608] +- [`-Zmutable-noalias=yes`][82834] is enabled by default when using LLVM 12 or above. \* Refer to Rust's [platform support page][platform-support-doc] for more information on Rust's tiered platform support. @@ -244,6 +245,7 @@ Compatibility Notes [83366]: https://github.com/rust-lang/rust/pull/83366 [83278]: https://github.com/rust-lang/rust/pull/83278 [85292]: https://github.com/rust-lang/rust/pull/85292 +[82834]: https://github.com/rust-lang/rust/pull/82834 [cargo/9520]: https://github.com/rust-lang/cargo/pull/9520 [cargo/9499]: https://github.com/rust-lang/cargo/pull/9499 [cargo/9488]: https://github.com/rust-lang/cargo/pull/9488 diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 575a00cdd0e43..2c2d30d872e20 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2028,6 +2028,7 @@ pub enum InlineAsmOperand { #[derive(Clone, Encodable, Decodable, Debug)] pub struct InlineAsm { pub template: Vec, + pub template_strs: Box<[(Symbol, Option, Span)]>, pub operands: Vec<(InlineAsmOperand, Span)>, pub clobber_abi: Option<(Symbol, Span)>, pub options: InlineAsmOptions, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index a377763983a4b..774d5cb2dda9d 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -19,20 +19,20 @@ use crate::token; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum AssocCtxt { Trait, Impl, } -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum FnCtxt { Free, Foreign, Assoc(AssocCtxt), } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub enum FnKind<'a> { /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>), diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index d94fb48d7cb88..b9b27855a0b88 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -392,8 +392,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let operands = self.arena.alloc_from_iter(operands); let template = self.arena.alloc_from_iter(asm.template.iter().cloned()); + let template_strs = self.arena.alloc_from_iter(asm.template_strs.iter().cloned()); let line_spans = self.arena.alloc_slice(&asm.line_spans[..]); - let hir_asm = hir::InlineAsm { template, operands, options: asm.options, line_spans }; + let hir_asm = + hir::InlineAsm { template, template_strs, operands, options: asm.options, line_spans }; self.arena.alloc(hir_asm) } } diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index cb0cfdcefdc22..652165fb9b60b 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -7,10 +7,10 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_expand::base::{self, *}; use rustc_parse::parser::Parser; use rustc_parse_format as parse; -use rustc_session::lint::{self, BuiltinLintDiagnostics}; +use rustc_session::lint; use rustc_span::symbol::Ident; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::{InnerSpan, MultiSpan, Span}; +use rustc_span::{InnerSpan, Span}; use rustc_target::asm::InlineAsmArch; use smallvec::smallvec; @@ -484,11 +484,7 @@ fn parse_reg<'a>( Ok(result) } -fn expand_preparsed_asm( - ecx: &mut ExtCtxt<'_>, - args: AsmArgs, - is_local_asm: bool, -) -> Option { +fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option { let mut template = vec![]; // Register operands are implicitly used since they are not allowed to be // referenced in the template string. @@ -501,6 +497,8 @@ fn expand_preparsed_asm( let mut line_spans = Vec::with_capacity(args.templates.len()); let mut curarg = 0; + let mut template_strs = Vec::with_capacity(args.templates.len()); + for template_expr in args.templates.into_iter() { if !template.is_empty() { template.push(ast::InlineAsmTemplatePiece::String("\n".to_string())); @@ -524,8 +522,13 @@ fn expand_preparsed_asm( ast::StrStyle::Raw(raw) => Some(raw as usize), }; - let template_str = &template_str.as_str(); let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok(); + template_strs.push(( + template_str, + template_snippet.as_ref().map(|s| Symbol::intern(s)), + template_sp, + )); + let template_str = &template_str.as_str(); if let Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) = ecx.sess.asm_arch { let find_span = |needle: &str| -> Span { @@ -560,72 +563,6 @@ fn expand_preparsed_asm( } } - // Lint against the use of named labels in inline `asm!` but not `global_asm!` - if is_local_asm { - let find_label_span = |needle: &str| -> Option { - if let Some(snippet) = &template_snippet { - if let Some(pos) = snippet.find(needle) { - let end = pos - + &snippet[pos..] - .find(|c| c == ':') - .unwrap_or(snippet[pos..].len() - 1); - let inner = InnerSpan::new(pos, end); - return Some(template_sp.from_inner(inner)); - } - } - - None - }; - - let mut found_labels = Vec::new(); - - // A semicolon might not actually be specified as a separator for all targets, but it seems like LLVM accepts it always - let statements = template_str.split(|c| matches!(c, '\n' | ';')); - for statement in statements { - // If there's a comment, trim it from the statement - let statement = statement.find("//").map_or(statement, |idx| &statement[..idx]); - let mut start_idx = 0; - for (idx, _) in statement.match_indices(':') { - let possible_label = statement[start_idx..idx].trim(); - let mut chars = possible_label.chars(); - if let Some(c) = chars.next() { - // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $ - if (c.is_alphabetic() || matches!(c, '.' | '_')) - && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$')) - { - found_labels.push(possible_label); - } else { - // If we encounter a non-label, there cannot be any further labels, so stop checking - break; - } - } else { - // Empty string means a leading ':' in this section, which is not a label - break; - } - - start_idx = idx + 1; - } - } - - if found_labels.len() > 0 { - let spans = - found_labels.into_iter().filter_map(find_label_span).collect::>(); - // If there were labels but we couldn't find a span, combine the warnings and use the template span - let target_spans: MultiSpan = - if spans.len() > 0 { spans.into() } else { template_sp.into() }; - ecx.parse_sess().buffer_lint_with_diagnostic( - lint::builtin::NAMED_ASM_LABELS, - target_spans, - ecx.current_expansion.lint_node_id, - "avoid using named labels in inline assembly", - BuiltinLintDiagnostics::NamedAsmLabel( - "only local labels of the form `:` should be used in inline asm" - .to_string(), - ), - ); - } - } - // Don't treat raw asm as a format string. if args.options.contains(ast::InlineAsmOptions::RAW) { template.push(ast::InlineAsmTemplatePiece::String(template_str.to_string())); @@ -819,6 +756,7 @@ fn expand_preparsed_asm( Some(ast::InlineAsm { template, + template_strs: template_strs.into_boxed_slice(), operands: args.operands, clobber_abi: args.clobber_abi, options: args.options, @@ -833,7 +771,7 @@ pub fn expand_asm<'cx>( ) -> Box { match parse_args(ecx, sp, tts, false) { Ok(args) => { - let expr = if let Some(inline_asm) = expand_preparsed_asm(ecx, args, true) { + let expr = if let Some(inline_asm) = expand_preparsed_asm(ecx, args) { P(ast::Expr { id: ast::DUMMY_NODE_ID, kind: ast::ExprKind::InlineAsm(P(inline_asm)), @@ -860,7 +798,7 @@ pub fn expand_global_asm<'cx>( ) -> Box { match parse_args(ecx, sp, tts, true) { Ok(args) => { - if let Some(inline_asm) = expand_preparsed_asm(ecx, args, false) { + if let Some(inline_asm) = expand_preparsed_asm(ecx, args) { MacEager::items(smallvec![P(ast::Item { ident: Ident::invalid(), attrs: Vec::new(), diff --git a/compiler/rustc_data_structures/src/owning_ref/mod.rs b/compiler/rustc_data_structures/src/owning_ref/mod.rs index 5b27a407ad422..e7397bf13bad4 100644 --- a/compiler/rustc_data_structures/src/owning_ref/mod.rs +++ b/compiler/rustc_data_structures/src/owning_ref/mod.rs @@ -5,7 +5,7 @@ This crate provides the _owning reference_ types `OwningRef` and `OwningRefMut` that enables it to bundle a reference together with the owner of the data it points to. -This allows moving and dropping of a `OwningRef` without needing to recreate the reference. +This allows moving and dropping of an `OwningRef` without needing to recreate the reference. This can sometimes be useful because Rust borrowing rules normally prevent moving a type that has been moved from. For example, this kind of code gets rejected: @@ -1146,7 +1146,7 @@ pub type VecRef = OwningRef, U>; /// Typedef of an owning reference that uses a `String` as the owner. pub type StringRef = OwningRef; -/// Typedef of an owning reference that uses a `Rc` as the owner. +/// Typedef of an owning reference that uses an `Rc` as the owner. pub type RcRef = OwningRef, U>; /// Typedef of an owning reference that uses an `Arc` as the owner. pub type ArcRef = OwningRef, U>; @@ -1157,9 +1157,9 @@ pub type RefRef<'a, T, U = T> = OwningRef, U>; pub type RefMutRef<'a, T, U = T> = OwningRef, U>; /// Typedef of an owning reference that uses a `MutexGuard` as the owner. pub type MutexGuardRef<'a, T, U = T> = OwningRef, U>; -/// Typedef of an owning reference that uses a `RwLockReadGuard` as the owner. +/// Typedef of an owning reference that uses an `RwLockReadGuard` as the owner. pub type RwLockReadGuardRef<'a, T, U = T> = OwningRef, U>; -/// Typedef of an owning reference that uses a `RwLockWriteGuard` as the owner. +/// Typedef of an owning reference that uses an `RwLockWriteGuard` as the owner. pub type RwLockWriteGuardRef<'a, T, U = T> = OwningRef, U>; /// Typedef of a mutable owning reference that uses a `Box` as the owner. @@ -1173,7 +1173,7 @@ pub type StringRefMut = OwningRefMut; pub type RefMutRefMut<'a, T, U = T> = OwningRefMut, U>; /// Typedef of a mutable owning reference that uses a `MutexGuard` as the owner. pub type MutexGuardRefMut<'a, T, U = T> = OwningRefMut, U>; -/// Typedef of a mutable owning reference that uses a `RwLockWriteGuard` as the owner. +/// Typedef of a mutable owning reference that uses an `RwLockWriteGuard` as the owner. pub type RwLockWriteGuardRefMut<'a, T, U = T> = OwningRef, U>; unsafe impl<'a, T: 'a> IntoErased<'a> for Box { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 888d1c1832b09..38deb8eaaae6b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2386,6 +2386,7 @@ impl<'hir> InlineAsmOperand<'hir> { #[derive(Debug, HashStable_Generic)] pub struct InlineAsm<'hir> { pub template: &'hir [InlineAsmTemplatePiece], + pub template_strs: &'hir [(Symbol, Option, Span)], pub operands: &'hir [(InlineAsmOperand<'hir>, Span)], pub options: InlineAsmOptions, pub line_spans: &'hir [Span], diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 0ac4b6b25bbfe..d0bd508bc257f 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -104,11 +104,5 @@ pub fn report_object_safety_error( to be resolvable dynamically; for more information visit \ ", ); - - if tcx.sess.trait_methods_not_found.borrow().iter().any(|full_span| full_span.contains(span)) { - // Avoid emitting error caused by non-existing method (#58734) - err.cancel(); - } - err } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index afa2cfca1880f..add0c0ff332f2 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -45,11 +45,11 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, Subst}; use rustc_middle::ty::Instance; use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt}; -use rustc_session::lint::FutureIncompatibilityReason; +use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason}; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, Span}; +use rustc_span::{BytePos, InnerSpan, MultiSpan, Span}; use rustc_target::abi::{LayoutOf, VariantIdx}; use rustc_trait_selection::traits::misc::can_type_implement_copy; @@ -3140,3 +3140,123 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr { } } } + +declare_lint! { + /// The `named_asm_labels` lint detects the use of named labels in the + /// inline `asm!` macro. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![feature(asm)] + /// fn main() { + /// unsafe { + /// asm!("foo: bar"); + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// LLVM is allowed to duplicate inline assembly blocks for any + /// reason, for example when it is in a function that gets inlined. Because + /// of this, GNU assembler [local labels] *must* be used instead of labels + /// with a name. Using named labels might cause assembler or linker errors. + /// + /// See the [unstable book] for more details. + /// + /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels + /// [unstable book]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels + pub NAMED_ASM_LABELS, + Deny, + "named labels in inline assembly", +} + +declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]); + +impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + if let hir::Expr { + kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, .. }), + .. + } = expr + { + for (template_sym, template_snippet, template_span) in template_strs.iter() { + let template_str = &template_sym.as_str(); + let find_label_span = |needle: &str| -> Option { + if let Some(template_snippet) = template_snippet { + let snippet = template_snippet.as_str(); + if let Some(pos) = snippet.find(needle) { + let end = pos + + &snippet[pos..] + .find(|c| c == ':') + .unwrap_or(snippet[pos..].len() - 1); + let inner = InnerSpan::new(pos, end); + return Some(template_span.from_inner(inner)); + } + } + + None + }; + + let mut found_labels = Vec::new(); + + // A semicolon might not actually be specified as a separator for all targets, but it seems like LLVM accepts it always + let statements = template_str.split(|c| matches!(c, '\n' | ';')); + for statement in statements { + // If there's a comment, trim it from the statement + let statement = statement.find("//").map_or(statement, |idx| &statement[..idx]); + let mut start_idx = 0; + for (idx, _) in statement.match_indices(':') { + let possible_label = statement[start_idx..idx].trim(); + let mut chars = possible_label.chars(); + if let Some(c) = chars.next() { + // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $ + if (c.is_alphabetic() || matches!(c, '.' | '_')) + && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$')) + { + found_labels.push(possible_label); + } else { + // If we encounter a non-label, there cannot be any further labels, so stop checking + break; + } + } else { + // Empty string means a leading ':' in this section, which is not a label + break; + } + + start_idx = idx + 1; + } + } + + debug!("NamedAsmLabels::check_expr(): found_labels: {:#?}", &found_labels); + + if found_labels.len() > 0 { + let spans = found_labels + .into_iter() + .filter_map(|label| find_label_span(label)) + .collect::>(); + // If there were labels but we couldn't find a span, combine the warnings and use the template span + let target_spans: MultiSpan = + if spans.len() > 0 { spans.into() } else { (*template_span).into() }; + + cx.lookup_with_diagnostics( + NAMED_ASM_LABELS, + Some(target_spans), + |diag| { + let mut err = + diag.build("avoid using named labels in inline assembly"); + err.emit(); + }, + BuiltinLintDiagnostics::NamedAsmLabel( + "only local labels of the form `:` should be used in inline asm" + .to_string(), + ), + ); + } + } + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c4008e77bab7c..24ac723f2c913 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -168,6 +168,7 @@ macro_rules! late_lint_passes { NonPanicFmt: NonPanicFmt, NoopMethodCall: NoopMethodCall, InvalidAtomicOrdering: InvalidAtomicOrdering, + NamedAsmLabels: NamedAsmLabels, ] ); }; diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a1c507b4c847f..1d978b6c82923 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2468,38 +2468,6 @@ declare_lint! { "incorrect use of inline assembly", } -declare_lint! { - /// The `named_asm_labels` lint detects the use of named labels in the - /// inline `asm!` macro. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// fn main() { - /// unsafe { - /// asm!("foo: bar"); - /// } - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// LLVM is allowed to duplicate inline assembly blocks for any - /// reason, for example when it is in a function that gets inlined. Because - /// of this, GNU assembler [local labels] *must* be used instead of labels - /// with a name. Using named labels might cause assembler or linker errors. - /// - /// See the [unstable book] for more details. - /// - /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels - /// [unstable book]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels - pub NAMED_ASM_LABELS, - Deny, - "named labels in inline assembly", -} - declare_lint! { /// The `unsafe_op_in_unsafe_fn` lint detects unsafe operations in unsafe /// functions without an explicit unsafe block. @@ -3020,7 +2988,6 @@ declare_lint_pass! { INLINE_NO_SANITIZE, BAD_ASM_STYLE, ASM_SUB_REGISTER, - NAMED_ASM_LABELS, UNSAFE_OP_IN_UNSAFE_FN, INCOMPLETE_INCLUDE, CENUM_IMPL_DROP_CAST, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index d49ba861785b3..20e94e32be61f 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -189,9 +189,6 @@ pub struct Session { /// Cap lint level specified by a driver specifically. pub driver_lint_caps: FxHashMap, - /// `Span`s of trait methods that weren't found to avoid emitting object safety errors - pub trait_methods_not_found: Lock>, - /// Mapping from ident span to path span for paths that don't exist as written, but that /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. pub confused_type_with_std_module: Lock>, @@ -1326,7 +1323,6 @@ pub fn build_session( print_fuel, jobserver: jobserver::client(), driver_lint_caps, - trait_methods_not_found: Lock::new(Default::default()), confused_type_with_std_module: Lock::new(Default::default()), ctfe_backtrace, miri_unleashed_features: Lock::new(Default::default()), diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index f9b7bb8ea9915..0cf30fecf7381 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -858,13 +858,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { path.segments, ); } - QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment), + QPath::TypeRelative(ref qself, ref segment) => { + // Don't use `self.to_ty`, since this will register a WF obligation. + // If we're trying to call a non-existent method on a trait + // (e.g. `MyTrait::missing_method`), then resolution will + // give us a `QPath::TypeRelative` with a trait object as + // `qself`. In that case, we want to avoid registering a WF obligation + // for `dyn MyTrait`, since we don't actually need the trait + // to be object-safe. + // We manually call `register_wf_obligation` in the success path + // below. + (>::ast_ty_to_ty(self, qself), qself, segment) + } QPath::LangItem(..) => { bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`") } }; if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id) { + self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None)); // Return directly on cache hit. This is useful to avoid doubly reporting // errors with default match binding modes. See #44614. let def = cached_result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)); @@ -878,6 +890,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), _ => Err(ErrorReported), }; + + // If we have a path like `MyTrait::missing_method`, then don't register + // a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise, + // register a WF obligation so that we can detect any additional + // errors in the self type. + if !(matches!(error, method::MethodError::NoMatch(_)) && ty.is_trait()) { + self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None)); + } if item_name.name != kw::Empty { if let Some(mut e) = self.report_method_error( span, @@ -895,6 +915,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if result.is_ok() { self.maybe_lint_bare_trait(qpath, hir_id); + self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None)); } // Write back the new resolution. diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 1d5a9e3e1f968..afe274a2a796e 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -70,15 +70,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn report_method_error( &self, - span: Span, + mut span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, source: SelfSource<'tcx>, error: MethodError<'tcx>, args: Option<&'tcx [hir::Expr<'tcx>]>, ) -> Option> { - let orig_span = span; - let mut span = span; // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { return None; @@ -545,7 +543,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds")); } - self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span); }; // If the method name is the name of a field with a function or closure type, diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index fc7f55e24b2f3..84dfdd4d4341b 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -489,7 +489,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut root_var_min_capture_list = typeck_results.closure_min_captures.remove(&closure_def_id).unwrap_or_default(); - for (place, capture_info) in capture_information.into_iter() { + for (mut place, capture_info) in capture_information.into_iter() { let var_hir_id = match place.base { PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, base => bug!("Expected upvar, found={:?}", base), @@ -530,14 +530,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Truncate the descendant (already in min_captures) to be same as the ancestor to handle any // possible change in capture mode. - let (_, descendant_capture_kind) = truncate_place_to_len( - possible_descendant.place, - possible_descendant.info.capture_kind, + truncate_place_to_len_and_update_capture_kind( + &mut possible_descendant.place, + &mut possible_descendant.info.capture_kind, place.projections.len(), ); - possible_descendant.info.capture_kind = descendant_capture_kind; - updated_capture_info = determine_capture_info(updated_capture_info, possible_descendant.info); @@ -561,14 +559,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Truncate the descendant (current place) to be same as the ancestor to handle any // possible change in capture mode. - let (_, descendant_capture_kind) = truncate_place_to_len( - place.clone(), - updated_capture_info.capture_kind, + truncate_place_to_len_and_update_capture_kind( + &mut place, + &mut updated_capture_info.capture_kind, possible_ancestor.place.projections.len(), ); - updated_capture_info.capture_kind = descendant_capture_kind; - possible_ancestor.info = determine_capture_info( possible_ancestor.info, updated_capture_info, @@ -1476,7 +1472,7 @@ fn restrict_repr_packed_field_ref_capture<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, place: &Place<'tcx>, - curr_borrow_kind: ty::UpvarCapture<'tcx>, + mut curr_borrow_kind: ty::UpvarCapture<'tcx>, ) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { let pos = place.projections.iter().enumerate().position(|(i, p)| { let ty = place.ty_before_projection(i); @@ -1508,13 +1504,13 @@ fn restrict_repr_packed_field_ref_capture<'tcx>( } }); - let place = place.clone(); + let mut place = place.clone(); if let Some(pos) = pos { - truncate_place_to_len(place, curr_borrow_kind, pos) - } else { - (place, curr_borrow_kind) + truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_borrow_kind, pos); } + + (place, curr_borrow_kind) } /// Returns a Ty that applies the specified capture kind on the provided capture Ty @@ -1841,31 +1837,28 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { /// them completely. /// - No projections are applied on top of Union ADTs, since these require unsafe blocks. fn restrict_precision_for_unsafe( - place: Place<'tcx>, - curr_mode: ty::UpvarCapture<'tcx>, + mut place: Place<'tcx>, + mut curr_mode: ty::UpvarCapture<'tcx>, ) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { - if place.projections.is_empty() { - // Nothing to do here - return (place, curr_mode); - } - if place.base_ty.is_unsafe_ptr() { - return truncate_place_to_len(place, curr_mode, 0); + truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, 0); } if place.base_ty.is_union() { - return truncate_place_to_len(place, curr_mode, 0); + truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, 0); } for (i, proj) in place.projections.iter().enumerate() { if proj.ty.is_unsafe_ptr() { // Don't apply any projections on top of an unsafe ptr. - return truncate_place_to_len(place, curr_mode, i + 1); + truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i + 1); + break; } if proj.ty.is_union() { // Don't capture preicse fields of a union. - return truncate_place_to_len(place, curr_mode, i + 1); + truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i + 1); + break; } } @@ -1880,7 +1873,7 @@ fn restrict_capture_precision<'tcx>( place: Place<'tcx>, curr_mode: ty::UpvarCapture<'tcx>, ) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { - let (place, curr_mode) = restrict_precision_for_unsafe(place, curr_mode); + let (mut place, mut curr_mode) = restrict_precision_for_unsafe(place, curr_mode); if place.projections.is_empty() { // Nothing to do here @@ -1891,7 +1884,8 @@ fn restrict_capture_precision<'tcx>( match proj.kind { ProjectionKind::Index => { // Arrays are completely captured, so we drop Index projections - return truncate_place_to_len(place, curr_mode, i); + truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i); + return (place, curr_mode); } ProjectionKind::Deref => {} ProjectionKind::Field(..) => {} // ignore @@ -1906,8 +1900,8 @@ fn restrict_capture_precision<'tcx>( /// (or if closure attempts to move data that it doesn’t own). /// Note: When taking ownership, only capture data found on the stack. fn adjust_for_move_closure<'tcx>( - place: Place<'tcx>, - kind: ty::UpvarCapture<'tcx>, + mut place: Place<'tcx>, + mut kind: ty::UpvarCapture<'tcx>, ) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { let contains_deref_of_ref = place.deref_tys().any(|ty| ty.is_ref()); let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref); @@ -1917,52 +1911,38 @@ fn adjust_for_move_closure<'tcx>( // If there's any Deref and the data needs to be moved into the closure body, // or it's a Deref of a Box, truncate the path to the first deref - _ if first_deref.is_some() => { - let place = match first_deref { - Some(idx) => { - let (place, _) = truncate_place_to_len(place, kind, idx); - place - } - None => place, - }; + _ => { + if let Some(idx) = first_deref { + truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx); + } // AMAN: I think we don't need the span inside the ByValue anymore // we have more detailed span in CaptureInfo (place, ty::UpvarCapture::ByValue(None)) } - - _ => (place, ty::UpvarCapture::ByValue(None)), } } /// Adjust closure capture just that if taking ownership of data, only move data /// from enclosing stack frame. fn adjust_for_non_move_closure<'tcx>( - place: Place<'tcx>, + mut place: Place<'tcx>, mut kind: ty::UpvarCapture<'tcx>, ) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { let contains_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref); match kind { - ty::UpvarCapture::ByValue(..) if contains_deref.is_some() => { - let place = match contains_deref { - Some(idx) => { - let (place, new_kind) = truncate_place_to_len(place, kind, idx); - - kind = new_kind; - place - } - // Because of the if guard on the match on `kind`, we should never get here. - None => unreachable!(), - }; - - (place, kind) + ty::UpvarCapture::ByValue(..) => { + if let Some(idx) = contains_deref { + truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx); + } } - ty::UpvarCapture::ByValue(..) => (place, kind), - ty::UpvarCapture::ByRef(..) => (place, kind), + ty::UpvarCapture::ByRef(..) => {} } + + (place, kind) } fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String { @@ -2157,15 +2137,13 @@ fn determine_capture_info( /// /// Note: Capture kind changes from `MutBorrow` to `UniqueImmBorrow` if the truncated part of the `place` /// contained `Deref` of `&mut`. -fn truncate_place_to_len( - mut place: Place<'tcx>, - curr_mode: ty::UpvarCapture<'tcx>, +fn truncate_place_to_len_and_update_capture_kind( + place: &mut Place<'tcx>, + curr_mode: &mut ty::UpvarCapture<'tcx>, len: usize, -) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { +) { let is_mut_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Mut)); - let mut capture_kind = curr_mode; - // If the truncated part of the place contains `Deref` of a `&mut` then convert MutBorrow -> // UniqueImmBorrow // Note that if the place contained Deref of a raw pointer it would've not been MutBorrow, so @@ -2176,7 +2154,7 @@ fn truncate_place_to_len( if place.projections[i].kind == ProjectionKind::Deref && is_mut_ref(place.ty_before_projection(i)) { - capture_kind = ty::UpvarCapture::ByRef(ty::UpvarBorrow { + *curr_mode = ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: ty::BorrowKind::UniqueImmBorrow, region, }); @@ -2190,8 +2168,6 @@ fn truncate_place_to_len( } place.projections.truncate(len); - - (place, capture_kind) } /// Determines the Ancestry relationship of Place A relative to Place B @@ -2256,8 +2232,8 @@ fn determine_place_ancestry_relation( /// } /// ``` fn truncate_capture_for_optimization<'tcx>( - place: Place<'tcx>, - curr_mode: ty::UpvarCapture<'tcx>, + mut place: Place<'tcx>, + mut curr_mode: ty::UpvarCapture<'tcx>, ) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { let is_shared_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not)); @@ -2269,10 +2245,12 @@ fn truncate_capture_for_optimization<'tcx>( match idx { // If that pointer is a shared reference, then we don't need those fields. Some(idx) if is_shared_ref(place.ty_before_projection(idx)) => { - truncate_place_to_len(place, curr_mode, idx + 1) + truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, idx + 1) } - None | Some(_) => (place, curr_mode), + None | Some(_) => {} } + + (place, curr_mode) } /// Precise capture is enabled if the feature gate `capture_disjoint_fields` is enabled or if diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 0b3079fa59db6..0814652a5d47d 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1011,7 +1011,7 @@ impl Rc { /// mutate a shared value. /// /// See also [`make_mut`][make_mut], which will [`clone`][clone] - /// the inner value when there are other pointers. + /// the inner value when there are other `Rc` pointers. /// /// [make_mut]: Rc::make_mut /// [clone]: Clone::clone @@ -1100,10 +1100,12 @@ impl Rc { /// [`clone`] the inner value to a new allocation to ensure unique ownership. This is also /// referred to as clone-on-write. /// - /// If there are no other `Rc` pointers to this allocation, then [`Weak`] - /// pointers to this allocation will be disassociated. + /// However, if there are no other `Rc` pointers to this allocation, but some [`Weak`] + /// pointers, then the [`Weak`] pointers will be disassociated and the inner value will not + /// be cloned. /// - /// See also [`get_mut`], which will fail rather than cloning. + /// See also [`get_mut`], which will fail rather than cloning the inner value + /// or diassociating [`Weak`] pointers. /// /// [`clone`]: Clone::clone /// [`get_mut`]: Rc::get_mut @@ -1115,11 +1117,11 @@ impl Rc { /// /// let mut data = Rc::new(5); /// - /// *Rc::make_mut(&mut data) += 1; // Won't clone anything - /// let mut other_data = Rc::clone(&data); // Won't clone inner data - /// *Rc::make_mut(&mut data) += 1; // Clones inner data - /// *Rc::make_mut(&mut data) += 1; // Won't clone anything - /// *Rc::make_mut(&mut other_data) *= 2; // Won't clone anything + /// *Rc::make_mut(&mut data) += 1; // Won't clone anything + /// let mut other_data = Rc::clone(&data); // Won't clone inner data + /// *Rc::make_mut(&mut data) += 1; // Clones inner data + /// *Rc::make_mut(&mut data) += 1; // Won't clone anything + /// *Rc::make_mut(&mut other_data) *= 2; // Won't clone anything /// /// // Now `data` and `other_data` point to different allocations. /// assert_eq!(*data, 8); @@ -1743,7 +1745,7 @@ impl fmt::Pointer for Rc { #[cfg(not(no_global_oom_handling))] #[stable(feature = "from_for_ptrs", since = "1.6.0")] impl From for Rc { - /// Converts a generic type `T` into a `Rc` + /// Converts a generic type `T` into an `Rc` /// /// The conversion allocates on the heap and moves `t` /// from the stack into it. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 3183a6db410b8..a066e0b49e25c 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1346,18 +1346,19 @@ impl Receiver for Arc {} impl Arc { /// Makes a mutable reference into the given `Arc`. /// - /// If there are other `Arc` or [`Weak`] pointers to the same allocation, - /// then `make_mut` will create a new allocation and invoke [`clone`][clone] on the inner value - /// to ensure unique ownership. This is also referred to as clone-on-write. + /// If there are other `Arc` pointers to the same allocation, then `make_mut` will + /// [`clone`] the inner value to a new allocation to ensure unique ownership. This is also + /// referred to as clone-on-write. /// - /// Note that this differs from the behavior of [`Rc::make_mut`] which disassociates - /// any remaining `Weak` pointers. + /// However, if there are no other `Arc` pointers to this allocation, but some [`Weak`] + /// pointers, then the [`Weak`] pointers will be disassociated and the inner value will not + /// be cloned. /// - /// See also [`get_mut`][get_mut], which will fail rather than cloning. + /// See also [`get_mut`], which will fail rather than cloning the inner value + /// or diassociating [`Weak`] pointers. /// - /// [clone]: Clone::clone - /// [get_mut]: Arc::get_mut - /// [`Rc::make_mut`]: super::rc::Rc::make_mut + /// [`clone`]: Clone::clone + /// [`get_mut`]: Arc::get_mut /// /// # Examples /// @@ -1376,6 +1377,23 @@ impl Arc { /// assert_eq!(*data, 8); /// assert_eq!(*other_data, 12); /// ``` + /// + /// [`Weak`] pointers will be disassociated: + /// + /// ``` + /// use std::sync::Arc; + /// + /// let mut data = Arc::new(75); + /// let weak = Arc::downgrade(&data); + /// + /// assert!(75 == *data); + /// assert!(75 == *weak.upgrade().unwrap()); + /// + /// *Arc::make_mut(&mut data) += 1; + /// + /// assert!(76 == *data); + /// assert!(weak.upgrade().is_none()); + /// ``` #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "arc_unique", since = "1.4.0")] @@ -1441,7 +1459,7 @@ impl Arc { /// mutate a shared value. /// /// See also [`make_mut`][make_mut], which will [`clone`][clone] - /// the inner value when there are other pointers. + /// the inner value when there are other `Arc` pointers. /// /// [make_mut]: Arc::make_mut /// [clone]: Clone::clone diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs index 6a83f5da87cc8..a38b5c471bf06 100644 --- a/library/alloc/tests/boxed.rs +++ b/library/alloc/tests/boxed.rs @@ -35,11 +35,11 @@ fn box_clone_and_clone_from_equivalence() { } } -/// This test might give a false positive in case the box realocates, but the alocator keeps the -/// original pointer. +/// This test might give a false positive in case the box reallocates, +/// but the allocator keeps the original pointer. /// -/// On the other hand it won't give a false negative, if it fails than the memory was definitely not -/// reused +/// On the other hand, it won't give a false negative: If it fails, then the +/// memory was definitely not reused. #[test] fn box_clone_from_ptr_stability() { for size in (0..8).map(|i| 2usize.pow(i)) { diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index f0c934edf3977..85b43f4884760 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -576,6 +576,26 @@ impl Cell<[T]> { } } +impl Cell<[T; N]> { + /// Returns a `&[Cell; N]` from a `&Cell<[T; N]>` + /// + /// # Examples + /// + /// ``` + /// #![feature(as_array_of_cells)] + /// use std::cell::Cell; + /// + /// let mut array: [i32; 3] = [1, 2, 3]; + /// let cell_array: &Cell<[i32; 3]> = Cell::from_mut(&mut array); + /// let array_cell: &[Cell; 3] = cell_array.as_array_of_cells(); + /// ``` + #[unstable(feature = "as_array_of_cells", issue = "88248")] + pub fn as_array_of_cells(&self) -> &[Cell; N] { + // SAFETY: `Cell` has the same memory layout as `T`. + unsafe { &*(self as *const Cell<[T; N]> as *const [Cell; N]) } + } +} + /// A mutable memory location with dynamically checked borrow rules /// /// See the [module-level documentation](self) for more. diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 524d8f857e2a5..850435b53cc7e 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1957,8 +1957,8 @@ pub trait Iterator { /// assert_eq!(it.next(), Some(&40)); /// ``` /// - /// While you cannot `break` from a closure, the [`crate::ops::ControlFlow`] - /// type allows a similar idea: + /// While you cannot `break` from a closure, the [`ControlFlow`] type allows + /// a similar idea: /// /// ``` /// use std::ops::ControlFlow; @@ -2024,8 +2024,8 @@ pub trait Iterator { /// assert_eq!(it.next(), Some("stale_bread.json")); /// ``` /// - /// The [`crate::ops::ControlFlow`] type can be used with this method for the - /// situations in which you'd use `break` and `continue` in a normal loop: + /// The [`ControlFlow`] type can be used with this method for the situations + /// in which you'd use `break` and `continue` in a normal loop: /// /// ``` /// use std::ops::ControlFlow; @@ -2442,14 +2442,14 @@ pub trait Iterator { R: Try, // FIXME: This bound is rather strange, but means minimal breakage on nightly. // See #85115 for the issue tracking a holistic solution for this and try_map. - R: crate::ops::TryV2>, + R: Try>, { #[inline] fn check(mut f: F) -> impl FnMut((), T) -> ControlFlow> where F: FnMut(&T) -> R, R: Try, - R: crate::ops::TryV2>, + R: Try>, { move |(), x| match f(&x).branch() { ControlFlow::Continue(false) => ControlFlow::CONTINUE, diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index c2270c864dfae..cd2d57699c92c 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -63,7 +63,7 @@ pub enum ControlFlow { } #[unstable(feature = "try_trait_v2", issue = "84277")] -impl ops::TryV2 for ControlFlow { +impl ops::Try for ControlFlow { type Output = C; type Residual = ControlFlow; @@ -165,7 +165,7 @@ impl ControlFlow { /// These are used only as part of implementing the iterator adapters. /// They have mediocre names and non-obvious semantics, so aren't /// currently on a path to potential stabilization. -impl ControlFlow { +impl ControlFlow { /// Create a `ControlFlow` from any type implementing `Try`. #[inline] pub(crate) fn from_try(r: R) -> Self { diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 85e04740d96a4..bd7feb8b183ce 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -182,13 +182,7 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; #[unstable(feature = "try_trait_v2", issue = "84277")] -pub use self::try_trait::FromResidual; - -#[unstable(feature = "try_trait_v2", issue = "84277")] -pub use self::try_trait::Try; - -#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")] -pub(crate) use self::try_trait::Try as TryV2; +pub use self::try_trait::{FromResidual, Try}; #[unstable(feature = "generator_trait", issue = "43122")] pub use self::generator::{Generator, GeneratorState}; diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 78f5954532ff0..47865240f6a6f 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2013,7 +2013,7 @@ impl> FromIterator> for Option { } #[unstable(feature = "try_trait_v2", issue = "84277")] -impl ops::TryV2 for Option { +impl ops::Try for Option { type Output = T; type Residual = Option; diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 861790e8a4099..092e6544342b7 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1889,7 +1889,7 @@ impl> FromIterator> for Result { } #[unstable(feature = "try_trait_v2", issue = "84277")] -impl ops::TryV2 for Result { +impl ops::Try for Result { type Output = T; type Residual = Result; diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 36c2c4abdb4c5..8a31388fbdbbc 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -369,6 +369,22 @@ where // Instead of swapping one pair at the time, it is more efficient to perform a cyclic // permutation. This is not strictly equivalent to swapping, but produces a similar // result using fewer memory operations. + + // SAFETY: The use of `ptr::read` is valid because there is at least one element in + // both `offsets_l` and `offsets_r`, so `left!` is a valid pointer to read from. + // + // The uses of `left!` involve calls to `offset` on `l`, which points to the + // beginning of `v`. All the offsets pointed-to by `start_l` are at most `block_l`, so + // these `offset` calls are safe as all reads are within the block. The same argument + // applies for the uses of `right!`. + // + // The calls to `start_l.offset` are valid because there are at most `count-1` of them, + // plus the final one at the end of the unsafe block, where `count` is the minimum number + // of collected offsets in `offsets_l` and `offsets_r`, so there is no risk of there not + // being enough elements. The same reasoning applies to the calls to `start_r.offset`. + // + // The calls to `copy_nonoverlapping` are safe because `left!` and `right!` are guaranteed + // not to overlap, and are valid because of the reasoning above. unsafe { let tmp = ptr::read(left!()); ptr::copy_nonoverlapping(right!(), left!(), 1); @@ -389,11 +405,21 @@ where if start_l == end_l { // All out-of-order elements in the left block were moved. Move to the next block. + + // block-width-guarantee + // SAFETY: if `!is_done` then the slice width is guaranteed to be at least `2*BLOCK` wide. There + // are at most `BLOCK` elements in `offsets_l` because of its size, so the `offset` operation is + // safe. Otherwise, the debug assertions in the `is_done` case guarantee that + // `width(l, r) == block_l + block_r`, namely, that the block sizes have been adjusted to account + // for the smaller number of remaining elements. l = unsafe { l.offset(block_l as isize) }; } if start_r == end_r { // All out-of-order elements in the right block were moved. Move to the previous block. + + // SAFETY: Same argument as [block-width-guarantee]. Either this is a full block `2*BLOCK`-wide, + // or `block_r` has been adjusted for the last handful of elements. r = unsafe { r.offset(-(block_r as isize)) }; } diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index fc0a4e747973a..2507046099632 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -222,7 +222,7 @@ impl From for Poll { } #[unstable(feature = "try_trait_v2", issue = "84277")] -impl ops::TryV2 for Poll> { +impl ops::Try for Poll> { type Output = Poll; type Residual = Result; @@ -252,7 +252,7 @@ impl> ops::FromResidual> for Pol } #[unstable(feature = "try_trait_v2", issue = "84277")] -impl ops::TryV2 for Poll>> { +impl ops::Try for Poll>> { type Output = Poll>; type Residual = Result; diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 0d082648591ce..de05c37785295 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -958,7 +958,7 @@ impl From<&CStr> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { - /// Converts a [`CString`] into a [`Rc`]`` without copying or allocating. + /// Converts a [`CString`] into an [`Rc`]`` without copying or allocating. #[inline] fn from(s: CString) -> Rc { let rc: Rc<[u8]> = Rc::from(s.into_inner()); diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index f05295f89af1f..21f354caf6ae9 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -916,7 +916,7 @@ impl From<&OsStr> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { - /// Converts an [`OsString`] into a [`Rc`]`` without copying or allocating. + /// Converts an [`OsString`] into an [`Rc`]`` without copying or allocating. #[inline] fn from(s: OsString) -> Rc { let rc = s.inner.into_rc(); diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 9da5fbff9cf02..df60af7c36a3e 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -323,7 +323,6 @@ impl BufWriter { /// # Examples /// /// ``` - /// #![feature(bufwriter_into_parts)] /// use std::io::{BufWriter, Write}; /// /// let mut buffer = [0u8; 10]; @@ -334,7 +333,7 @@ impl BufWriter { /// assert_eq!(recovered_writer.len(), 0); /// assert_eq!(&buffered_data.unwrap(), b"ata"); /// ``` - #[unstable(feature = "bufwriter_into_parts", issue = "80690")] + #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] pub fn into_parts(mut self) -> (W, Result, WriterPanicked>) { let buf = mem::take(&mut self.buf); let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) }; @@ -444,14 +443,13 @@ impl BufWriter { } } -#[unstable(feature = "bufwriter_into_parts", issue = "80690")] +#[stable(feature = "bufwriter_into_parts", since = "1.56.0")] /// Error returned for the buffered data from `BufWriter::into_parts`, when the underlying /// writer has previously panicked. Contains the (possibly partly written) buffered data. /// /// # Example /// /// ``` -/// #![feature(bufwriter_into_parts)] /// use std::io::{self, BufWriter, Write}; /// use std::panic::{catch_unwind, AssertUnwindSafe}; /// @@ -478,7 +476,7 @@ pub struct WriterPanicked { impl WriterPanicked { /// Returns the perhaps-unwritten data. Some of this data may have been written by the /// panicking call(s) to the underlying writer, so simply writing it again is not a good idea. - #[unstable(feature = "bufwriter_into_parts", issue = "80690")] + #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] pub fn into_inner(self) -> Vec { self.buf } @@ -487,7 +485,7 @@ impl WriterPanicked { "BufWriter inner writer panicked, what data remains unwritten is not known"; } -#[unstable(feature = "bufwriter_into_parts", issue = "80690")] +#[stable(feature = "bufwriter_into_parts", since = "1.56.0")] impl error::Error for WriterPanicked { #[allow(deprecated, deprecated_in_future)] fn description(&self) -> &str { @@ -495,14 +493,14 @@ impl error::Error for WriterPanicked { } } -#[unstable(feature = "bufwriter_into_parts", issue = "80690")] +#[stable(feature = "bufwriter_into_parts", since = "1.56.0")] impl fmt::Display for WriterPanicked { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", Self::DESCRIPTION) } } -#[unstable(feature = "bufwriter_into_parts", issue = "80690")] +#[stable(feature = "bufwriter_into_parts", since = "1.56.0")] impl fmt::Debug for WriterPanicked { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("WriterPanicked") diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs index 8cfffc2fd35a4..179bdf7fe553a 100644 --- a/library/std/src/io/buffered/mod.rs +++ b/library/std/src/io/buffered/mod.rs @@ -14,7 +14,7 @@ use crate::io::Error; pub use bufreader::BufReader; pub use bufwriter::BufWriter; -#[unstable(feature = "bufwriter_into_parts", issue = "80690")] +#[stable(feature = "bufwriter_into_parts", since = "1.56.0")] pub use bufwriter::WriterPanicked; pub use linewriter::LineWriter; use linewritershim::LineWriterShim; diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 829ef3d98bbc9..51666c0a3c7f1 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -261,19 +261,15 @@ pub enum ErrorKind { #[stable(feature = "rust1", since = "1.0.0")] Interrupted, - /// A custom error that does not fall under any other I/O error kind. - /// - /// This can be used to construct your own [`Error`]s that do not match any - /// [`ErrorKind`]. - /// - /// This [`ErrorKind`] is not used by the standard library. + /// This operation is unsupported on this platform. /// - /// Errors from the standard library that do not fall under any of the I/O - /// error kinds cannot be `match`ed on, and will only match a wildcard (`_`) pattern. - /// New [`ErrorKind`]s might be added in the future for some of those. - #[stable(feature = "rust1", since = "1.0.0")] - Other, + /// This means that the operation can never succeed. + #[stable(feature = "unsupported_error", since = "1.53.0")] + Unsupported, + // ErrorKinds which are primarily categorisations for OS error + // codes should be added above. + // /// An error returned when an operation could not be completed because an /// "end of file" was reached prematurely. /// @@ -283,17 +279,28 @@ pub enum ErrorKind { #[stable(feature = "read_exact", since = "1.6.0")] UnexpectedEof, - /// This operation is unsupported on this platform. - /// - /// This means that the operation can never succeed. - #[stable(feature = "unsupported_error", since = "1.53.0")] - Unsupported, - /// An operation could not be completed, because it failed /// to allocate enough memory. #[stable(feature = "out_of_memory_error", since = "1.54.0")] OutOfMemory, + // "Unusual" error kinds which do not correspond simply to (sets + // of) OS error codes, should be added just above this comment. + // `Other` and `Uncategorised` should remain at the end: + // + /// A custom error that does not fall under any other I/O error kind. + /// + /// This can be used to construct your own [`Error`]s that do not match any + /// [`ErrorKind`]. + /// + /// This [`ErrorKind`] is not used by the standard library. + /// + /// Errors from the standard library that do not fall under any of the I/O + /// error kinds cannot be `match`ed on, and will only match a wildcard (`_`) pattern. + /// New [`ErrorKind`]s might be added in the future for some of those. + #[stable(feature = "rust1", since = "1.0.0")] + Other, + /// Any I/O error from the standard library that's not part of this list. /// /// Errors that are `Uncategorized` now may move to a different or a new @@ -307,13 +314,13 @@ pub enum ErrorKind { impl ErrorKind { pub(crate) fn as_str(&self) -> &'static str { use ErrorKind::*; + // Strictly alphabetical, please. (Sadly rustfmt cannot do this yet.) match *self { AddrInUse => "address in use", AddrNotAvailable => "address not available", AlreadyExists => "entity already exists", ArgumentListTooLong => "argument list too long", BrokenPipe => "broken pipe", - ResourceBusy => "resource busy", ConnectionAborted => "connection aborted", ConnectionRefused => "connection refused", ConnectionReset => "connection reset", @@ -321,9 +328,10 @@ impl ErrorKind { Deadlock => "deadlock", DirectoryNotEmpty => "directory not empty", ExecutableFileBusy => "executable file busy", + FileTooLarge => "file too large", FilenameTooLong => "filename too long", + FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)", FilesystemQuotaExceeded => "filesystem quota exceeded", - FileTooLarge => "file too large", HostUnreachable => "host unreachable", Interrupted => "operation interrupted", InvalidData => "invalid data", @@ -332,16 +340,16 @@ impl ErrorKind { NetworkDown => "network down", NetworkUnreachable => "network unreachable", NotADirectory => "not a directory", - StorageFull => "no storage space", NotConnected => "not connected", NotFound => "entity not found", + NotSeekable => "seek on unseekable file", Other => "other error", OutOfMemory => "out of memory", PermissionDenied => "permission denied", ReadOnlyFilesystem => "read-only filesystem or storage medium", + ResourceBusy => "resource busy", StaleNetworkFileHandle => "stale network file handle", - FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)", - NotSeekable => "seek on unseekable file", + StorageFull => "no storage space", TimedOut => "timed out", TooManyLinks => "too many links", Uncategorized => "uncategorized error", diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 28254fea0d374..e8466fa06b899 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -264,7 +264,7 @@ use crate::sys_common::memchr; #[stable(feature = "rust1", since = "1.0.0")] pub use self::buffered::IntoInnerError; -#[unstable(feature = "bufwriter_into_parts", issue = "80690")] +#[stable(feature = "bufwriter_into_parts", since = "1.56.0")] pub use self::buffered::WriterPanicked; #[stable(feature = "rust1", since = "1.0.0")] pub use self::buffered::{BufReader, BufWriter, LineWriter}; diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 3faf38c66ec8b..e34768bc2c906 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -301,6 +301,7 @@ def default_build_triple(verbose): 'ppc': 'powerpc', 'ppc64': 'powerpc64', 'ppc64le': 'powerpc64le', + 'riscv64': 'riscv64gc', 's390x': 's390x', 'x64': 'x86_64', 'x86': 'i686', diff --git a/src/doc/book b/src/doc/book index 7e49659102f09..687e21bde2ea1 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 7e49659102f0977d9142190e1ba23345c0f00eb1 +Subproject commit 687e21bde2ea10c261f79fa14797c5137425098d diff --git a/src/doc/reference b/src/doc/reference index 4884fe45c14f8..da6ea9b03f74c 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 4884fe45c14f8b22121760fb117181bb4da8dfe0 +Subproject commit da6ea9b03f74cae0a292f40315723d7a3a973637 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 0dc9cd4e89f00..04f489c889235 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 0dc9cd4e89f00cb5230f120e1a083916386e422b +Subproject commit 04f489c889235fe3b6dfe678ae5410d07deda958 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index c4644b427cbda..cf0e151b7925a 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit c4644b427cbdaafc7a87be0ccdf5d8aaa07ac35f +Subproject commit cf0e151b7925a40f13fbc6573c6f97d5f94c7c17 diff --git a/src/test/ui/asm/named-asm-labels.rs b/src/test/ui/asm/named-asm-labels.rs index 803501b40b68e..9f487bd8061fc 100644 --- a/src/test/ui/asm/named-asm-labels.rs +++ b/src/test/ui/asm/named-asm-labels.rs @@ -1,6 +1,14 @@ // only-x86_64 -#![feature(asm, global_asm)] +// Tests that the use of named labels in the `asm!` macro are linted against +// except for in `#[naked]` fns. +// Using a named label is incorrect as per the RFC because for most cases +// the compiler cannot ensure that inline asm is emitted exactly once per +// codegen unit (except for naked fns) and so the label could be duplicated +// which causes less readable LLVM errors and in the worst cases causes ICEs +// or segfaults based on system dependent behavior and codegen flags. + +#![feature(asm, global_asm, naked_functions)] #[no_mangle] pub static FOO: usize = 42; @@ -126,5 +134,61 @@ fn main() { } } +// Trigger on naked fns too, even though they can't be inlined, reusing a +// label or LTO can cause labels to break +#[naked] +pub extern "C" fn foo() -> i32 { + unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } //~ ERROR avoid using named labels +} + +// Make sure that non-naked attributes *do* still let the lint happen +#[no_mangle] +pub extern "C" fn bar() { + unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } + //~^ ERROR avoid using named labels +} + +#[naked] +pub extern "C" fn aaa() { + fn _local() {} + + unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } //~ ERROR avoid using named labels +} + +pub fn normal() { + fn _local1() {} + + #[naked] + pub extern "C" fn bbb() { + fn _very_local() {} + + unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } //~ ERROR avoid using named labels + } + + fn _local2() {} +} + +// Make sure that the lint happens within closures +fn closures() { + || unsafe { + asm!("closure1: nop"); //~ ERROR avoid using named labels + }; + + move || unsafe { + asm!("closure2: nop"); //~ ERROR avoid using named labels + }; + + || { + #[naked] + unsafe extern "C" fn _nested() { + asm!("ret;", options(noreturn)); + } + + unsafe { + asm!("closure3: nop"); //~ ERROR avoid using named labels + } + }; +} + // Don't trigger on global asm global_asm!("aaaaaaaa: nop"); diff --git a/src/test/ui/asm/named-asm-labels.stderr b/src/test/ui/asm/named-asm-labels.stderr index 3c4a4db75e02d..396f0a1942428 100644 --- a/src/test/ui/asm/named-asm-labels.stderr +++ b/src/test/ui/asm/named-asm-labels.stderr @@ -1,5 +1,5 @@ error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:11:15 + --> $DIR/named-asm-labels.rs:19:15 | LL | asm!("bar: nop"); | ^^^ @@ -9,7 +9,7 @@ LL | asm!("bar: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:14:15 + --> $DIR/named-asm-labels.rs:22:15 | LL | asm!("abcd:"); | ^^^^ @@ -18,7 +18,7 @@ LL | asm!("abcd:"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:17:15 + --> $DIR/named-asm-labels.rs:25:15 | LL | asm!("foo: bar1: nop"); | ^^^ ^^^^ @@ -27,7 +27,7 @@ LL | asm!("foo: bar1: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:21:15 + --> $DIR/named-asm-labels.rs:29:15 | LL | asm!("foo1: nop", "nop"); | ^^^^ @@ -36,7 +36,7 @@ LL | asm!("foo1: nop", "nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:22:15 + --> $DIR/named-asm-labels.rs:30:15 | LL | asm!("foo2: foo3: nop", "nop"); | ^^^^ ^^^^ @@ -45,7 +45,7 @@ LL | asm!("foo2: foo3: nop", "nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:24:22 + --> $DIR/named-asm-labels.rs:32:22 | LL | asm!("nop", "foo4: nop"); | ^^^^ @@ -54,7 +54,7 @@ LL | asm!("nop", "foo4: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:25:15 + --> $DIR/named-asm-labels.rs:33:15 | LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ @@ -63,7 +63,7 @@ LL | asm!("foo5: nop", "foo6: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:25:28 + --> $DIR/named-asm-labels.rs:33:28 | LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ @@ -72,7 +72,7 @@ LL | asm!("foo5: nop", "foo6: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:30:15 + --> $DIR/named-asm-labels.rs:38:15 | LL | asm!("foo7: nop; foo8: nop"); | ^^^^ ^^^^ @@ -81,7 +81,7 @@ LL | asm!("foo7: nop; foo8: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:32:15 + --> $DIR/named-asm-labels.rs:40:15 | LL | asm!("foo9: nop; nop"); | ^^^^ @@ -90,7 +90,7 @@ LL | asm!("foo9: nop; nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:33:20 + --> $DIR/named-asm-labels.rs:41:20 | LL | asm!("nop; foo10: nop"); | ^^^^^ @@ -99,7 +99,7 @@ LL | asm!("nop; foo10: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:36:15 + --> $DIR/named-asm-labels.rs:44:15 | LL | asm!("bar2: nop\n bar3: nop"); | ^^^^ ^^^^ @@ -108,7 +108,7 @@ LL | asm!("bar2: nop\n bar3: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:38:15 + --> $DIR/named-asm-labels.rs:46:15 | LL | asm!("bar4: nop\n nop"); | ^^^^ @@ -117,7 +117,7 @@ LL | asm!("bar4: nop\n nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:39:21 + --> $DIR/named-asm-labels.rs:47:21 | LL | asm!("nop\n bar5: nop"); | ^^^^ @@ -126,7 +126,7 @@ LL | asm!("nop\n bar5: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:40:21 + --> $DIR/named-asm-labels.rs:48:21 | LL | asm!("nop\n bar6: bar7: nop"); | ^^^^ ^^^^ @@ -135,7 +135,7 @@ LL | asm!("nop\n bar6: bar7: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:46:13 + --> $DIR/named-asm-labels.rs:54:13 | LL | blah2: nop | ^^^^^ @@ -146,7 +146,7 @@ LL | blah3: nop = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:55:19 + --> $DIR/named-asm-labels.rs:63:19 | LL | nop ; blah4: nop | ^^^^^ @@ -155,7 +155,7 @@ LL | nop ; blah4: nop = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:69:15 + --> $DIR/named-asm-labels.rs:77:15 | LL | asm!("blah1: 2bar: nop"); | ^^^^^ @@ -164,7 +164,7 @@ LL | asm!("blah1: 2bar: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:72:15 + --> $DIR/named-asm-labels.rs:80:15 | LL | asm!("def: def: nop"); | ^^^ @@ -173,7 +173,7 @@ LL | asm!("def: def: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:73:15 + --> $DIR/named-asm-labels.rs:81:15 | LL | asm!("def: nop\ndef: nop"); | ^^^ @@ -182,7 +182,7 @@ LL | asm!("def: nop\ndef: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:74:15 + --> $DIR/named-asm-labels.rs:82:15 | LL | asm!("def: nop; def: nop"); | ^^^ @@ -191,7 +191,7 @@ LL | asm!("def: nop; def: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:82:15 + --> $DIR/named-asm-labels.rs:90:15 | LL | asm!("fooo\u{003A} nop"); | ^^^^^^^^^^^^^^^^ @@ -200,7 +200,7 @@ LL | asm!("fooo\u{003A} nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:83:15 + --> $DIR/named-asm-labels.rs:91:15 | LL | asm!("foooo\x3A nop"); | ^^^^^^^^^^^^^ @@ -209,7 +209,7 @@ LL | asm!("foooo\x3A nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:86:15 + --> $DIR/named-asm-labels.rs:94:15 | LL | asm!("fooooo:\u{000A} nop"); | ^^^^^^ @@ -218,7 +218,7 @@ LL | asm!("fooooo:\u{000A} nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:87:15 + --> $DIR/named-asm-labels.rs:95:15 | LL | asm!("foooooo:\x0A nop"); | ^^^^^^^ @@ -227,7 +227,7 @@ LL | asm!("foooooo:\x0A nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:91:14 + --> $DIR/named-asm-labels.rs:99:14 | LL | asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -236,7 +236,7 @@ LL | asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:102:13 + --> $DIR/named-asm-labels.rs:110:13 | LL | ab: nop // ab: does foo | ^^ @@ -245,7 +245,7 @@ LL | ab: nop // ab: does foo = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:114:14 + --> $DIR/named-asm-labels.rs:122:14 | LL | asm!(include_str!("named-asm-labels.s")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -254,18 +254,81 @@ LL | asm!(include_str!("named-asm-labels.s")); = note: see the asm section of the unstable book for more information warning: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:124:19 + --> $DIR/named-asm-labels.rs:132:19 | LL | asm!("warned: nop"); | ^^^^^^ | note: the lint level is defined here - --> $DIR/named-asm-labels.rs:122:16 + --> $DIR/named-asm-labels.rs:130:16 | LL | #[warn(named_asm_labels)] | ^^^^^^^^^^^^^^^^ = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of the unstable book for more information -error: aborting due to 28 previous errors; 1 warning emitted +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:141:20 + | +LL | unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } + | ^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of the unstable book for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:147:20 + | +LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } + | ^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of the unstable book for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:155:20 + | +LL | unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } + | ^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of the unstable book for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:165:24 + | +LL | unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } + | ^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of the unstable book for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:174:15 + | +LL | asm!("closure1: nop"); + | ^^^^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of the unstable book for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:178:15 + | +LL | asm!("closure2: nop"); + | ^^^^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of the unstable book for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:188:19 + | +LL | asm!("closure3: nop"); + | ^^^^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of the unstable book for more information + +error: aborting due to 35 previous errors; 1 warning emitted diff --git a/src/test/ui/drop/dropck_legal_cycles.rs b/src/test/ui/drop/dropck_legal_cycles.rs index fb13fd764bfaf..27a599315dc1c 100644 --- a/src/test/ui/drop/dropck_legal_cycles.rs +++ b/src/test/ui/drop/dropck_legal_cycles.rs @@ -368,7 +368,7 @@ pub fn main() { // We can use refcells if we're single-threaded (as this test is). // If one were to generalize these constructions to a // multi-threaded context, then it might seem like we could choose - // between either a RwLock or a Mutex to hold the owned arcs on + // between either an RwLock or a Mutex to hold the owned arcs on // each node. // // Part of the point of this test is to actually confirm that the diff --git a/src/test/ui/rfcs/rfc-1789-as-cell/from-mut.rs b/src/test/ui/rfcs/rfc-1789-as-cell/from-mut.rs index ea3ad7aed4926..329fadb150fcd 100644 --- a/src/test/ui/rfcs/rfc-1789-as-cell/from-mut.rs +++ b/src/test/ui/rfcs/rfc-1789-as-cell/from-mut.rs @@ -1,5 +1,7 @@ // run-pass +#![feature(as_array_of_cells)] + use std::cell::Cell; fn main() { @@ -8,4 +10,11 @@ fn main() { let slice_cell: &[Cell] = cell_slice.as_slice_of_cells(); assert_eq!(slice_cell.len(), 3); + + let mut array: [i32; 3] = [1, 2, 3]; + let cell_array: &Cell<[i32; 3]> = Cell::from_mut(&mut array); + let array_cell: &[Cell; 3] = cell_array.as_array_of_cells(); + + array_cell[0].set(99); + assert_eq!(array, [99, 2, 3]); } diff --git a/src/test/ui/type-alias-impl-trait/type_of_a_let.rs b/src/test/ui/type-alias-impl-trait/type_of_a_let.rs new file mode 100644 index 0000000000000..7f8e6127cca3b --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/type_of_a_let.rs @@ -0,0 +1,29 @@ +#![feature(type_alias_impl_trait)] +#![allow(dead_code)] + +// FIXME This should compile, but it currently doesn't + +use std::fmt::Debug; + +type Foo = impl Debug; +//~^ ERROR: could not find defining uses + +fn foo1() -> u32 { + let x: Foo = 22_u32; + //~^ ERROR: mismatched types [E0308] + x + //~^ ERROR: mismatched types [E0308] +} + +fn foo2() -> u32 { + let x: Foo = 22_u32; + //~^ ERROR: mismatched types [E0308] + let y: Foo = x; + same_type((x, y)); + y + //~^ ERROR: mismatched types [E0308] +} + +fn same_type(x: (T, T)) {} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/type_of_a_let.stderr b/src/test/ui/type-alias-impl-trait/type_of_a_let.stderr new file mode 100644 index 0000000000000..cac8d6841afda --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/type_of_a_let.stderr @@ -0,0 +1,67 @@ +error[E0308]: mismatched types + --> $DIR/type_of_a_let.rs:12:18 + | +LL | type Foo = impl Debug; + | ---------- the expected opaque type +... +LL | let x: Foo = 22_u32; + | --- ^^^^^^ expected opaque type, found `u32` + | | + | expected due to this + | + = note: expected opaque type `impl Debug` + found type `u32` + +error[E0308]: mismatched types + --> $DIR/type_of_a_let.rs:14:5 + | +LL | type Foo = impl Debug; + | ---------- the found opaque type +... +LL | fn foo1() -> u32 { + | --- expected `u32` because of return type +... +LL | x + | ^ expected `u32`, found opaque type + | + = note: expected type `u32` + found opaque type `impl Debug` + +error[E0308]: mismatched types + --> $DIR/type_of_a_let.rs:19:18 + | +LL | type Foo = impl Debug; + | ---------- the expected opaque type +... +LL | let x: Foo = 22_u32; + | --- ^^^^^^ expected opaque type, found `u32` + | | + | expected due to this + | + = note: expected opaque type `impl Debug` + found type `u32` + +error[E0308]: mismatched types + --> $DIR/type_of_a_let.rs:23:5 + | +LL | type Foo = impl Debug; + | ---------- the found opaque type +... +LL | fn foo2() -> u32 { + | --- expected `u32` because of return type +... +LL | y + | ^ expected `u32`, found opaque type + | + = note: expected type `u32` + found opaque type `impl Debug` + +error: could not find defining uses + --> $DIR/type_of_a_let.rs:8:12 + | +LL | type Foo = impl Debug; + | ^^^^^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/type_of_a_let2.rs b/src/test/ui/type-alias-impl-trait/type_of_a_let2.rs new file mode 100644 index 0000000000000..33d3f164ce15e --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/type_of_a_let2.rs @@ -0,0 +1,25 @@ +#![feature(type_alias_impl_trait)] +#![allow(dead_code)] + +// FIXME This should be under a feature flag + +use std::fmt::Debug; + +fn foo1() -> u32 { + let x: impl Debug = 22_u32; + //~^ ERROR: `impl Trait` not allowed outside of function and method return types [E0562] + x // ERROR: we only know x: Debug, we don't know x = u32 +} + +fn foo2() -> u32 { + let x: impl Debug = 22_u32; + //~^ ERROR: `impl Trait` not allowed outside of function and method return types [E0562] + let y: impl Debug = x; + //~^ ERROR: `impl Trait` not allowed outside of function and method return types [E0562] + same_type((x, y)); // ERROR + x +} + +fn same_type(x: (T, T)) {} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/type_of_a_let2.stderr b/src/test/ui/type-alias-impl-trait/type_of_a_let2.stderr new file mode 100644 index 0000000000000..7a1825a8e2d9a --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/type_of_a_let2.stderr @@ -0,0 +1,21 @@ +error[E0562]: `impl Trait` not allowed outside of function and method return types + --> $DIR/type_of_a_let2.rs:9:12 + | +LL | let x: impl Debug = 22_u32; + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` not allowed outside of function and method return types + --> $DIR/type_of_a_let2.rs:15:12 + | +LL | let x: impl Debug = 22_u32; + | ^^^^^^^^^^ + +error[E0562]: `impl Trait` not allowed outside of function and method return types + --> $DIR/type_of_a_let2.rs:17:12 + | +LL | let y: impl Debug = x; + | ^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0562`.