diff --git a/.github/ISSUE_TEMPLATE/diagnostics.yaml b/.github/ISSUE_TEMPLATE/diagnostics.yaml index 873fbaaf654f..54bf2bc6ee24 100644 --- a/.github/ISSUE_TEMPLATE/diagnostics.yaml +++ b/.github/ISSUE_TEMPLATE/diagnostics.yaml @@ -52,10 +52,23 @@ body: render: Rust validations: required: false - - type: markdown + - type: textarea + id: version attributes: - value: | - If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. The output might also be different depending on the Edition. + label: Rust Version + description: Please provide the `rustc` version, `rustc --version --verbose`. Make sure that you're using the latest version of the compiler, and not an outdated stable or nightly release! + placeholder: | + $ rustc --version --verbose + rustc 1.XX.Y (SHORTHASH DATE) + binary: rustc + commit-hash: LONGHASHVALUE + commit-date: DATE + host: PLATFORMTRIPLE + release: 1.XX.Y + LLVM version: XX.YY.ZZ + render: Shell + validations: + required: true - type: textarea id: extra attributes: diff --git a/.github/ISSUE_TEMPLATE/ice.yaml b/.github/ISSUE_TEMPLATE/ice.yaml index 7bec05cc575a..13be13d4f998 100644 --- a/.github/ISSUE_TEMPLATE/ice.yaml +++ b/.github/ISSUE_TEMPLATE/ice.yaml @@ -40,7 +40,7 @@ body: id: version attributes: label: Rust Version - description: Please provide the `rustc` version, `rustc --version --verbose` + description: Please provide the `rustc` version, `rustc --version --verbose`. Make sure that you're using the latest version of the compiler, and not an outdated stable or nightly release! placeholder: | $ rustc --version --verbose rustc 1.XX.Y (SHORTHASH DATE) diff --git a/Cargo.lock b/Cargo.lock index 4dc8c69c7b24..75c7de4f405a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -704,9 +704,9 @@ checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335" [[package]] name = "compiler_builtins" -version = "0.1.103" +version = "0.1.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b73c3443a5fd2438d7ba4853c64e4c8efc2404a9e28a9234cc2d5eebc6c242" +checksum = "99c3f9035afc33f4358773239573f7d121099856753e1bbd2a6a5207098fc741" dependencies = [ "cc", "rustc-std-workspace-core", @@ -3738,6 +3738,7 @@ dependencies = [ "rustc_trait_selection", "rustc_ty_utils", "serde_json", + "shlex", "time", "tracing", "windows", @@ -3797,7 +3798,6 @@ dependencies = [ name = "rustc_expand" version = "0.0.0" dependencies = [ - "crossbeam-channel", "rustc_ast", "rustc_ast_passes", "rustc_ast_pretty", @@ -3877,6 +3877,7 @@ dependencies = [ "rustc_feature", "rustc_fluent_macro", "rustc_hir", + "rustc_hir_pretty", "rustc_index", "rustc_infer", "rustc_lint_defs", @@ -4644,6 +4645,7 @@ dependencies = [ "rustc_index", "rustc_macros", "rustc_serialize", + "rustc_span", "smallvec", ] diff --git a/Cargo.toml b/Cargo.toml index 9b11ae8744b4..039150788386 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,6 +104,14 @@ gimli.debug = 0 miniz_oxide.debug = 0 object.debug = 0 +# These are very thin wrappers around executing lld with the right binary name. +# Basically nothing within them can go wrong without having been explicitly logged anyway. +# We ship these in every rustc tarball and even after compression they add up +# to around 0.6MB of data every user needs to download (and 15MB on disk). +[profile.release.package.lld-wrapper] +debug = 0 +strip = true + [patch.crates-io] # See comments in `library/rustc-std-workspace-core/README.md` for what's going on # here diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 549927d58987..ea194e10defd 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -16,7 +16,7 @@ use rustc_data_structures::stable_hasher::StableOrd; #[cfg(feature = "nightly")] use rustc_macros::HashStable_Generic; #[cfg(feature = "nightly")] -use rustc_macros::{Decodable, Encodable}; +use rustc_macros::{Decodable_Generic, Encodable_Generic}; #[cfg(feature = "nightly")] use std::iter::Step; @@ -30,7 +30,7 @@ pub use layout::LayoutCalculator; pub trait HashStableContext {} #[derive(Clone, Copy, PartialEq, Eq, Default)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] +#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] pub struct ReprFlags(u8); bitflags! { @@ -52,7 +52,7 @@ bitflags! { rustc_data_structures::external_bitflags_debug! { ReprFlags } #[derive(Copy, Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] +#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] pub enum IntegerType { /// Pointer-sized integer type, i.e. `isize` and `usize`. The field shows signedness, e.g. /// `Pointer(true)` means `isize`. @@ -73,7 +73,7 @@ impl IntegerType { /// Represents the repr options provided by the user. #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] +#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] pub struct ReprOptions { pub int: Option, pub align: Option, @@ -412,7 +412,7 @@ impl FromStr for Endian { /// Size of a type in bytes. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] +#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] pub struct Size { raw: u64, } @@ -636,7 +636,7 @@ impl Step for Size { /// Alignment of a type in bytes (always a power of two). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] +#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] pub struct Align { pow2: u8, } @@ -777,7 +777,7 @@ impl AbiAndPrefAlign { /// Integers, also used for enum discriminants. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] +#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] pub enum Integer { I8, I16, diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 1812cc335a4f..e1e4e5fc5675 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -20,6 +20,7 @@ pub use crate::format::*; pub use crate::util::parser::ExprPrecedence; +pub use rustc_span::AttrId; pub use GenericArgs::*; pub use UnsafeSource::*; @@ -30,7 +31,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; use rustc_macros::HashStable_Generic; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; @@ -2682,22 +2682,6 @@ pub enum AttrStyle { Inner, } -rustc_index::newtype_index! { - #[orderable] - #[debug_format = "AttrId({})"] - pub struct AttrId {} -} - -impl Encodable for AttrId { - fn encode(&self, _s: &mut S) {} -} - -impl Decodable for AttrId { - default fn decode(_: &mut D) -> AttrId { - panic!("cannot decode `AttrId` with `{}`", std::any::type_name::()); - } -} - /// A list of attributes. pub type AttrVec = ThinVec; diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 053468ff936a..298c01a45674 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -21,8 +21,8 @@ use crate::AttrVec; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{self, Lrc}; use rustc_macros::HashStable_Generic; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_serialize::{Decodable, Encodable}; +use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; @@ -150,14 +150,14 @@ impl fmt::Debug for LazyAttrTokenStream { } } -impl Encodable for LazyAttrTokenStream { +impl Encodable for LazyAttrTokenStream { fn encode(&self, s: &mut S) { // Used by AST json printing. Encodable::encode(&self.to_attr_token_stream(), s); } } -impl Decodable for LazyAttrTokenStream { +impl Decodable for LazyAttrTokenStream { fn decode(_d: &mut D) -> Self { panic!("Attempted to decode LazyAttrTokenStream"); } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index fd94e7e9341d..e7177402db1d 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -35,7 +35,7 @@ ast_lowering_bad_return_type_notation_output = ast_lowering_base_expression_double_dot = base expression required after `..` - .label = add a base expression here + .suggestion = add a base expression here ast_lowering_clobber_abi_not_supported = `clobber_abi` is not supported on this target @@ -106,7 +106,8 @@ ast_lowering_misplaced_double_dot = .note = only allowed in tuple, tuple struct, and slice patterns ast_lowering_misplaced_impl_trait = - `impl Trait` only allowed in function and inherent method argument and return types, not in {$position} + `impl Trait` is not allowed in {$position} + .note = `impl Trait` is only allowed in arguments and return types of functions and methods ast_lowering_misplaced_relax_trait_bound = `?Trait` bounds are only permitted at the point where a type parameter is declared diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 710690d0d86a..2811fe104cd0 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -90,6 +90,7 @@ pub enum AssocTyParenthesesSub { #[derive(Diagnostic)] #[diag(ast_lowering_misplaced_impl_trait, code = "E0562")] +#[note] pub struct MisplacedImplTrait<'a> { #[primary_span] pub span: Span, @@ -113,10 +114,10 @@ pub struct UnderscoreExprLhsAssign { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_base_expression_double_dot)] +#[diag(ast_lowering_base_expression_double_dot, code = "E0797")] pub struct BaseExpressionDoubleDot { #[primary_span] - #[label] + #[suggestion(code = "/* expr */", applicability = "has-placeholders", style = "verbose")] pub span: Span, } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c618953461cf..d8de447e5b4c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -12,6 +12,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::PredicateOrigin; use rustc_index::{Idx, IndexSlice, IndexVec}; +use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{kw, sym, Ident}; @@ -182,7 +183,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs) } ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => { - let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); + let (ty, body_id) = + self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); hir::ItemKind::Static(ty, *m, body_id) } ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { @@ -191,7 +193,9 @@ impl<'hir> LoweringContext<'_, 'hir> { Const::No, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - |this| this.lower_const_item(ty, span, expr.as_deref()), + |this| { + this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy) + }, ); hir::ItemKind::Const(ty, generics, body_id) } @@ -448,8 +452,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ty: &Ty, span: Span, body: Option<&Expr>, + impl_trait_position: ImplTraitPosition, ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { - let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(impl_trait_position)); (ty, self.lower_const_body(span, body)) } @@ -572,23 +577,25 @@ impl<'hir> LoweringContext<'_, 'hir> { // This is used to track which lifetimes have already been defined, // and which need to be replicated when lowering an async fn. - match parent_hir.node().expect_item().kind { + let generics = match parent_hir.node().expect_item().kind { hir::ItemKind::Impl(impl_) => { self.is_in_trait_impl = impl_.of_trait.is_some(); + &impl_.generics } - hir::ItemKind::Trait(_, _, generics, _, _) if self.tcx.features().effects => { - self.host_param_id = generics - .params - .iter() - .find(|param| { - matches!( - param.kind, - hir::GenericParamKind::Const { is_host_effect: true, .. } - ) - }) - .map(|param| param.def_id); + hir::ItemKind::Trait(_, _, generics, _, _) => generics, + kind => { + span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr()) } - _ => {} + }; + + if self.tcx.features().effects { + self.host_param_id = generics + .params + .iter() + .find(|param| { + matches!(param.kind, hir::GenericParamKind::Const { is_host_effect: true, .. }) + }) + .map(|param| param.def_id); } match ctxt { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index fb59770d48a2..dc23b1dce7bf 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -304,8 +304,6 @@ enum ImplTraitPosition { ClosureParam, PointerParam, FnTraitParam, - TraitParam, - ImplParam, ExternFnReturn, ClosureReturn, PointerReturn, @@ -324,29 +322,27 @@ impl std::fmt::Display for ImplTraitPosition { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let name = match self { ImplTraitPosition::Path => "paths", - ImplTraitPosition::Variable => "variable bindings", + ImplTraitPosition::Variable => "the type of variable bindings", ImplTraitPosition::Trait => "traits", ImplTraitPosition::AsyncBlock => "async blocks", ImplTraitPosition::Bound => "bounds", ImplTraitPosition::Generic => "generics", - ImplTraitPosition::ExternFnParam => "`extern fn` params", - ImplTraitPosition::ClosureParam => "closure params", - ImplTraitPosition::PointerParam => "`fn` pointer params", - ImplTraitPosition::FnTraitParam => "`Fn` trait params", - ImplTraitPosition::TraitParam => "trait method params", - ImplTraitPosition::ImplParam => "`impl` method params", + ImplTraitPosition::ExternFnParam => "`extern fn` parameters", + ImplTraitPosition::ClosureParam => "closure parameters", + ImplTraitPosition::PointerParam => "`fn` pointer parameters", + ImplTraitPosition::FnTraitParam => "the parameters of `Fn` trait bounds", ImplTraitPosition::ExternFnReturn => "`extern fn` return types", ImplTraitPosition::ClosureReturn => "closure return types", ImplTraitPosition::PointerReturn => "`fn` pointer return types", - ImplTraitPosition::FnTraitReturn => "`Fn` trait return types", + ImplTraitPosition::FnTraitReturn => "the return type of `Fn` trait bounds", ImplTraitPosition::GenericDefault => "generic parameter defaults", ImplTraitPosition::ConstTy => "const types", ImplTraitPosition::StaticTy => "static types", ImplTraitPosition::AssocTy => "associated types", ImplTraitPosition::FieldTy => "field types", - ImplTraitPosition::Cast => "cast types", + ImplTraitPosition::Cast => "cast expression types", ImplTraitPosition::ImplSelf => "impl headers", - ImplTraitPosition::OffsetOf => "`offset_of!` params", + ImplTraitPosition::OffsetOf => "`offset_of!` parameters", }; write!(f, "{name}") @@ -364,19 +360,6 @@ enum FnDeclKind { Impl, } -impl FnDeclKind { - fn param_impl_trait_allowed(&self) -> bool { - matches!(self, FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait) - } - - fn return_impl_trait_allowed(&self) -> bool { - match self { - FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => true, - _ => false, - } - } -} - #[derive(Copy, Clone)] enum AstOwner<'a> { NonOwner, @@ -1842,19 +1825,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { inputs = &inputs[..inputs.len() - 1]; } let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| { - let itctx = if kind.param_impl_trait_allowed() { - ImplTraitContext::Universal - } else { - ImplTraitContext::Disallowed(match kind { - FnDeclKind::Fn | FnDeclKind::Inherent => { - unreachable!("fn should allow APIT") - } - FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam, - FnDeclKind::Closure => ImplTraitPosition::ClosureParam, - FnDeclKind::Pointer => ImplTraitPosition::PointerParam, - FnDeclKind::Trait => ImplTraitPosition::TraitParam, - FnDeclKind::Impl => ImplTraitPosition::ImplParam, - }) + let itctx = match kind { + FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => { + ImplTraitContext::Universal + } + FnDeclKind::ExternFn => { + ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnParam) + } + FnDeclKind::Closure => { + ImplTraitContext::Disallowed(ImplTraitPosition::ClosureParam) + } + FnDeclKind::Pointer => { + ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam) + } }; self.lower_ty_direct(¶m.ty, &itctx) })); @@ -1866,26 +1849,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } None => match &decl.output { FnRetTy::Ty(ty) => { - let context = if kind.return_impl_trait_allowed() { - let fn_def_id = self.local_def_id(fn_node_id); - ImplTraitContext::ReturnPositionOpaqueTy { - origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), + let itctx = match kind { + FnDeclKind::Fn + | FnDeclKind::Inherent + | FnDeclKind::Trait + | FnDeclKind::Impl => ImplTraitContext::ReturnPositionOpaqueTy { + origin: hir::OpaqueTyOrigin::FnReturn(self.local_def_id(fn_node_id)), fn_kind: kind, + }, + FnDeclKind::ExternFn => { + ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnReturn) + } + FnDeclKind::Closure => { + ImplTraitContext::Disallowed(ImplTraitPosition::ClosureReturn) + } + FnDeclKind::Pointer => { + ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn) } - } else { - ImplTraitContext::Disallowed(match kind { - FnDeclKind::Fn - | FnDeclKind::Inherent - | FnDeclKind::Trait - | FnDeclKind::Impl => { - unreachable!("fn should allow return-position impl trait in traits") - } - FnDeclKind::ExternFn => ImplTraitPosition::ExternFnReturn, - FnDeclKind::Closure => ImplTraitPosition::ClosureReturn, - FnDeclKind::Pointer => ImplTraitPosition::PointerReturn, - }) }; - hir::FnRetTy::Return(self.lower_ty(ty, &context)) + hir::FnRetTy::Return(self.lower_ty(ty, &itctx)) } FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)), }, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2b746789a769..35b8de64af7e 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -23,7 +23,7 @@ macro_rules! gate { ($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{ if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { feature_err(&$visitor.sess.parse_sess, sym::$feature, $span, $explain) - .help($help) + .help_mv($help) .emit(); } }}; diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index fdb5d66bf62b..5f61a56c189a 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -54,13 +54,12 @@ pub(crate) struct UnknownMetaItem<'a> { impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnknownMetaItem<'_> { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::>(); - let mut diag = DiagnosticBuilder::new(dcx, level, fluent::attr_unknown_meta_item); - diag.span(self.span); - diag.code(error_code!(E0541)); - diag.arg("item", self.item); - diag.arg("expected", expected.join(", ")); - diag.span_label(self.span, fluent::attr_label); - diag + DiagnosticBuilder::new(dcx, level, fluent::attr_unknown_meta_item) + .span_mv(self.span) + .code_mv(error_code!(E0541)) + .arg_mv("item", self.item) + .arg_mv("expected", expected.join(", ")) + .span_label_mv(self.span, fluent::attr_label) } } diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 900b78910196..a9fc0a6f415d 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -31,17 +31,15 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { borrow_span: Span, borrow_desc: &str, ) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( + struct_span_err!( self.dcx(), span, E0503, "cannot use {} because it was mutably borrowed", desc, - ); - - err.span_label(borrow_span, format!("{borrow_desc} is borrowed here")); - err.span_label(span, format!("use of borrowed {borrow_desc}")); - err + ) + .span_label_mv(borrow_span, format!("{borrow_desc} is borrowed here")) + .span_label_mv(span, format!("use of borrowed {borrow_desc}")) } pub(crate) fn cannot_mutably_borrow_multiply( @@ -238,17 +236,15 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { borrow_span: Span, desc: &str, ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( + struct_span_err!( self.dcx(), span, E0506, "cannot assign to {} because it is borrowed", desc, - ); - - err.span_label(borrow_span, format!("{desc} is borrowed here")); - err.span_label(span, format!("{desc} is assigned to here but it was already borrowed")); - err + ) + .span_label_mv(borrow_span, format!("{desc} is borrowed here")) + .span_label_mv(span, format!("{desc} is assigned to here but it was already borrowed")) } pub(crate) fn cannot_reassign_immutable( @@ -287,16 +283,15 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { (&ty::Slice(_), _) => "slice", _ => span_bug!(move_from_span, "this path should not cause illegal move"), }; - let mut err = struct_span_err!( + struct_span_err!( self.dcx(), move_from_span, E0508, "cannot move out of type `{}`, a non-copy {}", ty, type_name, - ); - err.span_label(move_from_span, "cannot move out of here"); - err + ) + .span_label_mv(move_from_span, "cannot move out of here") } pub(crate) fn cannot_move_out_of_interior_of_drop( @@ -304,15 +299,14 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { move_from_span: Span, container_ty: Ty<'_>, ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( + struct_span_err!( self.dcx(), move_from_span, E0509, "cannot move out of type `{}`, which implements the `Drop` trait", container_ty, - ); - err.span_label(move_from_span, "cannot move out of here"); - err + ) + .span_label_mv(move_from_span, "cannot move out of here") } pub(crate) fn cannot_act_on_moved_value( @@ -352,7 +346,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { immutable_section: &str, action: &str, ) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( + struct_span_err!( self.dcx(), mutate_span, E0510, @@ -360,10 +354,9 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { action, immutable_place, immutable_section, - ); - err.span_label(mutate_span, format!("cannot {action}")); - err.span_label(immutable_span, format!("value is immutable in {immutable_section}")); - err + ) + .span_label_mv(mutate_span, format!("cannot {action}")) + .span_label_mv(immutable_span, format!("value is immutable in {immutable_section}")) } pub(crate) fn cannot_borrow_across_coroutine_yield( @@ -372,14 +365,13 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { yield_span: Span, ) -> DiagnosticBuilder<'tcx> { let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind; - let mut err = struct_span_err!( + struct_span_err!( self.dcx(), span, E0626, "borrow may still be in use when {coroutine_kind:#} yields", - ); - err.span_label(yield_span, "possible yield occurs here"); - err + ) + .span_label_mv(yield_span, "possible yield occurs here") } pub(crate) fn cannot_borrow_across_destructor( @@ -409,7 +401,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { reference_desc: &str, path_desc: &str, ) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( + struct_span_err!( self.dcx(), span, E0515, @@ -417,14 +409,11 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { RETURN = return_kind, REFERENCE = reference_desc, LOCAL = path_desc, - ); - - err.span_label( + ) + .span_label_mv( span, format!("{return_kind}s a {reference_desc} data owned by the current function"), - ); - - err + ) } pub(crate) fn cannot_capture_in_long_lived_closure( @@ -435,16 +424,15 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { capture_span: Span, scope: &str, ) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( + struct_span_err!( self.dcx(), closure_span, E0373, "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \ which is owned by the current {scope}", - ); - err.span_label(capture_span, format!("{borrowed_path} is borrowed here")) - .span_label(closure_span, format!("may outlive borrowed value {borrowed_path}")); - err + ) + .span_label_mv(capture_span, format!("{borrowed_path} is borrowed here")) + .span_label_mv(closure_span, format!("may outlive borrowed value {borrowed_path}")) } pub(crate) fn thread_local_value_does_not_live_long_enough( diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 9ce753134fbc..5baa108ed3cc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2218,15 +2218,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { drop_span, borrow_span ); - let mut err = self.thread_local_value_does_not_live_long_enough(borrow_span); - - err.span_label( - borrow_span, - "thread-local variables cannot be borrowed beyond the end of the function", - ); - err.span_label(drop_span, "end of enclosing function is here"); - - err + self.thread_local_value_does_not_live_long_enough(borrow_span) + .span_label_mv( + borrow_span, + "thread-local variables cannot be borrowed beyond the end of the function", + ) + .span_label_mv(drop_span, "end of enclosing function is here") } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index f3b21d22c1a5..50dde5ce636e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -329,15 +329,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let PlaceRef { local, projection: [] } = deref_base { let decl = &self.body.local_decls[local]; if decl.is_ref_for_guard() { - let mut err = self.cannot_move_out_of( - span, - &format!("`{}` in pattern guard", self.local_names[local].unwrap()), - ); - err.note( - "variables bound in patterns cannot be moved from \ + return self + .cannot_move_out_of( + span, + &format!("`{}` in pattern guard", self.local_names[local].unwrap()), + ) + .note_mv( + "variables bound in patterns cannot be moved from \ until after the end of the pattern guard", - ); - return err; + ); } else if decl.is_ref_to_static() { return self.report_cannot_move_from_static(move_place, span); } @@ -381,15 +381,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { closure_kind_ty, closure_kind, place_description, ); - let mut diag = self.cannot_move_out_of(span, &place_description); - - diag.span_label(upvar_span, "captured outer variable"); - diag.span_label( - self.infcx.tcx.def_span(def_id), - format!("captured by this `{closure_kind}` closure"), - ); - - diag + self.cannot_move_out_of(span, &place_description) + .span_label_mv(upvar_span, "captured outer variable") + .span_label_mv( + self.infcx.tcx.def_span(def_id), + format!("captured by this `{closure_kind}` closure"), + ) } _ => { let source = self.borrowed_content_source(deref_base); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index b3450b09cdf9..020429c19144 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -348,7 +348,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty); let named_key = self.regioncx.name_regions(self.infcx.tcx, key); let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region); - let mut diag = unexpected_hidden_region_diagnostic( + let diag = unexpected_hidden_region_diagnostic( self.infcx.tcx, span, named_ty, diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 093017ecba23..5f427a5ac801 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -421,7 +421,7 @@ fn check_opaque_type_parameter_valid( return Err(tcx .dcx() .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note(spans, format!("{descr} used multiple times")) + .span_note_mv(spans, format!("{descr} used multiple times")) .emit()); } } diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index b5801c1b0f16..d0e13fa3c0f3 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -458,7 +458,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option template_part, Err(err) => { - if let Some((mut err, _)) = err { + if let Some((err, _)) = err { err.emit(); } return None; @@ -693,13 +693,14 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option {} 1 => { let (sp, msg) = unused_operands.into_iter().next().unwrap(); - let mut err = ecx.dcx().struct_span_err(sp, msg); - err.span_label(sp, msg); - err.help(format!( - "if this argument is intentionally unused, \ - consider using it in an asm comment: `\"/*{help_str} */\"`" - )); - err.emit(); + ecx.dcx() + .struct_span_err(sp, msg) + .span_label_mv(sp, msg) + .help_mv(format!( + "if this argument is intentionally unused, \ + consider using it in an asm comment: `\"/*{help_str} */\"`" + )) + .emit(); } _ => { let mut err = ecx.dcx().struct_span_err( @@ -747,7 +748,7 @@ pub(super) fn expand_asm<'cx>( }; MacEager::expr(expr) } - Err(mut err) => { + Err(err) => { err.emit(); DummyResult::any(sp) } @@ -779,7 +780,7 @@ pub(super) fn expand_global_asm<'cx>( DummyResult::any(sp) } } - Err(mut err) => { + Err(err) => { err.emit(); DummyResult::any(sp) } diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 8fa3fe5b3e6c..501d557f3ab8 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -22,7 +22,7 @@ pub fn expand_assert<'cx>( ) -> Box { let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) { Ok(assert) => assert, - Err(mut err) => { + Err(err) => { err.emit(); return DummyResult::any(span); } diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 48be680b619f..1bc2512a7b05 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -28,7 +28,7 @@ pub fn expand_cfg( ); MacEager::expr(cx.expr_bool(sp, matches_cfg)) } - Err(mut err) => { + Err(err) => { err.emit(); DummyResult::any(sp) } diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index ca26b7ed8270..cfa94b0e7808 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -200,7 +200,7 @@ impl CfgEval<'_, '_> { parser.capture_cfg = true; match parse_annotatable_with(&mut parser) { Ok(a) => annotatable = a, - Err(mut err) => { + Err(err) => { err.emit(); return Some(annotatable); } diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 2803ddefba21..d956c096d24a 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -18,7 +18,7 @@ pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String]) let start_span = parser.token.span; let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) { Ok(ai) => ai, - Err(mut err) => { + Err(err) => { err.emit(); continue; } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index f9ddffcc155d..13e5a40ca9ee 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -803,24 +803,23 @@ pub(crate) struct AsmClobberNoReg { impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { - let mut diag = DiagnosticBuilder::new( - dcx, - level, - crate::fluent_generated::builtin_macros_asm_clobber_no_reg, - ); - diag.span(self.spans.clone()); // eager translation as `span_labels` takes `AsRef` let lbl1 = dcx.eagerly_translate_to_string( crate::fluent_generated::builtin_macros_asm_clobber_abi, [].into_iter(), ); - diag.span_labels(self.clobbers, &lbl1); let lbl2 = dcx.eagerly_translate_to_string( crate::fluent_generated::builtin_macros_asm_clobber_outputs, [].into_iter(), ); - diag.span_labels(self.spans, &lbl2); - diag + DiagnosticBuilder::new( + dcx, + level, + crate::fluent_generated::builtin_macros_asm_clobber_no_reg, + ) + .span_mv(self.spans.clone()) + .span_labels_mv(self.clobbers, &lbl1) + .span_labels_mv(self.spans, &lbl2) } } diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index a668db438eb2..93381b69fdcc 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -99,7 +99,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< } match p.expect(&token::Comma) { - Err(mut err) => { + Err(err) => { match token::TokenKind::Comma.similar_tokens() { Some(tks) if tks.contains(&p.token.kind) => { // If a similar token is found, then it may be a typo. We @@ -630,8 +630,7 @@ fn report_missing_placeholders( .collect::>(); if !placeholders.is_empty() { - if let Some(mut new_diag) = report_redundant_format_arguments(ecx, args, used, placeholders) - { + if let Some(new_diag) = report_redundant_format_arguments(ecx, args, used, placeholders) { diag.cancel(); new_diag.emit(); return; @@ -976,7 +975,7 @@ fn expand_format_args_impl<'cx>( MacEager::expr(DummyResult::raw_expr(sp, true)) } } - Err(mut err) => { + Err(err) => { err.emit(); DummyResult::any(sp) } diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 4fddaa8ab6cd..9fb6da6e0121 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -194,7 +194,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { self.dcx .struct_span_err(attr.span, msg) - .span_label(prev_attr.span, "previous attribute here") + .span_label_mv(prev_attr.span, "previous attribute here") .emit(); return; diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 30f80bb87dd1..caebb12919fc 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -109,7 +109,7 @@ pub fn expand_include<'cx>( // The file will be added to the code map by the parser let file = match resolve_path(&cx.sess.parse_sess, file.as_str(), sp) { Ok(f) => f, - Err(mut err) => { + Err(err) => { err.emit(); return DummyResult::any(sp); } @@ -146,7 +146,7 @@ pub fn expand_include<'cx>( let mut ret = SmallVec::new(); loop { match self.p.parse_item(ForceCollect::No) { - Err(mut err) => { + Err(err) => { err.emit(); break; } @@ -181,7 +181,7 @@ pub fn expand_include_str( }; let file = match resolve_path(&cx.sess.parse_sess, file.as_str(), sp) { Ok(f) => f, - Err(mut err) => { + Err(err) => { err.emit(); return DummyResult::any(sp); } @@ -215,7 +215,7 @@ pub fn expand_include_bytes( }; let file = match resolve_path(&cx.sess.parse_sess, file.as_str(), sp) { Ok(f) => f, - Err(mut err) => { + Err(err) => { err.emit(); return DummyResult::any(sp); } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 568f8247b280..717f5d9c38a2 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -409,8 +409,8 @@ fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) ), ); } - err.span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions") - .span_suggestion(attr_sp, + err.span_label_mv(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions") + .span_suggestion_mv(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", "#[cfg(test)]", Applicability::MaybeIncorrect) @@ -480,7 +480,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { "argument must be of the form: \ `expected = \"error message\"`", ) - .note( + .note_mv( "errors in this attribute were erroneously \ allowed and will become a hard error in a \ future release", diff --git a/compiler/rustc_builtin_macros/src/type_ascribe.rs b/compiler/rustc_builtin_macros/src/type_ascribe.rs index 72b85af14863..564797012ae2 100644 --- a/compiler/rustc_builtin_macros/src/type_ascribe.rs +++ b/compiler/rustc_builtin_macros/src/type_ascribe.rs @@ -12,7 +12,7 @@ pub fn expand_type_ascribe( ) -> Box { let (expr, ty) = match parse_ascribe(cx, tts) { Ok(parsed) => parsed, - Err(mut err) => { + Err(err) => { err.emit(); return DummyResult::any(span); } diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index a1cdf31c68a0..2a7b1107ffca 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -111,6 +111,9 @@ fn start( } static mut NUM: u8 = 6 * 7; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static NUM_REF: &'static u8 = unsafe { &NUM }; unsafe fn zeroed() -> T { diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 6230ca15d6e1..d1b21d0a0b6c 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -68,15 +68,7 @@ impl DebugContext { // In order to have a good line stepping behavior in debugger, we overwrite debug // locations of macro expansions with that of the outermost expansion site (when the macro is // annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). - let span = if tcx.should_collapse_debuginfo(span) { - span - } else { - // Walk up the macro expansion chain until we reach a non-expanded span. - // We also stop at the function body level because no line stepping can occur - // at the level above that. - rustc_span::hygiene::walk_chain(span, function_span.ctxt()) - }; - + let span = tcx.collapsed_debuginfo(span, function_span); match tcx.sess.source_map().lookup_line(span.lo()) { Ok(SourceFileAndLine { sf: file, line }) => { let line_pos = file.lines()[line]; diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index a8d8fb189e2e..50d9f287e74c 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -321,9 +321,10 @@ fn dep_symbol_lookup_fn( Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { let name = crate_info.crate_name[&cnum]; - let mut err = sess.dcx().struct_err(format!("Can't load static lib {}", name)); - err.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); - err.emit(); + sess.dcx() + .struct_err(format!("Can't load static lib {}", name)) + .note("rustc_codegen_cranelift can only load dylibs in JIT mode.") + .emit(); } Linkage::Dynamic => { dylib_paths.push(src.dylib.as_ref().unwrap().0.clone()); diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index 40a1ad22c0e1..9827e299f2a3 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -98,6 +98,9 @@ fn start( } static mut NUM: u8 = 6 * 7; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static NUM_REF: &'static u8 = unsafe { &NUM }; macro_rules! assert { diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 58b3aa438c51..ca3760297354 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -134,7 +134,8 @@ fn create_wrapper_function( llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } if tcx.sess.must_emit_unwind_tables() { - let uwtable = attributes::uwtable_attr(llcx); + let uwtable = + attributes::uwtable_attr(llcx, tcx.sess.opts.unstable_opts.use_sync_unwind); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index b3fa7b7cd445..0a7ea5994312 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -95,11 +95,12 @@ pub fn sanitize_attrs<'ll>( /// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function. #[inline] -pub fn uwtable_attr(llcx: &llvm::Context) -> &Attribute { +pub fn uwtable_attr(llcx: &llvm::Context, use_sync_unwind: Option) -> &Attribute { // NOTE: We should determine if we even need async unwind tables, as they // take have more overhead and if we can use sync unwind tables we // probably should. - llvm::CreateUWTableAttr(llcx, true) + let async_unwind = !use_sync_unwind.unwrap_or(false); + llvm::CreateUWTableAttr(llcx, async_unwind) } pub fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { @@ -333,7 +334,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( // You can also find more info on why Windows always requires uwtables here: // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 if cx.sess().must_emit_unwind_tables() { - to_add.push(uwtable_attr(cx.llcx)); + to_add.push(uwtable_attr(cx.llcx, cx.sess().opts.unstable_opts.use_sync_unwind)); } if cx.sess().opts.unstable_opts.profile_sample_use.is_some() { diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 422e8edff5f6..6e2c0dc21ad8 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -105,10 +105,8 @@ impl IntoDiagnostic<'_, G> for ParseTargetMachineConfig<'_ let (message, _) = diag.messages().first().expect("`LlvmError` with no message"); let message = dcx.eagerly_translate_to_string(message.clone(), diag.args()); - let mut diag = - DiagnosticBuilder::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config); - diag.arg("error", message); - diag + DiagnosticBuilder::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config) + .arg_mv("error", message) } } @@ -204,10 +202,10 @@ impl IntoDiagnostic<'_, G> for WithLlvmError<'_> { PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err, ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err, }; - let mut diag = self.0.into_diagnostic(dcx, level); - diag.primary_message(msg_with_llvm_err); - diag.arg("llvm_err", self.1); - diag + self.0 + .into_diagnostic(dcx, level) + .primary_message_mv(msg_with_llvm_err) + .arg_mv("llvm_err", self.1) } } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 63fd7b42f7ba..f53067d194ac 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -303,14 +303,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // This exception needs to be kept in sync with allowing // `#[target_feature]` on `main` and `start`. } else if !tcx.features().target_feature_11 { - let mut err = feature_err( + feature_err( &tcx.sess.parse_sess, sym::target_feature_11, attr.span, "`#[target_feature(..)]` can only be applied to `unsafe` functions", - ); - err.span_label(tcx.def_span(did), "not an `unsafe` function"); - err.emit(); + ) + .span_label_mv(tcx.def_span(did), "not an `unsafe` function") + .emit(); } else { check_target_feature_trait_unsafe(tcx, did, attr.span); } @@ -477,7 +477,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { InlineAttr::Never } else { struct_span_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument") - .help("valid inline arguments are `always` and `never`") + .help_mv("valid inline arguments are `always` and `never`") .emit(); InlineAttr::None @@ -662,7 +662,7 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal); tcx.dcx() .struct_span_err(attr.span, msg) - .note("the value may not exceed `u16::MAX`") + .note_mv("the value may not exceed `u16::MAX`") .emit(); None } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index c1086bebb8d4..7e3b69fa52f4 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -212,192 +212,124 @@ pub struct ThorinErrorWrapper(pub thorin::Error); impl IntoDiagnostic<'_, G> for ThorinErrorWrapper { fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let build = |msg| DiagnosticBuilder::new(dcx, level, msg); - let mut diag; match self.0 { - thorin::Error::ReadInput(_) => { - diag = build(fluent::codegen_ssa_thorin_read_input_failure); - diag - } + thorin::Error::ReadInput(_) => build(fluent::codegen_ssa_thorin_read_input_failure), thorin::Error::ParseFileKind(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_input_file_kind); - diag + build(fluent::codegen_ssa_thorin_parse_input_file_kind) } thorin::Error::ParseObjectFile(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_input_object_file); - diag + build(fluent::codegen_ssa_thorin_parse_input_object_file) } thorin::Error::ParseArchiveFile(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_input_archive_file); - diag + build(fluent::codegen_ssa_thorin_parse_input_archive_file) } thorin::Error::ParseArchiveMember(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_archive_member); - diag - } - thorin::Error::InvalidInputKind => { - diag = build(fluent::codegen_ssa_thorin_invalid_input_kind); - diag - } - thorin::Error::DecompressData(_) => { - diag = build(fluent::codegen_ssa_thorin_decompress_data); - diag + build(fluent::codegen_ssa_thorin_parse_archive_member) } + thorin::Error::InvalidInputKind => build(fluent::codegen_ssa_thorin_invalid_input_kind), + thorin::Error::DecompressData(_) => build(fluent::codegen_ssa_thorin_decompress_data), thorin::Error::NamelessSection(_, offset) => { - diag = build(fluent::codegen_ssa_thorin_section_without_name); - diag.arg("offset", format!("0x{offset:08x}")); - diag + build(fluent::codegen_ssa_thorin_section_without_name) + .arg_mv("offset", format!("0x{offset:08x}")) } thorin::Error::RelocationWithInvalidSymbol(section, offset) => { - diag = build(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol); - diag.arg("section", section); - diag.arg("offset", format!("0x{offset:08x}")); - diag + build(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol) + .arg_mv("section", section) + .arg_mv("offset", format!("0x{offset:08x}")) } thorin::Error::MultipleRelocations(section, offset) => { - diag = build(fluent::codegen_ssa_thorin_multiple_relocations); - diag.arg("section", section); - diag.arg("offset", format!("0x{offset:08x}")); - diag + build(fluent::codegen_ssa_thorin_multiple_relocations) + .arg_mv("section", section) + .arg_mv("offset", format!("0x{offset:08x}")) } thorin::Error::UnsupportedRelocation(section, offset) => { - diag = build(fluent::codegen_ssa_thorin_unsupported_relocation); - diag.arg("section", section); - diag.arg("offset", format!("0x{offset:08x}")); - diag - } - thorin::Error::MissingDwoName(id) => { - diag = build(fluent::codegen_ssa_thorin_missing_dwo_name); - diag.arg("id", format!("0x{id:08x}")); - diag + build(fluent::codegen_ssa_thorin_unsupported_relocation) + .arg_mv("section", section) + .arg_mv("offset", format!("0x{offset:08x}")) } + thorin::Error::MissingDwoName(id) => build(fluent::codegen_ssa_thorin_missing_dwo_name) + .arg_mv("id", format!("0x{id:08x}")), thorin::Error::NoCompilationUnits => { - diag = build(fluent::codegen_ssa_thorin_no_compilation_units); - diag - } - thorin::Error::NoDie => { - diag = build(fluent::codegen_ssa_thorin_no_die); - diag + build(fluent::codegen_ssa_thorin_no_compilation_units) } + thorin::Error::NoDie => build(fluent::codegen_ssa_thorin_no_die), thorin::Error::TopLevelDieNotUnit => { - diag = build(fluent::codegen_ssa_thorin_top_level_die_not_unit); - diag + build(fluent::codegen_ssa_thorin_top_level_die_not_unit) } thorin::Error::MissingRequiredSection(section) => { - diag = build(fluent::codegen_ssa_thorin_missing_required_section); - diag.arg("section", section); - diag + build(fluent::codegen_ssa_thorin_missing_required_section) + .arg_mv("section", section) } thorin::Error::ParseUnitAbbreviations(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_unit_abbreviations); - diag + build(fluent::codegen_ssa_thorin_parse_unit_abbreviations) } thorin::Error::ParseUnitAttribute(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_unit_attribute); - diag + build(fluent::codegen_ssa_thorin_parse_unit_attribute) } thorin::Error::ParseUnitHeader(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_unit_header); - diag - } - thorin::Error::ParseUnit(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_unit); - diag + build(fluent::codegen_ssa_thorin_parse_unit_header) } + thorin::Error::ParseUnit(_) => build(fluent::codegen_ssa_thorin_parse_unit), thorin::Error::IncompatibleIndexVersion(section, format, actual) => { - diag = build(fluent::codegen_ssa_thorin_incompatible_index_version); - diag.arg("section", section); - diag.arg("actual", actual); - diag.arg("format", format); - diag + build(fluent::codegen_ssa_thorin_incompatible_index_version) + .arg_mv("section", section) + .arg_mv("actual", actual) + .arg_mv("format", format) } thorin::Error::OffsetAtIndex(_, index) => { - diag = build(fluent::codegen_ssa_thorin_offset_at_index); - diag.arg("index", index); - diag + build(fluent::codegen_ssa_thorin_offset_at_index).arg_mv("index", index) } thorin::Error::StrAtOffset(_, offset) => { - diag = build(fluent::codegen_ssa_thorin_str_at_offset); - diag.arg("offset", format!("0x{offset:08x}")); - diag + build(fluent::codegen_ssa_thorin_str_at_offset) + .arg_mv("offset", format!("0x{offset:08x}")) } thorin::Error::ParseIndex(_, section) => { - diag = build(fluent::codegen_ssa_thorin_parse_index); - diag.arg("section", section); - diag + build(fluent::codegen_ssa_thorin_parse_index).arg_mv("section", section) } thorin::Error::UnitNotInIndex(unit) => { - diag = build(fluent::codegen_ssa_thorin_unit_not_in_index); - diag.arg("unit", format!("0x{unit:08x}")); - diag + build(fluent::codegen_ssa_thorin_unit_not_in_index) + .arg_mv("unit", format!("0x{unit:08x}")) } thorin::Error::RowNotInIndex(_, row) => { - diag = build(fluent::codegen_ssa_thorin_row_not_in_index); - diag.arg("row", row); - diag - } - thorin::Error::SectionNotInRow => { - diag = build(fluent::codegen_ssa_thorin_section_not_in_row); - diag + build(fluent::codegen_ssa_thorin_row_not_in_index).arg_mv("row", row) } + thorin::Error::SectionNotInRow => build(fluent::codegen_ssa_thorin_section_not_in_row), thorin::Error::EmptyUnit(unit) => { - diag = build(fluent::codegen_ssa_thorin_empty_unit); - diag.arg("unit", format!("0x{unit:08x}")); - diag + build(fluent::codegen_ssa_thorin_empty_unit).arg_mv("unit", format!("0x{unit:08x}")) } thorin::Error::MultipleDebugInfoSection => { - diag = build(fluent::codegen_ssa_thorin_multiple_debug_info_section); - diag + build(fluent::codegen_ssa_thorin_multiple_debug_info_section) } thorin::Error::MultipleDebugTypesSection => { - diag = build(fluent::codegen_ssa_thorin_multiple_debug_types_section); - diag - } - thorin::Error::NotSplitUnit => { - diag = build(fluent::codegen_ssa_thorin_not_split_unit); - diag - } - thorin::Error::DuplicateUnit(unit) => { - diag = build(fluent::codegen_ssa_thorin_duplicate_unit); - diag.arg("unit", format!("0x{unit:08x}")); - diag + build(fluent::codegen_ssa_thorin_multiple_debug_types_section) } + thorin::Error::NotSplitUnit => build(fluent::codegen_ssa_thorin_not_split_unit), + thorin::Error::DuplicateUnit(unit) => build(fluent::codegen_ssa_thorin_duplicate_unit) + .arg_mv("unit", format!("0x{unit:08x}")), thorin::Error::MissingReferencedUnit(unit) => { - diag = build(fluent::codegen_ssa_thorin_missing_referenced_unit); - diag.arg("unit", format!("0x{unit:08x}")); - diag + build(fluent::codegen_ssa_thorin_missing_referenced_unit) + .arg_mv("unit", format!("0x{unit:08x}")) } thorin::Error::NoOutputObjectCreated => { - diag = build(fluent::codegen_ssa_thorin_not_output_object_created); - diag + build(fluent::codegen_ssa_thorin_not_output_object_created) } thorin::Error::MixedInputEncodings => { - diag = build(fluent::codegen_ssa_thorin_mixed_input_encodings); - diag + build(fluent::codegen_ssa_thorin_mixed_input_encodings) } thorin::Error::Io(e) => { - diag = build(fluent::codegen_ssa_thorin_io); - diag.arg("error", format!("{e}")); - diag + build(fluent::codegen_ssa_thorin_io).arg_mv("error", format!("{e}")) } thorin::Error::ObjectRead(e) => { - diag = build(fluent::codegen_ssa_thorin_object_read); - diag.arg("error", format!("{e}")); - diag + build(fluent::codegen_ssa_thorin_object_read).arg_mv("error", format!("{e}")) } thorin::Error::ObjectWrite(e) => { - diag = build(fluent::codegen_ssa_thorin_object_write); - diag.arg("error", format!("{e}")); - diag + build(fluent::codegen_ssa_thorin_object_write).arg_mv("error", format!("{e}")) } thorin::Error::GimliRead(e) => { - diag = build(fluent::codegen_ssa_thorin_gimli_read); - diag.arg("error", format!("{e}")); - diag + build(fluent::codegen_ssa_thorin_gimli_read).arg_mv("error", format!("{e}")) } thorin::Error::GimliWrite(e) => { - diag = build(fluent::codegen_ssa_thorin_gimli_write); - diag.arg("error", format!("{e}")); - diag + build(fluent::codegen_ssa_thorin_gimli_write).arg_mv("error", format!("{e}")) } _ => unimplemented!("Untranslated thorin error"), } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 14915e816ee9..48f3f4f25228 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -228,21 +228,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// In order to have a good line stepping behavior in debugger, we overwrite debug /// locations of macro expansions with that of the outermost expansion site (when the macro is /// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). - fn adjust_span_for_debugging(&self, mut span: Span) -> Span { + fn adjust_span_for_debugging(&self, span: Span) -> Span { // Bail out if debug info emission is not enabled. if self.debug_context.is_none() { return span; } - - if self.cx.tcx().should_collapse_debuginfo(span) { - // Walk up the macro expansion chain until we reach a non-expanded span. - // We also stop at the function body level because no line stepping can occur - // at the level above that. - // Use span of the outermost expansion site, while keeping the original lexical scope. - span = rustc_span::hygiene::walk_chain(span, self.mir.span.ctxt()); - } - - span + // Walk up the macro expansion chain until we reach a non-expanded span. + // We also stop at the function body level because no line stepping can occur + // at the level above that. + // Use span of the outermost expansion site, while keeping the original lexical scope. + self.cx.tcx().collapsed_debuginfo(span, self.mir.span) } fn spill_operand_to_stack( diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index b6bb1607a09c..c0ce8a54af57 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -27,7 +27,7 @@ pub fn from_target_feature( let code = "enable = \"..\""; tcx.dcx() .struct_span_err(span, msg) - .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders) + .span_suggestion_mv(span, "must be of the form", code, Applicability::HasPlaceholders) .emit(); }; let rust_features = tcx.features(); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 92955c4ed14c..738c532964a2 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -338,7 +338,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { return; } - let mut err = op.build_error(self.ccx, span); + let err = op.build_error(self.ccx, span); assert!(err.is_error()); match op.importance() { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 7e1cbfe66674..1efa52df5817 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -157,9 +157,7 @@ impl Qualif for NeedsNonConstDrop { // FIXME(effects): If `destruct` is not a `const_trait`, // or effects are disabled in this crate, then give up. let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span)); - if cx.tcx.generics_of(destruct_def_id).host_effect_index.is_none() - || !cx.tcx.features().effects - { + if !cx.tcx.has_host_param(destruct_def_id) || !cx.tcx.features().effects { return NeedsDrop::in_any_value_of_ty(cx, ty); } diff --git a/compiler/rustc_const_eval/src/transform/mod.rs b/compiler/rustc_const_eval/src/transform/mod.rs index a2928bdf51b8..e3582c7d3174 100644 --- a/compiler/rustc_const_eval/src/transform/mod.rs +++ b/compiler/rustc_const_eval/src/transform/mod.rs @@ -1,3 +1,2 @@ pub mod check_consts; -pub mod promote_consts; pub mod validate; diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index 9fce0e1e65cc..80e72250470c 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -7,6 +7,7 @@ pub type StdEntry<'a, K, V> = std::collections::hash_map::Entry<'a, K, V>; pub type FxIndexMap = indexmap::IndexMap>; pub type FxIndexSet = indexmap::IndexSet>; pub type IndexEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>; +pub type IndexOccupiedEntry<'a, K, V> = indexmap::map::OccupiedEntry<'a, K, V>; #[macro_export] macro_rules! define_id_collections { diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index 4b819e1cbd61..a45f1dd72a12 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -394,6 +394,7 @@ impl Dominators { /// # Panics /// /// Panics if `b` is unreachable. + #[inline] pub fn dominates(&self, a: Node, b: Node) -> bool { match &self.kind { Kind::Path => a.index() <= b.index(), diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index ed2e558bffa6..1436628139fd 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -16,7 +16,7 @@ pub use index_map::SortedIndexMultiMap; /// stores data in a more compact way. It also supports accessing contiguous /// ranges of elements as a slice, and slices of already sorted elements can be /// inserted efficiently. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable_Generic, Decodable_Generic)] pub struct SortedMap { data: Vec<(K, V)>, } diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs index 71679086f16c..1cfc9fecd47d 100644 --- a/compiler/rustc_data_structures/src/svh.rs +++ b/compiler/rustc_data_structures/src/svh.rs @@ -10,7 +10,7 @@ use std::fmt; use crate::stable_hasher; -#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable_Generic, Decodable_Generic, Hash)] pub struct Svh { hash: Fingerprint, } diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 43221d70e21c..48edfba8da08 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -56,9 +56,6 @@ mod parallel; pub use parallel::scope; pub use parallel::{join, par_for_each_in, par_map, parallel_guard, try_par_for_each_in}; -pub use std::sync::atomic::Ordering; -pub use std::sync::atomic::Ordering::SeqCst; - pub use vec::{AppendOnlyIndexVec, AppendOnlyVec}; mod vec; @@ -67,8 +64,7 @@ mod freeze; pub use freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard}; mod mode { - use super::Ordering; - use std::sync::atomic::AtomicU8; + use std::sync::atomic::{AtomicU8, Ordering}; const UNINITIALIZED: u8 = 0; const DYN_NOT_THREAD_SAFE: u8 = 1; @@ -113,6 +109,7 @@ cfg_match! { cfg(not(parallel_compiler)) => { use std::ops::Add; use std::cell::Cell; + use std::sync::atomic::Ordering; pub unsafe auto trait Send {} pub unsafe auto trait Sync {} diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index bd4dff6f62ff..907c866b3edd 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -226,7 +226,7 @@ trait UnordCollection {} /// /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533) /// for more information. -#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)] +#[derive(Debug, Eq, PartialEq, Clone, Encodable_Generic, Decodable_Generic)] pub struct UnordSet { inner: FxHashSet, } @@ -417,7 +417,7 @@ impl> HashStable for UnordSet { /// /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533) /// for more information. -#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)] +#[derive(Debug, Eq, PartialEq, Clone, Encodable_Generic, Decodable_Generic)] pub struct UnordMap { inner: FxHashMap, } @@ -626,7 +626,7 @@ impl, V: HashStable> HashStable fo /// /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533) /// for more information. -#[derive(Default, Debug, Eq, PartialEq, Clone, Encodable, Decodable)] +#[derive(Default, Debug, Eq, PartialEq, Clone, Encodable_Generic, Decodable_Generic)] pub struct UnordBag { inner: Vec, } diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 490429845538..97a7dfef3b39 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -50,6 +50,7 @@ rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } serde_json = "1.0.59" +shlex = "1.0" time = { version = "0.3", default-features = false, features = ["alloc", "formatting"] } tracing = { version = "0.1.35" } # tidy-alphabetical-end diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs index b7407f5a508e..5dfd37a6da4d 100644 --- a/compiler/rustc_driver_impl/src/args.rs +++ b/compiler/rustc_driver_impl/src/args.rs @@ -5,18 +5,92 @@ use std::io; use rustc_session::EarlyDiagCtxt; -fn arg_expand(arg: String) -> Result, Error> { - if let Some(path) = arg.strip_prefix('@') { - let file = match fs::read_to_string(path) { - Ok(file) => file, - Err(ref err) if err.kind() == io::ErrorKind::InvalidData => { - return Err(Error::Utf8Error(Some(path.to_string()))); +/// Expands argfiles in command line arguments. +#[derive(Default)] +struct Expander { + shell_argfiles: bool, + next_is_unstable_option: bool, + expanded: Vec, +} + +impl Expander { + /// Handles the next argument. If the argument is an argfile, it is expanded + /// inline. + fn arg(&mut self, arg: &str) -> Result<(), Error> { + if let Some(argfile) = arg.strip_prefix('@') { + match argfile.split_once(':') { + Some(("shell", path)) if self.shell_argfiles => { + shlex::split(&Self::read_file(path)?) + .ok_or_else(|| Error::ShellParseError(path.to_string()))? + .into_iter() + .for_each(|arg| self.push(arg)); + } + _ => { + let contents = Self::read_file(argfile)?; + contents.lines().for_each(|arg| self.push(arg.to_string())); + } } - Err(err) => return Err(Error::IOError(path.to_string(), err)), - }; - Ok(file.lines().map(ToString::to_string).collect()) - } else { - Ok(vec![arg]) + } else { + self.push(arg.to_string()); + } + + Ok(()) + } + + /// Adds a command line argument verbatim with no argfile expansion. + fn push(&mut self, arg: String) { + // Unfortunately, we have to do some eager argparsing to handle unstable + // options which change the behavior of argfile arguments. + // + // Normally, all of the argfile arguments (e.g. `@args.txt`) are + // expanded into our arguments list *and then* the whole list of + // arguments are passed on to be parsed. However, argfile parsing + // options like `-Zshell_argfiles` need to change the behavior of that + // argument expansion. So we have to do a little parsing on our own here + // instead of leaning on the existing logic. + // + // All we care about are unstable options, so we parse those out and + // look for any that affect how we expand argfiles. This argument + // inspection is very conservative; we only change behavior when we see + // exactly the options we're looking for and everything gets passed + // through. + + if self.next_is_unstable_option { + self.inspect_unstable_option(&arg); + self.next_is_unstable_option = false; + } else if let Some(unstable_option) = arg.strip_prefix("-Z") { + if unstable_option.is_empty() { + self.next_is_unstable_option = true; + } else { + self.inspect_unstable_option(unstable_option); + } + } + + self.expanded.push(arg); + } + + /// Consumes the `Expander`, returning the expanded arguments. + fn finish(self) -> Vec { + self.expanded + } + + /// Parses any relevant unstable flags specified on the command line. + fn inspect_unstable_option(&mut self, option: &str) { + match option { + "shell-argfiles" => self.shell_argfiles = true, + _ => (), + } + } + + /// Reads the contents of a file as UTF-8. + fn read_file(path: &str) -> Result { + fs::read_to_string(path).map_err(|e| { + if e.kind() == io::ErrorKind::InvalidData { + Error::Utf8Error(Some(path.to_string())) + } else { + Error::IOError(path.to_string(), e) + } + }) } } @@ -24,20 +98,20 @@ fn arg_expand(arg: String) -> Result, Error> { /// If this function is intended to be used with command line arguments, /// `argv[0]` must be removed prior to calling it manually. pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec { - let mut args = Vec::new(); + let mut expander = Expander::default(); for arg in at_args { - match arg_expand(arg.clone()) { - Ok(arg) => args.extend(arg), - Err(err) => early_dcx.early_fatal(format!("Failed to load argument file: {err}")), + if let Err(err) = expander.arg(arg) { + early_dcx.early_fatal(format!("Failed to load argument file: {err}")); } } - args + expander.finish() } #[derive(Debug)] pub enum Error { Utf8Error(Option), IOError(String, io::Error), + ShellParseError(String), } impl fmt::Display for Error { @@ -46,6 +120,7 @@ impl fmt::Display for Error { Error::Utf8Error(None) => write!(fmt, "Utf8 error"), Error::Utf8Error(Some(path)) => write!(fmt, "Utf8 error in {path}"), Error::IOError(path, err) => write!(fmt, "IO Error: {path}: {err}"), + Error::ShellParseError(path) => write!(fmt, "Invalid shell-style arguments in {path}"), } } } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index fd925b62702a..3047f5d47e4d 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -25,7 +25,6 @@ use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults}; use rustc_data_structures::profiling::{ get_resident_set_size, print_time_passes_entry, TimePassesFormat, }; -use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{markdown, ColorConfig}; use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult}; @@ -476,7 +475,7 @@ fn run_compiler( eprintln!( "Fuel used by {}: {}", sess.opts.unstable_opts.print_fuel.as_ref().unwrap(), - sess.print_fuel.load(SeqCst) + sess.print_fuel.load(Ordering::SeqCst) ); } @@ -716,7 +715,7 @@ fn print_crate_info( let result = parse_crate_attrs(sess); match result { Ok(attrs) => Some(attrs), - Err(mut parse_error) => { + Err(parse_error) => { parse_error.emit(); return Compilation::Stop; } diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 1028d43f9c5b..9cd9ed54d414 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -515,6 +515,8 @@ E0792: include_str!("./error_codes/E0792.md"), E0793: include_str!("./error_codes/E0793.md"), E0794: include_str!("./error_codes/E0794.md"), E0795: include_str!("./error_codes/E0795.md"), +E0796: include_str!("./error_codes/E0796.md"), +E0797: include_str!("./error_codes/E0797.md"), } // Undocumented removed error codes. Note that many removed error codes are kept in the list above diff --git a/compiler/rustc_error_codes/src/error_codes/E0733.md b/compiler/rustc_error_codes/src/error_codes/E0733.md index 051b75148e50..42c01975dd8d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0733.md +++ b/compiler/rustc_error_codes/src/error_codes/E0733.md @@ -10,35 +10,31 @@ async fn foo(n: usize) { } ``` -To perform async recursion, the `async fn` needs to be desugared such that the -`Future` is explicit in the return type: - -```edition2018,compile_fail,E0720 -use std::future::Future; -fn foo_desugared(n: usize) -> impl Future { - async move { - if n > 0 { - foo_desugared(n - 1).await; - } - } -} -``` - -Finally, the future is wrapped in a pinned box: +The recursive invocation can be boxed: ```edition2018 -use std::future::Future; -use std::pin::Pin; -fn foo_recursive(n: usize) -> Pin>> { - Box::pin(async move { - if n > 0 { - foo_recursive(n - 1).await; - } - }) +async fn foo(n: usize) { + if n > 0 { + Box::pin(foo(n - 1)).await; + } } ``` The `Box<...>` ensures that the result is of known size, and the pin is required to keep it in the same place in memory. +Alternatively, the body can be boxed: + +```edition2018 +use std::future::Future; +use std::pin::Pin; +fn foo(n: usize) -> Pin>> { + Box::pin(async move { + if n > 0 { + foo(n - 1).await; + } + }) +} +``` + [`async`]: https://doc.rust-lang.org/std/keyword.async.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0796.md b/compiler/rustc_error_codes/src/error_codes/E0796.md new file mode 100644 index 000000000000..cea18f8db851 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0796.md @@ -0,0 +1,22 @@ +Reference of mutable static. + +Erroneous code example: + +```compile_fail,edition2024,E0796 +static mut X: i32 = 23; +static mut Y: i32 = 24; + +unsafe { + let y = &X; + let ref x = X; + let (x, y) = (&X, &Y); + foo(&X); +} + +fn foo<'a>(_x: &'a i32) {} +``` + +Mutable statics can be written to by multiple threads: aliasing violations or +data races will cause undefined behavior. + +Reference of mutable static is a hard error from 2024 edition. diff --git a/compiler/rustc_error_codes/src/error_codes/E0797.md b/compiler/rustc_error_codes/src/error_codes/E0797.md new file mode 100644 index 000000000000..8a912307264e --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0797.md @@ -0,0 +1,26 @@ +Struct update syntax was used without a base expression. + +Erroneous code example: + +```compile_fail,E0797 +struct Foo { + fizz: u8, + buzz: u8 +} + +let f1 = Foo { fizz: 10, buzz: 1}; +let f2 = Foo { fizz: 10, .. }; // error +``` + +Using struct update syntax requires a 'base expression'. +This will be used to fill remaining fields. + +``` +struct Foo { + fizz: u8, + buzz: u8 +} + +let f1 = Foo { fizz: 10, buzz: 1}; +let f2 = Foo { fizz: 10, ..f1 }; +``` diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index e018c14a4a5c..3789cdaf354a 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -30,57 +30,44 @@ where G: EmissionGuarantee, { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { - let mut diag = self.node.into_diagnostic(dcx, level); - diag.span(self.span); - diag + self.node.into_diagnostic(dcx, level).span_mv(self.span) } } /// Used for emitting structured error messages and other diagnostic information. +/// Each constructed `DiagnosticBuilder` must be consumed by a function such as +/// `emit`, `cancel`, `delay_as_bug`, or `into_diagnostic`. A panic occurrs if a +/// `DiagnosticBuilder` is dropped without being consumed by one of these +/// functions. /// /// If there is some state in a downstream crate you would like to /// access in the methods of `DiagnosticBuilder` here, consider /// extending `DiagCtxtFlags`. #[must_use] -#[derive(Clone)] pub struct DiagnosticBuilder<'a, G: EmissionGuarantee = ErrorGuaranteed> { - state: DiagnosticBuilderState<'a>, + pub dcx: &'a DiagCtxt, - /// `Diagnostic` is a large type, and `DiagnosticBuilder` is often used as a - /// return value, especially within the frequently-used `PResult` type. - /// In theory, return value optimization (RVO) should avoid unnecessary - /// copying. In practice, it does not (at the time of writing). - diagnostic: Box, + /// Why the `Option`? It is always `Some` until the `DiagnosticBuilder` is + /// consumed via `emit`, `cancel`, etc. At that point it is consumed and + /// replaced with `None`. Then `drop` checks that it is `None`; if not, it + /// panics because a diagnostic was built but not used. + /// + /// Why the Box? `Diagnostic` is a large type, and `DiagnosticBuilder` is + /// often used as a return value, especially within the frequently-used + /// `PResult` type. In theory, return value optimization (RVO) should avoid + /// unnecessary copying. In practice, it does not (at the time of writing). + diag: Option>, _marker: PhantomData, } -#[derive(Clone)] -enum DiagnosticBuilderState<'a> { - /// Initial state of a `DiagnosticBuilder`, before `.emit()` or `.cancel()`. - /// - /// The `Diagnostic` will be emitted through this `DiagCtxt`. - Emittable(&'a DiagCtxt), +// Cloning a `DiagnosticBuilder` is a recipe for a diagnostic being emitted +// twice, which would be bad. +impl !Clone for DiagnosticBuilder<'_, G> {} - /// State of a `DiagnosticBuilder`, after `.emit()` or *during* `.cancel()`. - /// - /// The `Diagnostic` will be ignored when calling `.emit()`, and it can be - /// assumed that `.emit()` was previously called, to end up in this state. - /// - /// While this is also used by `.cancel()`, this state is only observed by - /// the `Drop` `impl` of `DiagnosticBuilder`, because `.cancel()` takes - /// `self` by-value specifically to prevent any attempts to `.emit()`. - /// - // FIXME(eddyb) currently this doesn't prevent extending the `Diagnostic`, - // despite that being potentially lossy, if important information is added - // *after* the original `.emit()` call. - AlreadyEmittedOrDuringCancellation, -} - -// `DiagnosticBuilderState` should be pointer-sized. rustc_data_structures::static_assert_size!( - DiagnosticBuilderState<'_>, - std::mem::size_of::<&DiagCtxt>() + DiagnosticBuilder<'_, ()>, + 2 * std::mem::size_of::() ); /// Trait for types that `DiagnosticBuilder::emit` can return as a "guarantee" @@ -94,68 +81,50 @@ pub trait EmissionGuarantee: Sized { /// `impl` of `EmissionGuarantee`, to make it impossible to create a value /// of `Self::EmitResult` without actually performing the emission. #[track_caller] - fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult; + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult; } impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { + /// Takes the diagnostic. For use by methods that consume the + /// DiagnosticBuilder: `emit`, `cancel`, etc. Afterwards, `drop` is the + /// only code that will be run on `self`. + fn take_diag(&mut self) -> Diagnostic { + Box::into_inner(self.diag.take().unwrap()) + } + /// Most `emit_producing_guarantee` functions use this as a starting point. - fn emit_producing_nothing(&mut self) { - match self.state { - // First `.emit()` call, the `&DiagCtxt` is still available. - DiagnosticBuilderState::Emittable(dcx) => { - self.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; - dcx.emit_diagnostic_without_consuming(&mut self.diagnostic); - } - // `.emit()` was previously called, disallowed from repeating it. - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} - } + fn emit_producing_nothing(mut self) { + let diag = self.take_diag(); + self.dcx.emit_diagnostic(diag); + } + + /// `ErrorGuaranteed::emit_producing_guarantee` uses this. + // FIXME(eddyb) make `ErrorGuaranteed` impossible to create outside `.emit()`. + fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed { + let diag = self.take_diag(); + + // Only allow a guarantee if the `level` wasn't switched to a + // non-error. The field isn't `pub`, but the whole `Diagnostic` can be + // overwritten with a new one, thanks to `DerefMut`. + assert!( + diag.is_error(), + "emitted non-error ({:?}) diagnostic from `DiagnosticBuilder`", + diag.level, + ); + + let guar = self.dcx.emit_diagnostic(diag); + guar.unwrap() } } -// FIXME(eddyb) make `ErrorGuaranteed` impossible to create outside `.emit()`. impl EmissionGuarantee for ErrorGuaranteed { - fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { - // Contrast this with `emit_producing_nothing`. - match db.state { - // First `.emit()` call, the `&DiagCtxt` is still available. - DiagnosticBuilderState::Emittable(dcx) => { - db.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; - let guar = dcx.emit_diagnostic_without_consuming(&mut db.diagnostic); - - // Only allow a guarantee if the `level` wasn't switched to a - // non-error - the field isn't `pub`, but the whole `Diagnostic` - // can be overwritten with a new one, thanks to `DerefMut`. - assert!( - db.diagnostic.is_error(), - "emitted non-error ({:?}) diagnostic \ - from `DiagnosticBuilder`", - db.diagnostic.level, - ); - guar.unwrap() - } - // `.emit()` was previously called, disallowed from repeating it, - // but can take advantage of the previous `.emit()`'s guarantee - // still being applicable (i.e. as a form of idempotency). - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => { - // Only allow a guarantee if the `level` wasn't switched to a - // non-error - the field isn't `pub`, but the whole `Diagnostic` - // can be overwritten with a new one, thanks to `DerefMut`. - assert!( - db.diagnostic.is_error(), - "`DiagnosticBuilder`'s diagnostic \ - became non-error ({:?}), after original `.emit()`", - db.diagnostic.level, - ); - #[allow(deprecated)] - ErrorGuaranteed::unchecked_claim_error_was_emitted() - } - } + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + db.emit_producing_error_guaranteed() } } -// FIXME(eddyb) should there be a `Option` impl as well? impl EmissionGuarantee for () { - fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { db.emit_producing_nothing(); } } @@ -168,7 +137,7 @@ pub struct BugAbort; impl EmissionGuarantee for BugAbort { type EmitResult = !; - fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { db.emit_producing_nothing(); panic::panic_any(ExplicitBug); } @@ -182,37 +151,48 @@ pub struct FatalAbort; impl EmissionGuarantee for FatalAbort { type EmitResult = !; - fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { db.emit_producing_nothing(); crate::FatalError.raise() } } impl EmissionGuarantee for rustc_span::fatal_error::FatalError { - fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { db.emit_producing_nothing(); rustc_span::fatal_error::FatalError } } -/// In general, the `DiagnosticBuilder` uses deref to allow access to -/// the fields and methods of the embedded `diagnostic` in a -/// transparent way. *However,* many of the methods are intended to -/// be used in a chained way, and hence ought to return `self`. In -/// that case, we can't just naively forward to the method on the -/// `diagnostic`, because the return type would be a `&Diagnostic` -/// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes -/// it easy to declare such methods on the builder. +/// `DiagnosticBuilder` impls `DerefMut`, which allows access to the fields and +/// methods of the embedded `Diagnostic`. However, that doesn't allow method +/// chaining at the `DiagnosticBuilder` level. Each use of this macro defines +/// two builder methods at that level, both of which wrap the equivalent method +/// in `Diagnostic`. +/// - A `&mut self -> &mut Self` method, with the same name as the underlying +/// `Diagnostic` method. It is mostly to modify existing diagnostics, either +/// in a standalone fashion, e.g. `err.code(code)`, or in a chained fashion +/// to make multiple modifications, e.g. `err.code(code).span(span)`. +/// - A `self -> Self` method, with `_mv` suffix added (short for "move"). +/// It is mostly used in a chained fashion when producing a new diagnostic, +/// e.g. `let err = struct_err(msg).code_mv(code)`, or when emitting a new +/// diagnostic , e.g. `struct_err(msg).code_mv(code).emit()`. +/// +/// Although the latter method can be used to modify an existing diagnostic, +/// e.g. `err = err.code_mv(code)`, this should be avoided because the former +/// method give shorter code, e.g. `err.code(code)`. macro_rules! forward { - // Forward pattern for &mut self -> &mut Self ( - $(#[$attrs:meta])* - pub fn $n:ident(&mut self $(, $name:ident: $ty:ty)* $(,)?) -> &mut Self + ($n:ident, $n_mv:ident)($($name:ident: $ty:ty),* $(,)?) ) => { - $(#[$attrs])* #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")] - pub fn $n(&mut self $(, $name: $ty)*) -> &mut Self { - self.diagnostic.$n($($name),*); + pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { + self.diag.as_mut().unwrap().$n($($name),*); + self + } + #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")] + pub fn $n_mv(mut self, $($name: $ty),*) -> Self { + self.diag.as_mut().unwrap().$n($($name),*); self } }; @@ -222,13 +202,13 @@ impl Deref for DiagnosticBuilder<'_, G> { type Target = Diagnostic; fn deref(&self) -> &Diagnostic { - &self.diagnostic + self.diag.as_ref().unwrap() } } impl DerefMut for DiagnosticBuilder<'_, G> { fn deref_mut(&mut self) -> &mut Diagnostic { - &mut self.diagnostic + self.diag.as_mut().unwrap() } } @@ -242,20 +222,14 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// Creates a new `DiagnosticBuilder` with an already constructed /// diagnostic. #[track_caller] - pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diagnostic: Diagnostic) -> Self { + pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diag: Diagnostic) -> Self { debug!("Created new diagnostic"); - Self { - state: DiagnosticBuilderState::Emittable(dcx), - diagnostic: Box::new(diagnostic), - _marker: PhantomData, - } + Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData } } - /// Emit the diagnostic. Does not consume `self`, which may be surprising, - /// but there are various places that rely on continuing to use `self` - /// after calling `emit`. + /// Emit and consume the diagnostic. #[track_caller] - pub fn emit(&mut self) -> G::EmitResult { + pub fn emit(self) -> G::EmitResult { G::emit_producing_guarantee(self) } @@ -264,21 +238,17 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// /// See `emit` and `delay_as_bug` for details. #[track_caller] - pub fn emit_unless(&mut self, delay: bool) -> G::EmitResult { + pub fn emit_unless(mut self, delay: bool) -> G::EmitResult { if delay { self.downgrade_to_delayed_bug(); } self.emit() } - /// Cancel the diagnostic (a structured diagnostic must either be emitted or + /// Cancel and consume the diagnostic. (A diagnostic must either be emitted or /// cancelled or it will panic when dropped). - /// - /// This method takes `self` by-value to disallow calling `.emit()` on it, - /// which may be expected to *guarantee* the emission of an error, either - /// at the time of the call, or through a prior `.emit()` call. pub fn cancel(mut self) { - self.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + self.diag = None; drop(self); } @@ -294,44 +264,20 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { } /// Converts the builder to a `Diagnostic` for later emission, - /// unless dcx has disabled such buffering, or `.emit()` was called. + /// unless dcx has disabled such buffering. pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a DiagCtxt)> { - let dcx = match self.state { - // No `.emit()` calls, the `&DiagCtxt` is still available. - DiagnosticBuilderState::Emittable(dcx) => dcx, - // `.emit()` was previously called, nothing we can do. - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => { - return None; - } - }; - - if dcx.inner.lock().flags.dont_buffer_diagnostics - || dcx.inner.lock().flags.treat_err_as_bug.is_some() - { + if self.dcx.inner.lock().flags.treat_err_as_bug.is_some() { self.emit(); return None; } - // Take the `Diagnostic` by replacing it with a dummy. - let dummy = Diagnostic::new(Level::Allow, DiagnosticMessage::from("")); - let diagnostic = std::mem::replace(&mut *self.diagnostic, dummy); - - // Disable the ICE on `Drop`. - self.cancel(); + let diag = self.take_diag(); // Logging here is useful to help track down where in logs an error was // actually emitted. - debug!("buffer: diagnostic={:?}", diagnostic); + debug!("buffer: diag={:?}", diag); - Some((diagnostic, dcx)) - } - - /// Retrieves the [`DiagCtxt`] if available - pub fn dcx(&self) -> Option<&DiagCtxt> { - match self.state { - DiagnosticBuilderState::Emittable(dcx) => Some(dcx), - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => None, - } + Some((diag, self.dcx)) } /// Buffers the diagnostic for later emission, @@ -351,170 +297,157 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// In the meantime, though, callsites are required to deal with the "bug" /// locally in whichever way makes the most sense. #[track_caller] - pub fn delay_as_bug(&mut self) -> G::EmitResult { + pub fn delay_as_bug(mut self) -> G::EmitResult { self.downgrade_to_delayed_bug(); self.emit() } - forward!(pub fn span_label( - &mut self, + forward!((span_label, span_label_mv)( span: Span, - label: impl Into - ) -> &mut Self); - forward!(pub fn span_labels( - &mut self, + label: impl Into, + )); + forward!((span_labels, span_labels_mv)( spans: impl IntoIterator, label: &str, - ) -> &mut Self); - forward!(pub fn note_expected_found( - &mut self, + )); + forward!((note_expected_found, note_expected_found_mv)( expected_label: &dyn fmt::Display, expected: DiagnosticStyledString, found_label: &dyn fmt::Display, found: DiagnosticStyledString, - ) -> &mut Self); - forward!(pub fn note_expected_found_extra( - &mut self, + )); + forward!((note_expected_found_extra, note_expected_found_extra_mv)( expected_label: &dyn fmt::Display, expected: DiagnosticStyledString, found_label: &dyn fmt::Display, found: DiagnosticStyledString, expected_extra: &dyn fmt::Display, found_extra: &dyn fmt::Display, - ) -> &mut Self); - forward!(pub fn note(&mut self, msg: impl Into) -> &mut Self); - forward!(pub fn note_once(&mut self, msg: impl Into) -> &mut Self); - forward!(pub fn span_note( - &mut self, + )); + forward!((note, note_mv)( + msg: impl Into, + )); + forward!((note_once, note_once_mv)( + msg: impl Into, + )); + forward!((span_note, span_note_mv)( sp: impl Into, msg: impl Into, - ) -> &mut Self); - forward!(pub fn span_note_once( - &mut self, + )); + forward!((span_note_once, span_note_once_mv)( sp: impl Into, msg: impl Into, - ) -> &mut Self); - forward!(pub fn warn(&mut self, msg: impl Into) -> &mut Self); - forward!(pub fn span_warn( - &mut self, + )); + forward!((warn, warn_mv)( + msg: impl Into, + )); + forward!((span_warn, span_warn_mv)( sp: impl Into, msg: impl Into, - ) -> &mut Self); - forward!(pub fn help(&mut self, msg: impl Into) -> &mut Self); - forward!(pub fn help_once(&mut self, msg: impl Into) -> &mut Self); - forward!(pub fn span_help( - &mut self, + )); + forward!((help, help_mv)( + msg: impl Into, + )); + forward!((help_once, help_once_mv)( + msg: impl Into, + )); + forward!((span_help, span_help_once_mv)( sp: impl Into, msg: impl Into, - ) -> &mut Self); - forward!(pub fn is_lint(&mut self) -> &mut Self); - forward!(pub fn disable_suggestions(&mut self) -> &mut Self); - forward!(pub fn multipart_suggestion( - &mut self, + )); + forward!((multipart_suggestion, multipart_suggestion_mv)( msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn multipart_suggestion_verbose( - &mut self, + )); + forward!((multipart_suggestion_verbose, multipart_suggestion_verbose_mv)( msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn tool_only_multipart_suggestion( - &mut self, + )); + forward!((tool_only_multipart_suggestion, tool_only_multipart_suggestion_mv)( msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn span_suggestion( - &mut self, + )); + forward!((span_suggestion, span_suggestion_mv)( sp: Span, msg: impl Into, suggestion: impl ToString, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn span_suggestions( - &mut self, + )); + forward!((span_suggestions, span_suggestions_mv)( sp: Span, msg: impl Into, suggestions: impl IntoIterator, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn multipart_suggestions( - &mut self, + )); + forward!((multipart_suggestions, multipart_suggestions_mv)( msg: impl Into, suggestions: impl IntoIterator>, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn span_suggestion_short( - &mut self, + )); + forward!((span_suggestion_short, span_suggestion_short_mv)( sp: Span, msg: impl Into, suggestion: impl ToString, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn span_suggestion_verbose( - &mut self, + )); + forward!((span_suggestion_verbose, span_suggestion_verbose_mv)( sp: Span, msg: impl Into, suggestion: impl ToString, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn span_suggestion_hidden( - &mut self, + )); + forward!((span_suggestion_hidden, span_suggestion_hidden_mv)( sp: Span, msg: impl Into, suggestion: impl ToString, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn tool_only_span_suggestion( - &mut self, + )); + forward!((tool_only_span_suggestion, tool_only_span_suggestion_mv)( sp: Span, msg: impl Into, suggestion: impl ToString, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn primary_message(&mut self, msg: impl Into) -> &mut Self); - forward!(pub fn span(&mut self, sp: impl Into) -> &mut Self); - forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); - forward!(pub fn arg( - &mut self, - name: impl Into>, - arg: impl IntoDiagnosticArg, - ) -> &mut Self); - forward!(pub fn subdiagnostic( - &mut self, - subdiagnostic: impl crate::AddToDiagnostic - ) -> &mut Self); + )); + forward!((primary_message, primary_message_mv)( + msg: impl Into, + )); + forward!((span, span_mv)( + sp: impl Into, + )); + forward!((code, code_mv)( + s: DiagnosticId, + )); + forward!((arg, arg_mv)( + name: impl Into>, arg: impl IntoDiagnosticArg, + )); + forward!((subdiagnostic, subdiagnostic_mv)( + subdiagnostic: impl crate::AddToDiagnostic, + )); } impl Debug for DiagnosticBuilder<'_, G> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.diagnostic.fmt(f) + self.diag.fmt(f) } } -/// Destructor bomb - a `DiagnosticBuilder` must be either emitted or cancelled -/// or we emit a bug. +/// Destructor bomb: every `DiagnosticBuilder` must be consumed (emitted, +/// cancelled, etc.) or we emit a bug. impl Drop for DiagnosticBuilder<'_, G> { fn drop(&mut self) { - match self.state { - // No `.emit()` or `.cancel()` calls. - DiagnosticBuilderState::Emittable(dcx) => { - if !panicking() { - dcx.emit_diagnostic(Diagnostic::new( - Level::Bug, - DiagnosticMessage::from( - "the following error was constructed but not emitted", - ), - )); - dcx.emit_diagnostic_without_consuming(&mut self.diagnostic); - panic!("error was constructed but not emitted"); - } + match self.diag.take() { + Some(diag) if !panicking() => { + self.dcx.emit_diagnostic(Diagnostic::new( + Level::Bug, + DiagnosticMessage::from("the following error was constructed but not emitted"), + )); + self.dcx.emit_diagnostic(*diag); + panic!("error was constructed but not emitted"); } - // `.emit()` was previously called, or maybe we're during `.cancel()`. - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} + _ => {} } } } @@ -522,11 +455,11 @@ impl Drop for DiagnosticBuilder<'_, G> { #[macro_export] macro_rules! struct_span_err { ($dcx:expr, $span:expr, $code:ident, $($message:tt)*) => ({ - $dcx.struct_span_err_with_code( + $dcx.struct_span_err( $span, format!($($message)*), - $crate::error_code!($code), ) + .code_mv($crate::error_code!($code)) }) } diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index de27c6e910b2..58d4d2caf2ee 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -249,60 +249,43 @@ impl IntoDiagnosticArg for hir::def::Res { impl IntoDiagnostic<'_, G> for TargetDataLayoutErrors<'_> { fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { - let mut diag; match self { TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => { - diag = - DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_address_space); - diag.arg("addr_space", addr_space); - diag.arg("cause", cause); - diag.arg("err", err); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_address_space) + .arg_mv("addr_space", addr_space) + .arg_mv("cause", cause) + .arg_mv("err", err) } TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => { - diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits); - diag.arg("kind", kind); - diag.arg("bit", bit); - diag.arg("cause", cause); - diag.arg("err", err); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits) + .arg_mv("kind", kind) + .arg_mv("bit", bit) + .arg_mv("cause", cause) + .arg_mv("err", err) } TargetDataLayoutErrors::MissingAlignment { cause } => { - diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_missing_alignment); - diag.arg("cause", cause); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_missing_alignment) + .arg_mv("cause", cause) } TargetDataLayoutErrors::InvalidAlignment { cause, err } => { - diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_alignment); - diag.arg("cause", cause); - diag.arg("err_kind", err.diag_ident()); - diag.arg("align", err.align()); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_alignment) + .arg_mv("cause", cause) + .arg_mv("err_kind", err.diag_ident()) + .arg_mv("align", err.align()) } TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => { - diag = DiagnosticBuilder::new( - dcx, - level, - fluent::errors_target_inconsistent_architecture, - ); - diag.arg("dl", dl); - diag.arg("target", target); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_inconsistent_architecture) + .arg_mv("dl", dl) + .arg_mv("target", target) } TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => { - diag = DiagnosticBuilder::new( - dcx, - level, - fluent::errors_target_inconsistent_pointer_width, - ); - diag.arg("pointer_size", pointer_size); - diag.arg("target", target); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_inconsistent_pointer_width) + .arg_mv("pointer_size", pointer_size) + .arg_mv("target", target) } TargetDataLayoutErrors::InvalidBitsSize { err } => { - diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits_size); - diag.arg("err", err); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits_size) + .arg_mv("err", err) } } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 25bec9f766b0..76b7e0d79a98 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -7,9 +7,11 @@ #![feature(rustdoc_internals)] #![feature(array_windows)] #![feature(associated_type_defaults)] +#![feature(box_into_inner)] #![feature(extract_if)] #![feature(if_let_guard)] #![feature(let_chains)] +#![feature(negative_impls)] #![feature(never_type)] #![feature(rustc_attrs)] #![feature(yeet_expr)] @@ -507,11 +509,11 @@ pub enum StashKey { Cycle, } -fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) { - (*f)(d) +fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) { + (*f)(diag) } -pub static TRACK_DIAGNOSTICS: AtomicRef = +pub static TRACK_DIAGNOSTICS: AtomicRef = AtomicRef::new(&(default_track_diagnostic as _)); #[derive(Copy, Clone, Default)] @@ -522,9 +524,6 @@ pub struct DiagCtxtFlags { /// If Some, the Nth error-level diagnostic is upgraded to bug-level. /// (rustc: see `-Z treat-err-as-bug`) pub treat_err_as_bug: Option, - /// If true, immediately emit diagnostics that would otherwise be buffered. - /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`) - pub dont_buffer_diagnostics: bool, /// Show macro backtraces. /// (rustc: see `-Z macro-backtrace`) pub macro_backtrace: bool, @@ -728,24 +727,7 @@ impl DiagCtxt { span: impl Into, msg: impl Into, ) -> DiagnosticBuilder<'_, ()> { - let mut result = self.struct_warn(msg); - result.span(span); - result - } - - /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. - /// Also include a code. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_span_warn_with_code( - &self, - span: impl Into, - msg: impl Into, - code: DiagnosticId, - ) -> DiagnosticBuilder<'_, ()> { - let mut result = self.struct_span_warn(span, msg); - result.code(code); - result + self.struct_warn(msg).span_mv(span) } /// Construct a builder at the `Warning` level with the `msg`. @@ -785,23 +767,7 @@ impl DiagCtxt { span: impl Into, msg: impl Into, ) -> DiagnosticBuilder<'_> { - let mut result = self.struct_err(msg); - result.span(span); - result - } - - /// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_span_err_with_code( - &self, - span: impl Into, - msg: impl Into, - code: DiagnosticId, - ) -> DiagnosticBuilder<'_> { - let mut result = self.struct_span_err(span, msg); - result.code(code); - result + self.struct_err(msg).span_mv(span) } /// Construct a builder at the `Error` level with the `msg`. @@ -812,32 +778,6 @@ impl DiagCtxt { DiagnosticBuilder::new(self, Error, msg) } - /// Construct a builder at the `Error` level with the `msg` and the `code`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_err_with_code( - &self, - msg: impl Into, - code: DiagnosticId, - ) -> DiagnosticBuilder<'_> { - let mut result = self.struct_err(msg); - result.code(code); - result - } - - /// Construct a builder at the `Warn` level with the `msg` and the `code`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_warn_with_code( - &self, - msg: impl Into, - code: DiagnosticId, - ) -> DiagnosticBuilder<'_, ()> { - let mut result = self.struct_warn(msg); - result.code(code); - result - } - /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`. #[rustc_lint_diagnostics] #[track_caller] @@ -846,23 +786,7 @@ impl DiagCtxt { span: impl Into, msg: impl Into, ) -> DiagnosticBuilder<'_, FatalAbort> { - let mut result = self.struct_fatal(msg); - result.span(span); - result - } - - /// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_span_fatal_with_code( - &self, - span: impl Into, - msg: impl Into, - code: DiagnosticId, - ) -> DiagnosticBuilder<'_, FatalAbort> { - let mut result = self.struct_span_fatal(span, msg); - result.code(code); - result + self.struct_fatal(msg).span_mv(span) } /// Construct a builder at the `Fatal` level with the `msg`. @@ -903,9 +827,7 @@ impl DiagCtxt { span: impl Into, msg: impl Into, ) -> DiagnosticBuilder<'_, BugAbort> { - let mut result = self.struct_bug(msg); - result.span(span); - result + self.struct_bug(msg).span_mv(span) } #[rustc_lint_diagnostics] @@ -914,17 +836,6 @@ impl DiagCtxt { self.struct_span_fatal(span, msg).emit() } - #[rustc_lint_diagnostics] - #[track_caller] - pub fn span_fatal_with_code( - &self, - span: impl Into, - msg: impl Into, - code: DiagnosticId, - ) -> ! { - self.struct_span_fatal_with_code(span, msg, code).emit() - } - #[rustc_lint_diagnostics] #[track_caller] pub fn span_err( @@ -935,34 +846,12 @@ impl DiagCtxt { self.struct_span_err(span, msg).emit() } - #[rustc_lint_diagnostics] - #[track_caller] - pub fn span_err_with_code( - &self, - span: impl Into, - msg: impl Into, - code: DiagnosticId, - ) -> ErrorGuaranteed { - self.struct_span_err_with_code(span, msg, code).emit() - } - #[rustc_lint_diagnostics] #[track_caller] pub fn span_warn(&self, span: impl Into, msg: impl Into) { self.struct_span_warn(span, msg).emit() } - #[rustc_lint_diagnostics] - #[track_caller] - pub fn span_warn_with_code( - &self, - span: impl Into, - msg: impl Into, - code: DiagnosticId, - ) { - self.struct_span_warn_with_code(span, msg, code).emit() - } - pub fn span_bug(&self, span: impl Into, msg: impl Into) -> ! { self.struct_span_bug(span, msg).emit() } @@ -1020,9 +909,7 @@ impl DiagCtxt { span: impl Into, msg: impl Into, ) -> DiagnosticBuilder<'_, ()> { - let mut db = DiagnosticBuilder::new(self, Note, msg); - db.span(span); - db + DiagnosticBuilder::new(self, Note, msg).span_mv(span) } #[rustc_lint_diagnostics] @@ -1184,17 +1071,8 @@ impl DiagCtxt { self.inner.borrow_mut().emitter.emit_diagnostic(&db); } - pub fn emit_diagnostic(&self, mut diagnostic: Diagnostic) -> Option { - self.emit_diagnostic_without_consuming(&mut diagnostic) - } - - // It's unfortunate this exists. `emit_diagnostic` is preferred, because it - // consumes the diagnostic, thus ensuring it is emitted just once. - pub(crate) fn emit_diagnostic_without_consuming( - &self, - diagnostic: &mut Diagnostic, - ) -> Option { - self.inner.borrow_mut().emit_diagnostic_without_consuming(diagnostic) + pub fn emit_diagnostic(&self, diagnostic: Diagnostic) -> Option { + self.inner.borrow_mut().emit_diagnostic(diagnostic) } #[track_caller] @@ -1383,13 +1261,6 @@ impl DiagCtxtInner { } fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option { - self.emit_diagnostic_without_consuming(&mut diagnostic) - } - - fn emit_diagnostic_without_consuming( - &mut self, - diagnostic: &mut Diagnostic, - ) -> Option { if matches!(diagnostic.level, Error | Fatal) && self.treat_err_as_bug() { diagnostic.level = Bug; } @@ -1445,7 +1316,7 @@ impl DiagCtxtInner { } let mut guaranteed = None; - (*TRACK_DIAGNOSTICS)(diagnostic, &mut |diagnostic| { + (*TRACK_DIAGNOSTICS)(diagnostic, &mut |mut diagnostic| { if let Some(ref code) = diagnostic.code { self.emitted_diagnostic_codes.insert(code.clone()); } @@ -1481,7 +1352,7 @@ impl DiagCtxtInner { ); } - self.emitter.emit_diagnostic(diagnostic); + self.emitter.emit_diagnostic(&diagnostic); if diagnostic.is_error() { self.deduplicated_err_count += 1; } else if let Warning(_) = diagnostic.level { diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 9189a501aa5f..63247f9d0519 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -9,7 +9,6 @@ doctest = false [dependencies] # tidy-alphabetical-start -crossbeam-channel = "0.5.0" rustc_ast = { path = "../rustc_ast" } rustc_ast_passes = { path = "../rustc_ast_passes" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 8b5a22d19146..e87f2306bc70 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1232,7 +1232,7 @@ pub fn expr_to_string( ) -> Option<(Symbol, ast::StrStyle)> { expr_to_spanned_string(cx, expr, err_msg) .map_err(|err| { - err.map(|(mut err, _)| { + err.map(|(err, _)| { err.emit(); }) }) @@ -1254,7 +1254,7 @@ pub fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str pub fn parse_expr(p: &mut parser::Parser<'_>) -> Option> { match p.parse_expr() { Ok(e) => return Some(e), - Err(mut err) => { + Err(err) => { err.emit(); } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 2283a3bfc760..d015d7799632 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -362,7 +362,7 @@ impl<'a> StripUnconfigured<'a> { pub(crate) fn cfg_true(&self, attr: &Attribute) -> (bool, Option) { let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) { Ok(meta_item) => meta_item, - Err(mut err) => { + Err(err) => { err.emit(); return (true, None); } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 5a616e0ffbff..c39a3dce34e4 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -735,7 +735,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fragment_kind.expect_from_annotatables(items) } } - Err(mut err) => { + Err(err) => { err.emit(); fragment_kind.dummy(span) } diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index b248a1fe349b..b86831b8222d 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -679,8 +679,8 @@ impl TtParser { // We use the span of the metavariable declaration to determine any // edition-specific matching behavior for non-terminals. let nt = match parser.to_mut().parse_nonterminal(kind) { - Err(mut err) => { - let guarantee = err.span_label( + Err(err) => { + let guarantee = err.span_label_mv( span, format!( "while parsing argument for this `{kind}` macro fragment" diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index e9797abcbdf2..68296700987e 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -215,7 +215,7 @@ fn expand_macro<'cx>( // rhs has holes ( `$id` and `$(...)` that need filled) let tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) { Ok(tts) => tts, - Err(mut err) => { + Err(err) => { err.emit(); return DummyResult::any(arm_span); } diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 445be01bc97c..c3e4f40c166a 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -72,7 +72,7 @@ pub(super) fn parse( // `SyntaxContext::root()` from a foreign crate will // have the edition of that crate (which we manually // retrieve via the `edition` parameter). - if span.ctxt().is_root() { + if !span.from_expansion() { edition } else { span.edition() @@ -86,7 +86,7 @@ pub(super) fn parse( ); sess.dcx .struct_span_err(span, msg) - .help(VALID_FRAGMENT_NAMES_MSG) + .help_mv(VALID_FRAGMENT_NAMES_MSG) .emit(); token::NonterminalKind::Ident }, @@ -175,7 +175,7 @@ fn parse_tree<'a>( // of a meta-variable expression (e.g. `${count(ident)}`). // Try to parse the meta-variable expression. match MetaVarExpr::parse(tts, delim_span.entire(), sess) { - Err(mut err) => { + Err(err) => { err.emit(); // Returns early the same read `$` to avoid spanning // unrelated diagnostics that could be performed afterwards diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index c969ca7ef89b..434891ebc76e 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -13,19 +13,28 @@ use rustc_errors::DiagnosticBuilder; use rustc_errors::{pluralize, PResult}; use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent}; -use rustc_span::Span; +use rustc_span::{Span, SyntaxContext}; use smallvec::{smallvec, SmallVec}; use std::mem; // A Marker adds the given mark to the syntax context. -struct Marker(LocalExpnId, Transparency); +struct Marker(LocalExpnId, Transparency, FxHashMap); impl MutVisitor for Marker { const VISIT_TOKENS: bool = true; fn visit_span(&mut self, span: &mut Span) { - *span = span.apply_mark(self.0.to_expn_id(), self.1) + // `apply_mark` is a relatively expensive operation, both due to taking hygiene lock, and + // by itself. All tokens in a macro body typically have the same syntactic context, unless + // it's some advanced case with macro-generated macros. So if we cache the marked version + // of that context once, we'll typically have a 100% cache hit rate after that. + let Marker(expn_id, transparency, ref mut cache) = *self; + let data = span.data(); + let marked_ctxt = *cache + .entry(data.ctxt) + .or_insert_with(|| data.ctxt.apply_mark(expn_id.to_expn_id(), transparency)); + *span = data.with_ctxt(marked_ctxt); } } @@ -123,7 +132,7 @@ pub(super) fn transcribe<'a>( // again, and we are done transcribing. let mut result: Vec = Vec::new(); let mut result_stack = Vec::new(); - let mut marker = Marker(cx.current_expansion.id, transparency); + let mut marker = Marker(cx.current_expansion.id, transparency, Default::default()); loop { // Look at the last frame on the stack. diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 60647c3350a3..e979f9a75d4d 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -282,7 +282,7 @@ impl ModError<'_> { secondary_path: secondary_path.display().to_string(), }) } - ModError::ParserError(mut err) => err.emit(), + ModError::ParserError(err) => err.emit(), } } } diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 73a7d433b5c6..a1d213619571 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -13,16 +13,16 @@ use rustc_session::config::ProcMacroExecutionStrategy; use rustc_span::profiling::SpannedEventArgRecorder; use rustc_span::{Span, DUMMY_SP}; -struct CrossbeamMessagePipe { - tx: crossbeam_channel::Sender, - rx: crossbeam_channel::Receiver, +struct MessagePipe { + tx: std::sync::mpsc::SyncSender, + rx: std::sync::mpsc::Receiver, } -impl pm::bridge::server::MessagePipe for CrossbeamMessagePipe { +impl pm::bridge::server::MessagePipe for MessagePipe { fn new() -> (Self, Self) { - let (tx1, rx1) = crossbeam_channel::bounded(1); - let (tx2, rx2) = crossbeam_channel::bounded(1); - (CrossbeamMessagePipe { tx: tx1, rx: rx2 }, CrossbeamMessagePipe { tx: tx2, rx: rx1 }) + let (tx1, rx1) = std::sync::mpsc::sync_channel(1); + let (tx2, rx2) = std::sync::mpsc::sync_channel(1); + (MessagePipe { tx: tx1, rx: rx2 }, MessagePipe { tx: tx2, rx: rx1 }) } fn send(&mut self, value: T) { @@ -35,7 +35,7 @@ impl pm::bridge::server::MessagePipe for CrossbeamMessagePipe { } fn exec_strategy(ecx: &ExtCtxt<'_>) -> impl pm::bridge::server::ExecutionStrategy { - pm::bridge::server::MaybeCrossThread::>::new( + pm::bridge::server::MaybeCrossThread::>::new( ecx.sess.opts.unstable_opts.proc_macro_execution_strategy == ProcMacroExecutionStrategy::CrossThread, ) @@ -171,7 +171,7 @@ impl MultiItemModifier for DeriveProcMacro { items.push(Annotatable::Item(item)); } } - Err(mut err) => { + Err(err) => { err.emit(); break; } diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 66695e020f1d..0053f5503186 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -537,7 +537,7 @@ impl server::TokenStream for Rustc<'_, '_> { } expr }; - let expr = expr.map_err(|mut err| { + let expr = expr.map_err(|err| { err.emit(); })?; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e88b876534e5..082658a3a3b0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1361,6 +1361,12 @@ impl CoroutineKind { } } +impl CoroutineKind { + pub fn is_fn_like(self) -> bool { + matches!(self, CoroutineKind::Desugared(_, CoroutineSource::Fn)) + } +} + impl fmt::Display for CoroutineKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -1997,7 +2003,7 @@ pub enum LocalSource { AsyncFn, /// A desugared `.await`. AwaitDesugar, - /// A desugared `expr = expr`, where the LHS is a tuple, struct or array. + /// A desugared `expr = expr`, where the LHS is a tuple, struct, array or underscore expression. /// The span is that of the `=` sign. AssignDesugar(Span), } diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index b671bebeb050..b5ebc1fab765 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -17,6 +17,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_lint_defs = { path = "../rustc_lint_defs" } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index d8b6b9a1272f..6a17668ad17f 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -346,6 +346,20 @@ hir_analysis_start_not_target_feature = `#[start]` function is not allowed to ha hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]` .label = `#[start]` function is not allowed to be `#[track_caller]` +hir_analysis_static_mut_ref = reference of mutable static is disallowed + .label = reference of mutable static + .note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + .suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + .suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + +hir_analysis_static_mut_ref_lint = {$shared}reference of mutable static is discouraged + .label = shared reference of mutable static + .label_mut = mutable reference of mutable static + .suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + .suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + .note = reference of mutable static is a hard error from 2024 edition + .why_note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + hir_analysis_static_specialize = cannot specialize on `'static` lifetime hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index d403f1a850d9..38184a5dd182 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -305,7 +305,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { binding.span, format!("{} `{}` is private", assoc_item.kind, binding.item_name), ) - .span_label(binding.span, format!("private {}", assoc_item.kind)) + .span_label_mv(binding.span, format!("private {}", assoc_item.kind)) .emit(); } tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None); diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 5e1c29440a50..24b55461a427 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -58,13 +58,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if !trait_def.paren_sugar { if trait_segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar { // For now, require that parenthetical notation be used only with `Fn()` etc. - let mut err = feature_err( + feature_err( &self.tcx().sess.parse_sess, sym::unboxed_closures, span, "parenthetical notation is only stable when used with `Fn`-family traits", - ); - err.emit(); + ) + .emit(); } return; diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 3f0ad6584b65..adc6a9de8086 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -70,7 +70,7 @@ fn generic_arg_mismatch_err( Res::Err => { add_braces_suggestion(arg, &mut err); return err - .primary_message("unresolved item provided when a constant was expected") + .primary_message_mv("unresolved item provided when a constant was expected") .emit(); } Res::Def(DefKind::TyParam, src_def_id) => { @@ -650,9 +650,9 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes( if position == GenericArgPosition::Value && args.num_lifetime_params() != param_counts.lifetimes { - let mut err = struct_span_err!(tcx.dcx(), span, E0794, "{}", msg); - err.span_note(span_late, note); - err.emit(); + struct_span_err!(tcx.dcx(), span, E0794, "{}", msg) + .span_note_mv(span_late, note) + .emit(); } else { let mut multispan = MultiSpan::from_span(span); multispan.push_span_label(span_late, note); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 092df257dbfa..cdfb4c6389e1 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1032,7 +1032,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.trait_defines_associated_item_named(r.def_id(), assoc_kind, assoc_name) }); - let Some(mut bound) = matching_candidates.next() else { + let Some(bound) = matching_candidates.next() else { let reported = self.complain_about_assoc_item_not_found( all_candidates, &ty_param_name.to_string(), @@ -1046,38 +1046,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; debug!(?bound); - // look for a candidate that is not the same as our first bound, disregarding - // whether the bound is const. - let mut next_cand = matching_candidates.next(); - while let Some(mut bound2) = next_cand { - debug!(?bound2); - if bound2.bound_vars() != bound.bound_vars() { - break; - } - - let generics = tcx.generics_of(bound.def_id()); - let Some(host_index) = generics.host_effect_index else { break }; - - // always return the bound that contains the host param. - if let ty::ConstKind::Param(_) = bound2.skip_binder().args.const_at(host_index).kind() { - (bound, bound2) = (bound2, bound); - } - - let unconsted_args = bound - .skip_binder() - .args - .iter() - .enumerate() - .map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg }); - - if unconsted_args.eq(bound2.skip_binder().args.iter()) { - next_cand = matching_candidates.next(); - } else { - break; - } - } - - if let Some(bound2) = next_cand { + if let Some(bound2) = matching_candidates.next() { debug!(?bound2); let assoc_kind_str = assoc_kind_str(assoc_kind); @@ -1647,9 +1616,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let msg = format!("{kind} `{name}` is private"); let def_span = tcx.def_span(item); tcx.dcx() - .struct_span_err_with_code(span, msg, rustc_errors::error_code!(E0624)) - .span_label(span, format!("private {kind}")) - .span_label(def_span, format!("{kind} defined here")) + .struct_span_err(span, msg) + .code_mv(rustc_errors::error_code!(E0624)) + .span_label_mv(span, format!("private {kind}")) + .span_label_mv(def_span, format!("{kind} defined here")) .emit(); } tcx.check_stability(item, Some(block), span, None); diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index 8a3df79cb253..703e0bdc40ed 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -290,19 +290,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if references_self { let def_id = i.bottom().0.def_id(); - let mut err = struct_span_err!( + struct_span_err!( tcx.dcx(), i.bottom().1, E0038, "the {} `{}` cannot be made into an object", tcx.def_descr(def_id), tcx.item_name(def_id), - ); - err.note( + ) + .note_mv( rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![]) .error_msg(), - ); - err.emit(); + ) + .emit(); } ty::ExistentialTraitRef { def_id: trait_ref.def_id, args } @@ -375,7 +375,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ast_region_to_region(lifetime, None) } else { self.re_infer(None, span).unwrap_or_else(|| { - let mut err = struct_span_err!( + let err = struct_span_err!( tcx.dcx(), span, E0228, diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index b6688e0ce29e..b69f679880db 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -45,24 +45,6 @@ impl<'tcx> Bounds<'tcx> { polarity: ty::ImplPolarity, ) { self.push_trait_bound_inner(tcx, trait_ref, span, polarity); - - // push a non-const (`host = true`) version of the bound if it is `~const`. - if tcx.features().effects - && let Some(host_effect_idx) = tcx.generics_of(trait_ref.def_id()).host_effect_index - && trait_ref.skip_binder().args.const_at(host_effect_idx) != tcx.consts.true_ - { - let generics = tcx.generics_of(trait_ref.def_id()); - let Some(host_index) = generics.host_effect_index else { return }; - let trait_ref = trait_ref.map_bound(|mut trait_ref| { - trait_ref.args = - tcx.mk_args_from_iter(trait_ref.args.iter().enumerate().map(|(n, arg)| { - if host_index == n { tcx.consts.true_.into() } else { arg } - })); - trait_ref - }); - - self.push_trait_bound_inner(tcx, trait_ref, span, polarity); - } } fn push_trait_bound_inner( diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 5ccb7ac38964..7f23c04ce2df 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -17,7 +17,7 @@ use rustc_middle::middle::stability::EvalResult; use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; -use rustc_middle::ty::util::{Discr, IntTypeExt}; +use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt}; use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::{ AdtDef, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -213,13 +213,12 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { return; } - let args = GenericArgs::identity_for_item(tcx, item.owner_id); let span = tcx.def_span(item.owner_id.def_id); if tcx.type_of(item.owner_id.def_id).instantiate_identity().references_error() { return; } - if check_opaque_for_cycles(tcx, item.owner_id.def_id, args, span, origin).is_err() { + if check_opaque_for_cycles(tcx, item.owner_id.def_id, span).is_err() { return; } @@ -230,19 +229,36 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { pub(super) fn check_opaque_for_cycles<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, - args: GenericArgsRef<'tcx>, span: Span, - origin: &hir::OpaqueTyOrigin, ) -> Result<(), ErrorGuaranteed> { - if tcx.try_expand_impl_trait_type(def_id.to_def_id(), args).is_err() { - let reported = match origin { - hir::OpaqueTyOrigin::AsyncFn(..) => async_opaque_type_cycle_error(tcx, span), - _ => opaque_type_cycle_error(tcx, def_id, span), - }; - Err(reported) - } else { - Ok(()) + let args = GenericArgs::identity_for_item(tcx, def_id); + + // First, try to look at any opaque expansion cycles, considering coroutine fields + // (even though these aren't necessarily true errors). + if tcx + .try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::Yes) + .is_err() + { + // Look for true opaque expansion cycles, but ignore coroutines. + // This will give us any true errors. Coroutines are only problematic + // if they cause layout computation errors. + if tcx + .try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::No) + .is_err() + { + let reported = opaque_type_cycle_error(tcx, def_id, span); + return Err(reported); + } + + // And also look for cycle errors in the layout of coroutines. + if let Err(&LayoutError::Cycle(guar)) = + tcx.layout_of(tcx.param_env(def_id).and(Ty::new_opaque(tcx, def_id.to_def_id(), args))) + { + return Err(guar); + } } + + Ok(()) } /// Check that the concrete type behind `impl Trait` actually implements `Trait`. @@ -550,8 +566,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { E0044, "foreign items may not have {kinds} parameters", ) - .span_label(item.span, format!("can't have {kinds} parameters")) - .help( + .span_label_mv(item.span, format!("can't have {kinds} parameters")) + .help_mv( // FIXME: once we start storing spans for type arguments, turn this // into a suggestion. format!( @@ -788,7 +804,7 @@ fn check_impl_items_against_trait<'tcx>( }; tcx.dcx() .struct_span_err(tcx.def_span(def_id), msg) - .note(format!( + .note_mv(format!( "specialization behaves in inconsistent and \ surprising ways with {feature}, \ and for now is disallowed" @@ -830,7 +846,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { let e = fields[FieldIdx::from_u32(0)].ty(tcx, args); if !fields.iter().all(|f| f.ty(tcx, args) == e) { struct_span_err!(tcx.dcx(), sp, E0076, "SIMD vector should be homogeneous") - .span_label(sp, "SIMD elements must have the same type") + .span_label_mv(sp, "SIMD elements must have the same type") .emit(); return; } @@ -1107,7 +1123,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { E0084, "unsupported representation for zero-variant enum" ) - .span_label(tcx.def_span(def_id), "zero-variant enum") + .span_label_mv(tcx.def_span(def_id), "zero-variant enum") .emit(); } } @@ -1140,13 +1156,13 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { let disr_non_unit = def.variants().iter().any(|var| !is_unit(var) && has_disr(var)); if disr_non_unit || (disr_units && has_non_units) { - let mut err = struct_span_err!( + struct_span_err!( tcx.dcx(), tcx.def_span(def_id), E0732, "`#[repr(inttype)]` must be specified" - ); - err.emit(); + ) + .emit(); } } @@ -1249,7 +1265,7 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) } } - if let Some(mut e) = error { + if let Some(e) = error { e.emit(); } @@ -1294,22 +1310,12 @@ pub(super) fn check_type_params_are_used<'tcx>( { let span = tcx.def_span(param.def_id); struct_span_err!(tcx.dcx(), span, E0091, "type parameter `{}` is unused", param.name,) - .span_label(span, "unused type parameter") + .span_label_mv(span, "unused type parameter") .emit(); } } } -fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed { - struct_span_err!(tcx.dcx(), span, E0733, "recursion in an `async fn` requires boxing") - .span_label(span, "recursive `async fn`") - .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`") - .note( - "consider using the `async_recursion` crate: https://crates.io/crates/async_recursion", - ) - .emit() -} - /// Emit an error for recursive opaque types. /// /// If this is a return `impl Trait`, find the item's return expressions and point at them. For diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index cc4dc5aca0d9..46b5c1a94dec 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -934,12 +934,12 @@ impl<'tcx> ty::FallibleTypeFolder> for RemapHiddenTyRegions<'tcx> { return_span, "return type captures more lifetimes than trait definition", ) - .span_label(self.tcx.def_span(def_id), "this lifetime was captured") - .span_note( + .span_label_mv(self.tcx.def_span(def_id), "this lifetime was captured") + .span_note_mv( self.tcx.def_span(self.def_id), "hidden type must only reference lifetimes captured by this impl trait", ) - .note(format!("hidden type inferred to be `{}`", self.ty)) + .note_mv(format!("hidden type inferred to be `{}`", self.ty)) .emit() } _ => { @@ -1371,7 +1371,7 @@ fn compare_number_of_generics<'tcx>( let spans = arg_spans(impl_.kind, impl_item.generics); let span = spans.first().copied(); - let mut err = tcx.dcx().struct_span_err_with_code( + let mut err = tcx.dcx().struct_span_err( spans, format!( "{} `{}` has {} {kind} parameter{} but its trait \ @@ -1384,8 +1384,8 @@ fn compare_number_of_generics<'tcx>( pluralize!(trait_count), kind = kind, ), - DiagnosticId::Error("E0049".into()), ); + err.code(DiagnosticId::Error("E0049".into())); let msg = format!("expected {trait_count} {kind} parameter{}", pluralize!(trait_count),); diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 3492499db686..ff78d040aca1 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -161,7 +161,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( "`Drop` impl requires `{root_predicate}` \ but the {self_descr} it is implemented for does not", ) - .span_note(item_span, "the implementor must specify the same requirement") + .span_note_mv(item_span, "the implementor must specify the same requirement") .emit(), ); } @@ -193,7 +193,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( "`Drop` impl requires `{outlives}` \ but the {self_descr} it is implemented for does not", ) - .span_note(item_span, "the implementor must specify the same requirement") + .span_note_mv(item_span, "the implementor must specify the same requirement") .emit(), ); } diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs new file mode 100644 index 000000000000..27bb2c57a5cb --- /dev/null +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -0,0 +1,97 @@ +use rustc_hir as hir; +use rustc_hir_pretty::qpath_to_string; +use rustc_lint_defs::builtin::STATIC_MUT_REF; +use rustc_middle::ty::TyCtxt; +use rustc_span::Span; +use rustc_type_ir::Mutability; + +use crate::errors; + +/// Check for shared or mutable references of `static mut` inside expression +pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) { + let span = expr.span; + let hir_id = expr.hir_id; + if let hir::ExprKind::AddrOf(borrow_kind, m, expr) = expr.kind + && matches!(borrow_kind, hir::BorrowKind::Ref) + && let Some(var) = is_path_static_mut(*expr) + { + handle_static_mut_ref( + tcx, + span, + var, + span.edition().at_least_rust_2024(), + matches!(m, Mutability::Mut), + hir_id, + ); + } +} + +/// Check for shared or mutable references of `static mut` inside statement +pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) { + if let hir::StmtKind::Local(loc) = stmt.kind + && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind + && matches!(ba.0, rustc_ast::ByRef::Yes) + && let Some(init) = loc.init + && let Some(var) = is_path_static_mut(*init) + { + handle_static_mut_ref( + tcx, + init.span, + var, + loc.span.edition().at_least_rust_2024(), + matches!(ba.1, Mutability::Mut), + stmt.hir_id, + ); + } +} + +fn is_path_static_mut(expr: hir::Expr<'_>) -> Option { + if let hir::ExprKind::Path(qpath) = expr.kind + && let hir::QPath::Resolved(_, path) = qpath + && let hir::def::Res::Def(def_kind, _) = path.res + && let hir::def::DefKind::Static(mt) = def_kind + && matches!(mt, Mutability::Mut) + { + return Some(qpath_to_string(&qpath)); + } + None +} + +fn handle_static_mut_ref( + tcx: TyCtxt<'_>, + span: Span, + var: String, + e2024: bool, + mutable: bool, + hir_id: hir::HirId, +) { + if e2024 { + let sugg = if mutable { + errors::StaticMutRefSugg::Mut { span, var } + } else { + errors::StaticMutRefSugg::Shared { span, var } + }; + tcx.sess.parse_sess.dcx.emit_err(errors::StaticMutRef { span, sugg }); + return; + } + + let (label, sugg, shared) = if mutable { + ( + errors::RefOfMutStaticLabel::Mut { span }, + errors::RefOfMutStaticSugg::Mut { span, var }, + "mutable ", + ) + } else { + ( + errors::RefOfMutStaticLabel::Shared { span }, + errors::RefOfMutStaticSugg::Shared { span, var }, + "shared ", + ) + }; + tcx.emit_spanned_lint( + STATIC_MUT_REF, + hir_id, + span, + errors::RefOfMutStatic { shared, why_note: (), label, sugg }, + ); +} diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 632af780ed85..a5aedeb33ae9 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -30,7 +30,7 @@ fn equate_intrinsic_type<'tcx>( } _ => { struct_span_err!(tcx.dcx(), it.span, E0622, "intrinsic must be a function") - .span_label(it.span, "expected a function") + .span_label_mv(it.span, "expected a function") .emit(); return; } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index ac18e6de0bac..1979f52eda94 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -153,12 +153,14 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { }; let Some(asm_ty) = asm_ty else { let msg = format!("cannot use value of type `{ty}` for inline assembly"); - let mut err = self.tcx.dcx().struct_span_err(expr.span, msg); - err.note( - "only integers, floats, SIMD vectors, pointers and function pointers \ - can be used as arguments for inline assembly", - ); - err.emit(); + self.tcx + .dcx() + .struct_span_err(expr.span, msg) + .note_mv( + "only integers, floats, SIMD vectors, pointers and function pointers \ + can be used as arguments for inline assembly", + ) + .emit(); return None; }; @@ -166,9 +168,11 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // possibly fail is for SIMD types which don't #[derive(Copy)]. if !ty.is_copy_modulo_regions(self.tcx, self.param_env) { let msg = "arguments for inline assembly must be copyable"; - let mut err = self.tcx.dcx().struct_span_err(expr.span, msg); - err.note(format!("`{ty}` does not implement the Copy trait")); - err.emit(); + self.tcx + .dcx() + .struct_span_err(expr.span, msg) + .note_mv(format!("`{ty}` does not implement the Copy trait")) + .emit(); } // Ideally we wouldn't need to do this, but LLVM's register allocator @@ -183,16 +187,17 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if let Some((in_expr, Some(in_asm_ty))) = tied_input { if in_asm_ty != asm_ty { let msg = "incompatible types for asm inout argument"; - let mut err = self.tcx.dcx().struct_span_err(vec![in_expr.span, expr.span], msg); - let in_expr_ty = (self.get_operand_ty)(in_expr); - err.span_label(in_expr.span, format!("type `{in_expr_ty}`")); - err.span_label(expr.span, format!("type `{ty}`")); - err.note( - "asm inout arguments must have the same type, \ + self.tcx + .dcx() + .struct_span_err(vec![in_expr.span, expr.span], msg) + .span_label_mv(in_expr.span, format!("type `{in_expr_ty}`")) + .span_label_mv(expr.span, format!("type `{ty}`")) + .note_mv( + "asm inout arguments must have the same type, \ unless they are both pointers or integers of the same size", - ); - err.emit(); + ) + .emit(); } // All of the later checks have already been done on the input, so @@ -234,13 +239,15 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if let Some(feature) = feature { if !target_features.contains(feature) { let msg = format!("`{feature}` target feature is not enabled"); - let mut err = self.tcx.dcx().struct_span_err(expr.span, msg); - err.note(format!( - "this is required to use type `{}` with register class `{}`", - ty, - reg_class.name(), - )); - err.emit(); + self.tcx + .dcx() + .struct_span_err(expr.span, msg) + .note_mv(format!( + "this is required to use type `{}` with register class `{}`", + ty, + reg_class.name(), + )) + .emit(); return Some(asm_ty); } } @@ -449,14 +456,17 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::Never | ty::Error(_) => {} ty::FnDef(..) => {} _ => { - let mut err = - self.tcx.dcx().struct_span_err(*op_sp, "invalid `sym` operand"); - err.span_label( - self.tcx.def_span(anon_const.def_id), - format!("is {} `{}`", ty.kind().article(), ty), - ); - err.help("`sym` operands must refer to either a function or a static"); - err.emit(); + self.tcx + .dcx() + .struct_span_err(*op_sp, "invalid `sym` operand") + .span_label_mv( + self.tcx.def_span(anon_const.def_id), + format!("is {} `{}`", ty.kind().article(), ty), + ) + .help_mv( + "`sym` operands must refer to either a function or a static", + ) + .emit(); } }; } diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index f60d6950670d..ac0c715c6b30 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -66,6 +66,7 @@ mod check; mod compare_impl_item; pub mod dropck; mod entry; +mod errs; pub mod intrinsic; pub mod intrinsicck; mod region; diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 542e69a6c34d..5d5a4789734a 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -18,6 +18,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::source_map; use rustc_span::Span; +use super::errs::{maybe_expr_static_mut, maybe_stmt_static_mut}; + use std::mem; #[derive(Debug, Copy, Clone)] @@ -224,6 +226,8 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h let stmt_id = stmt.hir_id.local_id; debug!("resolve_stmt(stmt.id={:?})", stmt_id); + maybe_stmt_static_mut(visitor.tcx, *stmt); + // Every statement will clean up the temporaries created during // execution of that statement. Therefore each statement has an // associated destruction scope that represents the scope of the @@ -242,6 +246,8 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>) { debug!("resolve_expr - pre-increment {} expr = {:?}", visitor.expr_and_pat_count, expr); + maybe_expr_static_mut(visitor.tcx, *expr); + let prev_cx = visitor.cx; visitor.enter_node_scope_with_dtor(expr.hir_id.local_id); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 5f26da9c87f4..67ec2c3e5ea8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -197,11 +197,12 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() let mut res = Ok(()); if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) { let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span); - let mut err = - tcx.dcx().struct_span_err(sp, "impls of auto traits cannot be default"); - err.span_labels(impl_.defaultness_span, "default because of this"); - err.span_label(sp, "auto trait"); - res = Err(err.emit()); + res = Err(tcx + .dcx() + .struct_span_err(sp, "impls of auto traits cannot be default") + .span_labels_mv(impl_.defaultness_span, "default because of this") + .span_label_mv(sp, "auto trait") + .emit()); } // We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span. match tcx.impl_polarity(def_id) { @@ -489,35 +490,33 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { if !unsatisfied_bounds.is_empty() { let plural = pluralize!(unsatisfied_bounds.len()); - let mut err = tcx.dcx().struct_span_err( - gat_item_hir.span, - format!("missing required bound{} on `{}`", plural, gat_item_hir.ident), - ); - let suggestion = format!( "{} {}", gat_item_hir.generics.add_where_or_trailing_comma(), unsatisfied_bounds.join(", "), ); - err.span_suggestion( - gat_item_hir.generics.tail_span_for_predicate_suggestion(), - format!("add the required where clause{plural}"), - suggestion, - Applicability::MachineApplicable, - ); - let bound = if unsatisfied_bounds.len() > 1 { "these bounds are" } else { "this bound is" }; - err.note(format!( - "{bound} currently required to ensure that impls have maximum flexibility" - )); - err.note( - "we are soliciting feedback, see issue #87479 \ + tcx.dcx() + .struct_span_err( + gat_item_hir.span, + format!("missing required bound{} on `{}`", plural, gat_item_hir.ident), + ) + .span_suggestion_mv( + gat_item_hir.generics.tail_span_for_predicate_suggestion(), + format!("add the required where clause{plural}"), + suggestion, + Applicability::MachineApplicable, + ) + .note_mv(format!( + "{bound} currently required to ensure that impls have maximum flexibility" + )) + .note_mv( + "we are soliciting feedback, see issue #87479 \ \ for more information", - ); - - err.emit(); + ) + .emit(); } } } @@ -838,8 +837,8 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem trait_should_be_self, "associated item referring to unboxed trait object for its own trait", ) - .span_label(trait_name.span, "in this trait") - .multipart_suggestion( + .span_label_mv(trait_name.span, "in this trait") + .multipart_suggestion_mv( "you might have meant to use `Self` to refer to the implementing type", sugg, Applicability::MachineApplicable, @@ -938,8 +937,8 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), }; if may_suggest_feature && tcx.sess.is_nightly_build() { diag.help( - "add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types", - ); + "add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types", + ); } Err(diag.emit()) @@ -1599,7 +1598,7 @@ fn check_method_receiver<'tcx>( the `arbitrary_self_types` feature", ), ) - .help(HELP_FOR_SELF_TYPE) + .help_mv(HELP_FOR_SELF_TYPE) .emit() } else { // Report error; would not have worked with `arbitrary_self_types`. @@ -1612,8 +1611,8 @@ fn check_method_receiver<'tcx>( fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) -> ErrorGuaranteed { struct_span_err!(tcx.dcx(), span, E0307, "invalid `self` parameter type: {receiver_ty}") - .note("type of `self` must be `Self` or a type that dereferences to it") - .help(HELP_FOR_SELF_TYPE) + .note_mv("type of `self` must be `Self` or a type that dereferences to it") + .help_mv(HELP_FOR_SELF_TYPE) .emit() } @@ -1921,10 +1920,8 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error } fn error_392(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) -> DiagnosticBuilder<'_> { - let mut err = - struct_span_err!(tcx.dcx(), span, E0392, "parameter `{param_name}` is never used"); - err.span_label(span, "unused parameter"); - err + struct_span_err!(tcx.dcx(), span, E0392, "parameter `{param_name}` is never used") + .span_label_mv(span, "unused parameter") } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index ec15aa65e7ac..8f54bf00528c 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -70,17 +70,16 @@ impl<'tcx> InherentOverlapChecker<'tcx> { match seen_items.entry(norm_ident) { Entry::Occupied(entry) => { let former = entry.get(); - let mut err = struct_span_err!( + struct_span_err!( self.tcx.dcx(), span, E0592, "duplicate definitions with name `{}`", ident, - ); - err.span_label(span, format!("duplicate definitions for `{ident}`")); - err.span_label(*former, format!("other definition for `{ident}`")); - - err.emit(); + ) + .span_label_mv(span, format!("duplicate definitions for `{ident}`")) + .span_label_mv(*former, format!("other definition for `{ident}`")) + .emit(); } Entry::Vacant(entry) => { entry.insert(span); diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 5cc9da25d6a5..3d56f8fd44ea 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -181,7 +181,7 @@ fn check_object_overlap<'tcx>( trait_ref.self_ty(), tcx.def_path_str(trait_def_id) ) - .span_label( + .span_label_mv( span, format!( "`{}` automatically implements trait `{}`", diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index d208c55055b8..272c13b4c1c8 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -25,7 +25,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { "implementing the trait `{}` is not unsafe", trait_ref.print_trait_sugared() ) - .span_suggestion_verbose( + .span_suggestion_verbose_mv( item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)), "remove `unsafe` from this trait implementation", "", @@ -42,13 +42,13 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { "the trait `{}` requires an `unsafe impl` declaration", trait_ref.print_trait_sugared() ) - .note(format!( + .note_mv(format!( "the trait `{}` enforces invariants that the compiler can't check. \ Review the trait documentation and make sure this implementation \ upholds those invariants before adding the `unsafe` keyword", trait_ref.print_trait_sugared() )) - .span_suggestion_verbose( + .span_suggestion_verbose_mv( item.span.shrink_to_lo(), "add `unsafe` to this trait implementation", "unsafe ", @@ -65,13 +65,13 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { "requires an `unsafe impl` declaration due to `#[{}]` attribute", attr_name ) - .note(format!( + .note_mv(format!( "the trait `{}` enforces invariants that the compiler can't check. \ Review the trait documentation and make sure this implementation \ upholds those invariants before adding the `unsafe` keyword", trait_ref.print_trait_sugared() )) - .span_suggestion_verbose( + .span_suggestion_verbose_mv( item.span.shrink_to_lo(), "add `unsafe` to this trait implementation", "unsafe ", diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 41520718aa8d..ab9ed6ef98d9 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate}; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{Span, DUMMY_SP}; /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus @@ -38,38 +38,12 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic // an obligation and instead be skipped. Otherwise we'd use // `tcx.def_span(def_id);` let span = rustc_span::DUMMY_SP; - let non_const_bound = if tcx.features().effects && tcx.has_attr(def_id, sym::const_trait) { - // when `Self` is a const trait, also add `Self: Trait<.., true>` as implied bound, - // because only implementing `Self: Trait<.., false>` is currently not possible. - Some(( - ty::TraitRef::new( - tcx, - def_id, - ty::GenericArgs::for_item(tcx, def_id, |param, _| { - if param.is_host_effect() { - tcx.consts.true_.into() - } else { - tcx.mk_param_from_def(param) - } - }), - ) - .to_predicate(tcx), + + result.predicates = + tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once(( + ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), span, - )) - } else { - None - }; - result.predicates = tcx.arena.alloc_from_iter( - result - .predicates - .iter() - .copied() - .chain(std::iter::once(( - ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), - span, - ))) - .chain(non_const_bound), - ); + )))); } debug!("predicates_of(def_id={:?}) = {:?}", def_id, result); result diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 9a28534d7900..61bb4235139d 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -750,12 +750,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { kind: hir::ItemKind::OpaqueTy { .. }, .. }) = self.tcx.hir_node(parent_id) { - let mut err = self.tcx.dcx().struct_span_err( + self.tcx.dcx().struct_span_err( lifetime.ident.span, "higher kinded lifetime bounds on nested opaque types are not supported yet", - ); - err.span_note(self.tcx.def_span(def_id), "lifetime declared here"); - err.emit(); + ) + .span_note_mv(self.tcx.def_span(def_id), "lifetime declared here") + .emit(); self.uninsert_lifetime_on_error(lifetime, def.unwrap()); } } @@ -2114,7 +2114,7 @@ pub fn deny_non_region_late_bound( hir::GenericParamKind::Lifetime { .. } => continue, }; - let mut diag = tcx.dcx().struct_span_err( + let diag = tcx.dcx().struct_span_err( param.span, format!("late-bound {what} parameter not allowed on {where_}"), ); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 5a73097b0f6b..da7279967dac 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -69,6 +69,7 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local Node::Item(it) => locator.visit_item(it), Node::ImplItem(it) => locator.visit_impl_item(it), Node::TraitItem(it) => locator.visit_trait_item(it), + Node::ForeignItem(it) => locator.visit_foreign_item(it), other => bug!("{:?} is not a valid scope for an opaque type item", other), } } @@ -240,6 +241,12 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> { self.check(it.owner_id.def_id); intravisit::walk_trait_item(self, it); } + fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { + trace!(?it.owner_id); + assert_ne!(it.owner_id.def_id, self.def_id); + // No need to call `check`, as we do not run borrowck on foreign items. + intravisit::walk_foreign_item(self, it); + } } pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 9124d5021105..4f22da4ba3b9 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1410,3 +1410,94 @@ pub struct OnlyCurrentTraitsPointerSugg<'a> { pub mut_key: &'a str, pub ptr_ty: Ty<'a>, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_static_mut_ref, code = "E0796")] +#[note] +pub struct StaticMutRef { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub sugg: StaticMutRefSugg, +} + +#[derive(Subdiagnostic)] +pub enum StaticMutRefSugg { + #[suggestion( + hir_analysis_suggestion, + style = "verbose", + code = "addr_of!({var})", + applicability = "maybe-incorrect" + )] + Shared { + #[primary_span] + span: Span, + var: String, + }, + #[suggestion( + hir_analysis_suggestion_mut, + style = "verbose", + code = "addr_of_mut!({var})", + applicability = "maybe-incorrect" + )] + Mut { + #[primary_span] + span: Span, + var: String, + }, +} + +// STATIC_MUT_REF lint +#[derive(LintDiagnostic)] +#[diag(hir_analysis_static_mut_ref_lint)] +#[note] +pub struct RefOfMutStatic<'a> { + pub shared: &'a str, + #[note(hir_analysis_why_note)] + pub why_note: (), + #[subdiagnostic] + pub label: RefOfMutStaticLabel, + #[subdiagnostic] + pub sugg: RefOfMutStaticSugg, +} + +#[derive(Subdiagnostic)] +pub enum RefOfMutStaticLabel { + #[label(hir_analysis_label)] + Shared { + #[primary_span] + span: Span, + }, + #[label(hir_analysis_label_mut)] + Mut { + #[primary_span] + span: Span, + }, +} + +#[derive(Subdiagnostic)] +pub enum RefOfMutStaticSugg { + #[suggestion( + hir_analysis_suggestion, + style = "verbose", + code = "addr_of!({var})", + applicability = "maybe-incorrect" + )] + Shared { + #[primary_span] + span: Span, + var: String, + }, + #[suggestion( + hir_analysis_suggestion_mut, + style = "verbose", + code = "addr_of_mut!({var})", + applicability = "maybe-incorrect" + )] + Mut { + #[primary_span] + span: Span, + var: String, + }, +} diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index b9e7500c8942..dfc54ac5b23b 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -166,13 +166,12 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { // this ensures that later parts of type checking can assume that items // have valid types and not error - // FIXME(matthewjasper) We shouldn't need to use `track_errors`. - tcx.sess.track_errors(|| { - tcx.sess.time("type_collecting", || { - tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module)) - }); - })?; + tcx.sess.time("type_collecting", || { + tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module)) + }); + // FIXME(matthewjasper) We shouldn't need to use `track_errors` anywhere in this function + // or the compiler in general. if tcx.features().rustc_attrs { tcx.sess.track_errors(|| { tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx)); diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index ae68a8bf2811..04c42b4b2e63 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -523,8 +523,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { fn start_diagnostics(&self) -> DiagnosticBuilder<'tcx> { let span = self.path_segment.ident.span; let msg = self.create_error_message(); - - self.tcx.dcx().struct_span_err_with_code(span, msg, self.code()) + self.tcx.dcx().struct_span_err(span, msg).code_mv(self.code()) } /// Builds the `expected 1 type argument / supplied 2 type arguments` message. diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index de2cb5a6d5c7..fc61467df014 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -402,7 +402,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_expr.span, format!("evaluate({predicate:?}) = {result:?}"), ) - .span_label(predicate_span, "predicate") + .span_label_mv(predicate_span, "predicate") .emit(); } } @@ -490,11 +490,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.require_lang_item(hir::LangItem::FnOnce, Some(span)); let fn_once_output_def_id = self.tcx.require_lang_item(hir::LangItem::FnOnceOutput, Some(span)); - if self.tcx.generics_of(fn_once_def_id).host_effect_index.is_none() { - if idx == 0 && !self.tcx.is_const_fn_raw(def_id) { - self.dcx().emit_err(errors::ConstSelectMustBeConst { span }); - } - } else { + if self.tcx.has_host_param(fn_once_def_id) { let const_param: ty::GenericArg<'tcx> = ([self.tcx.consts.false_, self.tcx.consts.true_])[idx].into(); self.register_predicate(traits::Obligation::new( @@ -523,6 +519,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); self.select_obligations_where_possible(|_| {}); + } else if idx == 0 && !self.tcx.is_const_fn_raw(def_id) { + self.dcx().emit_err(errors::ConstSelectMustBeConst { span }); } } else { self.dcx().emit_err(errors::ConstSelectMustBeFn { span, ty: arg_ty }); diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 631854444793..0a9f2a27cb83 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -269,7 +269,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } CastError::NeedViaInt => { make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx) - .help("cast through an integer first") + .help_mv("cast through an integer first") .emit(); } CastError::IllegalCast => { @@ -277,7 +277,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } CastError::DifferingKinds => { make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx) - .note("vtable kinds may not match") + .note_mv("vtable kinds may not match") .emit(); } CastError::CastToBool => { @@ -512,7 +512,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.cast_ty, fcx, ) - .note("cannot cast an enum with a non-exhaustive variant when it's defined in another crate") + .note_mv("cannot cast an enum with a non-exhaustive variant when it's defined in another crate") .emit(); } } diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index c717319e5072..9850892bd36a 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -158,7 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Requires that the two types unify, and prints an error message if /// they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) { + if let Some(e) = self.demand_suptype_diag(sp, expected, actual) { e.emit(); } } @@ -189,7 +189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - if let Some(mut err) = self.demand_eqtype_diag(sp, expected, actual) { + if let Some(err) = self.demand_eqtype_diag(sp, expected, actual) { err.emit(); } } @@ -228,7 +228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let (ty, err) = self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase); - if let Some(mut err) = err { + if let Some(err) = err { err.emit(); } ty diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 44d9f1ed8184..7617f03fcf29 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -940,12 +940,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - // FIXME: Make this use Diagnostic once error codes can be dynamically set. - let mut err = self.dcx().struct_span_err_with_code( - op_span, - "invalid left-hand side of assignment", - DiagnosticId::Error(err_code.into()), - ); + let mut err = self.dcx().struct_span_err(op_span, "invalid left-hand side of assignment"); + err.code(DiagnosticId::Error(err_code.into())); err.span_label(lhs.span, "cannot assign to this expression"); self.comes_from_while_condition(lhs.hir_id, |expr| { @@ -1338,7 +1334,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Err(error) => { if segment.ident.name != kw::Empty { - if let Some(mut err) = self.report_method_error( + if let Some(err) = self.report_method_error( span, rcvr_t, segment.ident, @@ -2011,7 +2007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { != range_def_id { // Suppress any range expr type mismatches - if let Some(mut diag) = + if let Some(diag) = self.dcx().steal_diagnostic(last_expr_field.span, StashKey::MaybeFruTypo) { diag.delay_as_bug(); @@ -2836,15 +2832,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn private_field_err(&self, field: Ident, base_did: DefId) -> DiagnosticBuilder<'_> { let struct_path = self.tcx().def_path_str(base_did); let kind_name = self.tcx().def_descr(base_did); - let mut err = struct_span_err!( + struct_span_err!( self.dcx(), field.span, E0616, "field `{field}` of {kind_name} `{struct_path}` is private", - ); - err.span_label(field.span, "private field"); - - err + ) + .span_label_mv(field.span, "private field") } pub(crate) fn get_field_candidates_considering_privacy( @@ -3185,9 +3179,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized(ty, expr.span, traits::InlineAsmSized); if !is_input && !expr.is_syntactic_place_expr() { - let mut err = self.dcx().struct_span_err(expr.span, "invalid asm output"); - err.span_label(expr.span, "cannot assign to this expression"); - err.emit(); + self.dcx() + .struct_span_err(expr.span, "invalid asm output") + .span_label_mv(expr.span, "cannot assign to this expression") + .emit(); } // If this is an input value, we require its type to be fully resolved @@ -3280,27 +3275,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter_enumerated() .find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident) else { - let mut err = type_error_struct!( + type_error_struct!( self.dcx(), ident.span, container, E0599, "no variant named `{ident}` found for enum `{container}`", - ); - err.span_label(field.span, "variant not found"); - err.emit(); + ) + .span_label_mv(field.span, "variant not found") + .emit(); break; }; let Some(&subfield) = fields.next() else { - let mut err = type_error_struct!( + type_error_struct!( self.dcx(), ident.span, container, E0795, "`{ident}` is an enum variant; expected field at end of `offset_of`", - ); - err.span_label(field.span, "enum variant"); - err.emit(); + ) + .span_label_mv(field.span, "enum variant") + .emit(); break; }; let (subident, sub_def_scope) = @@ -3311,16 +3306,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter_enumerated() .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident) else { - let mut err = type_error_struct!( + type_error_struct!( self.dcx(), ident.span, container, E0609, "no field named `{subfield}` on enum variant `{container}::{ident}`", - ); - err.span_label(field.span, "this enum variant..."); - err.span_label(subident.span, "...does not have this field"); - err.emit(); + ) + .span_label_mv(field.span, "this enum variant...") + .span_label_mv(subident.span, "...does not have this field") + .emit(); break; }; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index cb109a2e0242..a4cd9ccc984e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -845,7 +845,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .and_then(|r| { // lint bare trait if the method is found in the trait if span.edition().at_least_rust_2021() - && let Some(mut diag) = + && let Some(diag) = self.dcx().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { diag.emit(); @@ -877,7 +877,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // emit or cancel the diagnostic for bare traits if span.edition().at_least_rust_2021() - && let Some(mut diag) = + && let Some(diag) = self.dcx().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { if trait_missing_method { @@ -889,7 +889,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if item_name.name != kw::Empty { - if let Some(mut e) = self.report_method_error( + if let Some(e) = self.report_method_error( span, ty.normalized, item_name, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 7b85c492eae5..da6f2042c110 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -664,7 +664,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("arguments to this {call_name} are incorrect"), ); } else { - err = tcx.dcx().struct_span_err_with_code( + err = tcx.dcx().struct_span_err( full_call_span, format!( "{call_name} takes {}{} but {} {} supplied", @@ -676,8 +676,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { potentially_plural_count(provided_args.len(), "argument"), pluralize!("was", provided_args.len()) ), - DiagnosticId::Error(err_code.to_owned()), ); + err.code(DiagnosticId::Error(err_code.to_owned())); err.multipart_suggestion_verbose( "wrap these arguments in parentheses to construct a tuple", vec![ @@ -815,18 +815,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_name, ) } else { - tcx.dcx().struct_span_err_with_code( - full_call_span, - format!( - "this {} takes {}{} but {} {} supplied", - call_name, - if c_variadic { "at least " } else { "" }, - potentially_plural_count(formal_and_expected_inputs.len(), "argument"), - potentially_plural_count(provided_args.len(), "argument"), - pluralize!("was", provided_args.len()) - ), - DiagnosticId::Error(err_code.to_owned()), - ) + tcx.dcx() + .struct_span_err( + full_call_span, + format!( + "this {} takes {}{} but {} {} supplied", + call_name, + if c_variadic { "at least " } else { "" }, + potentially_plural_count(formal_and_expected_inputs.len(), "argument"), + potentially_plural_count(provided_args.len(), "argument"), + pluralize!("was", provided_args.len()) + ), + ) + .code_mv(DiagnosticId::Error(err_code.to_owned())) }; // As we encounter issues, keep track of what we want to provide for the suggestion @@ -1384,7 +1385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "expected struct, variant or union type, found {}", ty.normalized.sort_string(self.tcx) ) - .span_label(path_span, "not a struct") + .span_label_mv(path_span, "not a struct") .emit(), }) } @@ -1459,8 +1460,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let previous_diverges = self.diverges.get(); let else_ty = self.check_block_with_expected(blk, NoExpectation); let cause = self.cause(blk.span, ObligationCauseCode::LetElse); - if let Some(mut err) = - self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) + if let Some(err) = self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) { err.emit(); } diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 44d28123fa3f..8bffd2dfc70a 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -74,9 +74,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && size_to == Pointer(dl.instruction_address_space).size(&tcx) { struct_span_err!(tcx.dcx(), span, E0591, "can't transmute zero-sized type") - .note(format!("source type: {from}")) - .note(format!("target type: {to}")) - .help("cast with `as` to a pointer instead") + .note_mv(format!("source type: {from}")) + .note_mv(format!("target type: {to}")) + .help_mv("cast with `as` to a pointer instead") .emit(); return; } @@ -121,6 +121,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); if from == to { err.note(format!("`{from}` does not have a fixed size")); + err.emit(); } else { err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from))) .note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to))); @@ -128,8 +129,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.delay_as_bug(); } else if let Err(LayoutError::ReferencesError(_)) = sk_to { err.delay_as_bug(); + } else { + err.emit(); } } - err.emit(); } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 6044b1fdd40a..ffae08d0f27c 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -366,18 +366,17 @@ fn report_unexpected_variant_res( _ => res.descr(), }; let path_str = rustc_hir_pretty::qpath_to_string(qpath); - let mut err = tcx.dcx().struct_span_err_with_code( - span, - format!("expected {expected}, found {res_descr} `{path_str}`"), - DiagnosticId::Error(err_code.into()), - ); + let err = tcx + .dcx() + .struct_span_err(span, format!("expected {expected}, found {res_descr} `{path_str}`")) + .code_mv(DiagnosticId::Error(err_code.into())); match res { Res::Def(DefKind::Fn | DefKind::AssocFn, _) if err_code == "E0164" => { let patterns_url = "https://doc.rust-lang.org/book/ch18-00-patterns.html"; - err.span_label(span, "`fn` calls are not allowed in patterns"); - err.help(format!("for more information, visit {patterns_url}")) + err.span_label_mv(span, "`fn` calls are not allowed in patterns") + .help_mv(format!("for more information, visit {patterns_url}")) } - _ => err.span_label(span, format!("not a {expected}")), + _ => err.span_label_mv(span, format!("not a {expected}")), } .emit() } diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 7b49a7cc009d..3b5226c64143 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -385,7 +385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let hir::ExprKind::Assign(..) = expr.kind { // We defer to the later error produced by `check_lhs_assignable`. - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); } let suggest_deref_binop = diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 02a35110716b..4ac85cce292f 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -117,7 +117,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { actual: Ty<'tcx>, ti: TopInfo<'tcx>, ) { - if let Some(mut err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) { + if let Some(err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) { err.emit(); } } @@ -441,7 +441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // then that's equivalent to there existing a LUB. let cause = self.pattern_cause(ti, span); - if let Some(mut err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) { + if let Some(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) { err.emit_unless( ti.span .filter(|&s| { @@ -1103,7 +1103,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type-check the tuple struct pattern against the expected type. let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, ti); - let had_err = if let Some(mut err) = diag { + let had_err = if let Some(err) = diag { err.emit(); true } else { @@ -1329,9 +1329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let element_tys = tcx.mk_type_list_from_iter(element_tys_iter); let pat_ty = Ty::new_tup(tcx, element_tys); - if let Some(mut err) = - self.demand_eqtype_pat_diag(span, expected, pat_ty, pat_info.top_info) - { + if let Some(err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, pat_info.top_info) { let reported = err.emit(); // Walk subpatterns with an expected type of `err` in this case to silence // further errors being emitted when using the bindings. #50333 @@ -1469,8 +1467,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } match (inexistent_fields_err, unmentioned_err) { - (Some(mut i), Some(mut u)) => { - if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { + (Some(i), Some(u)) => { + if let Some(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { // We don't want to show the nonexistent fields error when this was // `Foo { a, b }` when it should have been `Foo(a, b)`. i.delay_as_bug(); @@ -1481,19 +1479,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { u.emit(); } } - (None, Some(mut u)) => { - if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { + (None, Some(u)) => { + if let Some(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { u.delay_as_bug(); e.emit(); } else { u.emit(); } } - (Some(mut err), None) => { + (Some(err), None) => { err.emit(); } (None, None) - if let Some(mut err) = + if let Some(err) = self.error_tuple_variant_index_shorthand(variant, pat, fields) => { err.emit(); @@ -1543,19 +1541,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sp_comma = sm.end_point(pat.span.with_hi(sp_brace.hi())); let sugg = if no_fields || sp_brace != sp_comma { ".. }" } else { ", .. }" }; - let mut err = struct_span_err!( + struct_span_err!( self.dcx(), pat.span, E0638, "`..` required with {descr} marked as non-exhaustive", - ); - err.span_suggestion_verbose( + ) + .span_suggestion_verbose_mv( sp_comma, "add `..` at the end of the field list to ignore all other fields", sugg, Applicability::MachineApplicable, - ); - err.emit(); + ) + .emit(); } fn error_field_already_bound( @@ -1571,8 +1569,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "field `{}` bound multiple times in the pattern", ident ) - .span_label(span, format!("multiple uses of `{ident}` in pattern")) - .span_label(other_field, format!("first use of `{ident}`")) + .span_label_mv(span, format!("multiple uses of `{ident}` in pattern")) + .span_label_mv(other_field, format!("first use of `{ident}`")) .emit() } @@ -2237,7 +2235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pluralize!(min_len), size, ) - .span_label(span, format!("expected {} element{}", size, pluralize!(size))) + .span_label_mv(span, format!("expected {} element{}", size, pluralize!(size))) .emit() } @@ -2256,7 +2254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pluralize!(min_len), size, ) - .span_label( + .span_label_mv( span, format!("pattern cannot match array of {} element{}", size, pluralize!(size),), ) diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index c3bcdcfa5cd8..3825c513ef3f 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -332,15 +332,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if inside_union && source.ty_adt_def().is_some_and(|adt| adt.is_manually_drop()) { - let mut err = self.dcx().struct_span_err( + self.dcx().struct_span_err( expr.span, "not automatically applying `DerefMut` on `ManuallyDrop` union field", - ); - err.help( + ) + .help_mv( "writing to this reference calls the destructor for the old value", - ); - err.help("add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor"); - err.emit(); + ) + .help_mv("add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor") + .emit(); } } source = adjustment.target; diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index d730ef58deba..dfa3ced9dc14 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -10,7 +10,7 @@ use arrayvec::ArrayVec; use smallvec::{smallvec, SmallVec}; #[cfg(feature = "nightly")] -use rustc_macros::{Decodable, Encodable}; +use rustc_macros::{Decodable_Generic, Encodable_Generic}; use crate::{Idx, IndexVec}; @@ -112,7 +112,7 @@ macro_rules! bit_relations_inherent_impls { /// to or greater than the domain size. All operations that involve two bitsets /// will panic if the bitsets have differing domain sizes. /// -#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))] +#[cfg_attr(feature = "nightly", derive(Decodable_Generic, Encodable_Generic))] #[derive(Eq, PartialEq, Hash)] pub struct BitSet { domain_size: usize, @@ -1590,7 +1590,7 @@ impl From> for GrowableBitSet { /// /// All operations that involve a row and/or column index will panic if the /// index exceeds the relevant bound. -#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))] +#[cfg_attr(feature = "nightly", derive(Decodable_Generic, Encodable_Generic))] #[derive(Clone, Eq, PartialEq, Hash)] pub struct BitMatrix { num_rows: usize, @@ -1699,14 +1699,15 @@ impl BitMatrix { let (read_start, read_end) = self.range(read); let (write_start, write_end) = self.range(write); let words = &mut self.words[..]; - let mut changed = false; + let mut changed = 0; for (read_index, write_index) in iter::zip(read_start..read_end, write_start..write_end) { let word = words[write_index]; let new_word = word | words[read_index]; words[write_index] = new_word; - changed |= word != new_word; + // See `bitwise` for the rationale. + changed |= word ^ new_word; } - changed + changed != 0 } /// Adds the bits from `with` to the bits from row `write`, and @@ -1715,14 +1716,7 @@ impl BitMatrix { assert!(write.index() < self.num_rows); assert_eq!(with.domain_size(), self.num_columns); let (write_start, write_end) = self.range(write); - let mut changed = false; - for (read_index, write_index) in iter::zip(0..with.words.len(), write_start..write_end) { - let word = self.words[write_index]; - let new_word = word | with.words[read_index]; - self.words[write_index] = new_word; - changed |= word != new_word; - } - changed + bitwise(&mut self.words[write_start..write_end], &with.words, |a, b| a | b) } /// Sets every cell in `row` to true. @@ -2020,7 +2014,7 @@ impl std::fmt::Debug for FiniteBitSet { /// A fixed-sized bitset type represented by an integer type. Indices outwith than the range /// representable by `T` are considered set. -#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))] +#[cfg_attr(feature = "nightly", derive(Decodable_Generic, Encodable_Generic))] #[derive(Copy, Clone, Eq, PartialEq)] pub struct FiniteBitSet(pub T); diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 69a964484678..c156c13c9620 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -41,7 +41,33 @@ impl<'tcx> InferCtxt<'tcx> { where V: TypeFoldable>, { - self.canonicalize_query_with_mode(value, query_state, &CanonicalizeAllFreeRegions) + let (param_env, value) = value.into_parts(); + let param_env = self.tcx.canonical_param_env_cache.get_or_insert( + self.tcx, + param_env, + query_state, + |tcx, param_env, query_state| { + // FIXME(#118965): We don't canonicalize the static lifetimes that appear in the + // `param_env` beacause they are treated differently by trait selection. + Canonicalizer::canonicalize( + param_env, + None, + tcx, + &CanonicalizeFreeRegionsOtherThanStatic, + query_state, + ) + }, + ); + + Canonicalizer::canonicalize_with_base( + param_env, + value, + Some(self), + self.tcx, + &CanonicalizeAllFreeRegions, + query_state, + ) + .unchecked_map(|(param_env, value)| param_env.and(value)) } /// Canonicalizes a query *response* `V`. When we canonicalize a @@ -96,61 +122,6 @@ impl<'tcx> InferCtxt<'tcx> { &mut query_state, ) } - - /// A variant of `canonicalize_query` that does not - /// canonicalize `'static`. This is useful when - /// the query implementation can perform more efficient - /// handling of `'static` regions (e.g. trait evaluation). - pub fn canonicalize_query_keep_static( - &self, - value: ty::ParamEnvAnd<'tcx, V>, - query_state: &mut OriginalQueryValues<'tcx>, - ) -> Canonical<'tcx, ty::ParamEnvAnd<'tcx, V>> - where - V: TypeFoldable>, - { - self.canonicalize_query_with_mode( - value, - query_state, - &CanonicalizeFreeRegionsOtherThanStatic, - ) - } - - fn canonicalize_query_with_mode( - &self, - value: ty::ParamEnvAnd<'tcx, V>, - query_state: &mut OriginalQueryValues<'tcx>, - canonicalize_region_mode: &dyn CanonicalizeMode, - ) -> Canonical<'tcx, ty::ParamEnvAnd<'tcx, V>> - where - V: TypeFoldable>, - { - let (param_env, value) = value.into_parts(); - let base = self.tcx.canonical_param_env_cache.get_or_insert( - self.tcx, - param_env, - query_state, - |tcx, param_env, query_state| { - Canonicalizer::canonicalize( - param_env, - None, - tcx, - &CanonicalizeFreeRegionsOtherThanStatic, - query_state, - ) - }, - ); - - Canonicalizer::canonicalize_with_base( - base, - value, - Some(self), - self.tcx, - canonicalize_region_mode, - query_state, - ) - .unchecked_map(|(param_env, value)| param_env.and(value)) - } } /// Controls how we canonicalize "free regions" that are not inference diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b5a6374ec4b4..b1c360b61cb6 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -361,7 +361,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( ); } ty::ReError(_) => { - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); } _ => { // Ugh. This is a painful case: the hidden region is not one @@ -2356,15 +2356,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }, }; - let mut err = self.tcx.dcx().struct_span_err_with_code( - span, - format!("{labeled_user_string} may not live long enough"), - match sub.kind() { - ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => error_code!(E0309), - ty::ReStatic => error_code!(E0310), - _ => error_code!(E0311), - }, - ); + let mut err = self + .tcx + .dcx() + .struct_span_err(span, format!("{labeled_user_string} may not live long enough")); + err.code(match sub.kind() { + ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => error_code!(E0309), + ty::ReStatic => error_code!(E0310), + _ => error_code!(E0311), + }); '_explain: { let (description, span) = match sub.kind() { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index e13d1d38a89f..d3e28446ddef 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -60,7 +60,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { pub fn try_report(&self) -> Option { self.try_report_from_nll() - .map(|mut diag| diag.emit()) + .map(|diag| diag.emit()) .or_else(|| self.try_report_impl_not_conforming_to_trait()) .or_else(|| self.try_report_anon_anon_conflict()) .or_else(|| self.try_report_static_impl_trait()) diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index ae30cf53c71e..77a0accf80bb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -281,7 +281,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } }; if sub.is_error() || sup.is_error() { - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); } err } @@ -367,9 +367,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &trace.cause.code().peel_derives() { let span = *span; - let mut err = self.report_concrete_failure(placeholder_origin, sub, sup); - err.span_note(span, "the lifetime requirement is introduced here"); - err + self.report_concrete_failure(placeholder_origin, sub, sup) + .span_note_mv(span, "the lifetime requirement is introduced here") } else { unreachable!( "control flow ensures we have a `BindingObligation` or `ExprBindingObligation` here..." diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index ef00ced67ffe..7458be2c86da 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -29,7 +29,7 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { /// This is a callback from `rustc_errors` as it cannot access the implicit state /// in `rustc_middle` otherwise. It is used when diagnostic messages are /// emitted and stores them in the current query, if there is one. -fn track_diagnostic(diagnostic: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) { +fn track_diagnostic(diagnostic: Diagnostic, f: &mut dyn FnMut(Diagnostic)) { tls::with_context_opt(|icx| { if let Some(icx) = icx { if let Some(diagnostics) = icx.diagnostics { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 07bbe78dc2d4..9da806e0779a 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -108,7 +108,7 @@ impl<'tcx> Queries<'tcx> { pub fn parse(&self) -> Result> { self.parse.compute(|| { - passes::parse(&self.compiler.sess).map_err(|mut parse_error| parse_error.emit()) + passes::parse(&self.compiler.sess).map_err(|parse_error| parse_error.emit()) }) } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index f3f59b05682d..588139a303c5 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -659,7 +659,6 @@ fn test_unstable_options_tracking_hash() { // tidy-alphabetical-start untracked!(assert_incr_state, Some(String::from("loaded"))); untracked!(deduplicate_diagnostics, false); - untracked!(dont_buffer_diagnostics, true); untracked!(dump_dep_graph, true); untracked!(dump_mir, Some(String::from("abc"))); untracked!(dump_mir_dataflow, true); @@ -699,6 +698,7 @@ fn test_unstable_options_tracking_hash() { untracked!(query_dep_graph, true); untracked!(self_profile, SwitchWithOptPath::Enabled(None)); untracked!(self_profile_events, Some(vec![String::new()])); + untracked!(shell_argfiles, true); untracked!(span_debug, true); untracked!(span_free_formats, true); untracked!(temps_dir, Some(String::from("abc"))); diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 53d99c7f7f34..e3405aa2e559 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -549,7 +549,9 @@ declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]); impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { - if let ExprKind::Binary(BinOp { node: BinOpKind::Eq, .. }, lhs, rhs) = expr.kind { + if let ExprKind::Binary(BinOp { node: BinOpKind::Eq | BinOpKind::Ne, .. }, lhs, rhs) = + expr.kind + { if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) { cx.emit_spanned_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag); } diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 3eefd1b0e083..bdace8e01f6c 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -108,6 +108,10 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { if !matches!(local.pat.kind, hir::PatKind::Wild) { return; } + + if matches!(local.source, rustc_hir::LocalSource::AsyncFn) { + return; + } if let Some(init) = local.init { let init_ty = cx.typeck_results().expr_ty(init); // If the type has a trivial Drop implementation, then it doesn't @@ -126,6 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { suggestion: local.pat.span, multi_suggestion_start: local.span.until(init.span), multi_suggestion_end: init.span.shrink_to_hi(), + is_assign_desugar: matches!(local.source, rustc_hir::LocalSource::AssignDesugar(_)), }; if is_sync_lock { let mut span = MultiSpan::from_spans(vec![local.pat.span, init.span]); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 76c630fc456a..a9996e4a155b 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -513,6 +513,11 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see PR #117984 \ for more information", ); + store.register_removed( + "coinductive_overlap_in_coherence", + "converted into hard error, see PR #118649 \ + for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 614c3ecbcae2..bc9a9d7b7452 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -932,6 +932,7 @@ pub struct NonBindingLetSub { pub suggestion: Span, pub multi_suggestion_start: Span, pub multi_suggestion_end: Span, + pub is_assign_desugar: bool, } impl AddToDiagnostic for NonBindingLetSub { @@ -939,10 +940,11 @@ impl AddToDiagnostic for NonBindingLetSub { where F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { + let prefix = if self.is_assign_desugar { "let " } else { "" }; diag.span_suggestion_verbose( self.suggestion, fluent::lint_non_binding_let_suggestion, - "_unused", + format!("{prefix}_unused"), Applicability::MachineApplicable, ); diag.multipart_suggestion( diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index f0bbc03d7477..479acd88d718 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -111,10 +111,11 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc let mut arg_span = arg.span; let mut arg_macro = None; while !span.contains(arg_span) { - let expn = arg_span.ctxt().outer_expn_data(); - if expn.is_root() { + let ctxt = arg_span.ctxt(); + if ctxt.is_root() { break; } + let expn = ctxt.outer_expn_data(); arg_macro = expn.macro_def_id; arg_span = expn.call_site; } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 19da51b7dcfa..e917e7cb02b3 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -26,7 +26,6 @@ declare_lint_pass! { BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, CENUM_IMPL_DROP_CAST, COHERENCE_LEAK_CHECK, - COINDUCTIVE_OVERLAP_IN_COHERENCE, CONFLICTING_REPR_HINTS, CONST_EVALUATABLE_UNCHECKED, CONST_ITEM_MUTATION, @@ -89,6 +88,7 @@ declare_lint_pass! { SINGLE_USE_LIFETIMES, SOFT_UNSTABLE, STABLE_FEATURES, + STATIC_MUT_REF, SUSPICIOUS_AUTO_TRAIT_IMPLS, TEST_UNSTABLE_LINT, TEXT_DIRECTION_CODEPOINT_IN_COMMENT, @@ -1767,6 +1767,57 @@ declare_lint! { }; } +declare_lint! { + /// The `static_mut_ref` lint checks for shared or mutable references + /// of mutable static inside `unsafe` blocks and `unsafe` functions. + /// + /// ### Example + /// + /// ```rust,edition2021 + /// fn main() { + /// static mut X: i32 = 23; + /// static mut Y: i32 = 24; + /// + /// unsafe { + /// let y = &X; + /// let ref x = X; + /// let (x, y) = (&X, &Y); + /// foo(&X); + /// } + /// } + /// + /// unsafe fn _foo() { + /// static mut X: i32 = 23; + /// static mut Y: i32 = 24; + /// + /// let y = &X; + /// let ref x = X; + /// let (x, y) = (&X, &Y); + /// foo(&X); + /// } + /// + /// fn foo<'a>(_x: &'a i32) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Shared or mutable references of mutable static are almost always a mistake and + /// can lead to undefined behavior and various other problems in your code. + /// + /// This lint is "warn" by default on editions up to 2021, from 2024 there is + /// a hard error instead. + pub STATIC_MUT_REF, + Warn, + "shared references or mutable references of mutable static is discouraged", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), + reference: "issue #114447 ", + explain_reason: false, + }; +} + declare_lint! { /// The `absolute_paths_not_starting_with_crate` lint detects fully /// qualified paths that start with a module name instead of `crate`, @@ -4367,45 +4418,6 @@ declare_lint! { @feature_gate = sym::type_privacy_lints; } -declare_lint! { - /// The `coinductive_overlap_in_coherence` lint detects impls which are currently - /// considered not overlapping, but may be considered to overlap if support for - /// coinduction is added to the trait solver. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(coinductive_overlap_in_coherence)] - /// - /// trait CyclicTrait {} - /// impl CyclicTrait for T {} - /// - /// trait Trait {} - /// impl Trait for T {} - /// // conflicting impl with the above - /// impl Trait for u8 {} - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// We have two choices for impl which satisfy `u8: Trait`: the blanket impl - /// for generic `T`, and the direct impl for `u8`. These two impls nominally - /// overlap, since we can infer `T = u8` in the former impl, but since the where - /// clause `u8: CyclicTrait` would end up resulting in a cycle (since it depends - /// on itself), the blanket impl is not considered to hold for `u8`. This will - /// change in a future release. - pub COINDUCTIVE_OVERLAP_IN_COHERENCE, - Deny, - "impls that are not considered to overlap may be considered to \ - overlap in the future", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #114040 ", - }; -} - declare_lint! { /// The `unknown_or_malformed_diagnostic_attributes` lint detects unrecognized or otherwise malformed /// diagnostic attributes. diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index f558b74be9a9..f5d942b924e6 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -56,6 +56,8 @@ decl_derive!( hash_stable::hash_stable_no_context_derive ); +decl_derive!([Decodable_Generic] => serialize::decodable_generic_derive); +decl_derive!([Encodable_Generic] => serialize::encodable_generic_derive); decl_derive!([Decodable] => serialize::decodable_derive); decl_derive!([Encodable] => serialize::encodable_derive); decl_derive!([TyDecodable] => serialize::type_decodable_derive); diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 047066ac6815..9ca7ce09ba6c 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -31,6 +31,14 @@ pub fn meta_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: } pub fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + let decoder_ty = quote! { __D }; + s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_span::SpanDecoder}); + s.add_bounds(synstructure::AddBounds::Generics); + + decodable_body(s, decoder_ty) +} + +pub fn decodable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { let decoder_ty = quote! { __D }; s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_serialize::Decoder}); s.add_bounds(synstructure::AddBounds::Generics); @@ -129,6 +137,14 @@ pub fn meta_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: } pub fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + let encoder_ty = quote! { __E }; + s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_span::SpanEncoder}); + s.add_bounds(synstructure::AddBounds::Generics); + + encodable_body(s, encoder_ty, false) +} + +pub fn encodable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { let encoder_ty = quote! { __E }; s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder}); s.add_bounds(synstructure::AddBounds::Generics); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index d13a1664adea..49e849964be4 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -26,7 +26,7 @@ use rustc_serialize::{Decodable, Decoder}; use rustc_session::cstore::{CrateSource, ExternCrate}; use rustc_session::Session; use rustc_span::symbol::kw; -use rustc_span::{BytePos, Pos, SpanData, SyntaxContext, DUMMY_SP}; +use rustc_span::{BytePos, Pos, SpanData, SpanDecoder, SyntaxContext, DUMMY_SP}; use proc_macro::bridge::client::ProcMacro; use std::iter::TrustedLen; @@ -408,21 +408,6 @@ impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> Decodable> for CrateNum { - #[inline] - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> CrateNum { - let cnum = CrateNum::from_u32(d.read_u32()); - d.map_encoded_cnum_to_current(cnum) - } -} - -impl<'a, 'tcx> Decodable> for DefIndex { - #[inline] - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefIndex { - DefIndex::from_u32(d.read_u32()) - } -} - impl<'a, 'tcx> Decodable> for ExpnIndex { #[inline] fn decode(d: &mut DecodeContext<'a, 'tcx>) -> ExpnIndex { @@ -430,19 +415,29 @@ impl<'a, 'tcx> Decodable> for ExpnIndex { } } -impl<'a, 'tcx> Decodable> for ast::AttrId { - #[inline] - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> ast::AttrId { - let sess = d.sess.expect("can't decode AttrId without Session"); +impl<'a, 'tcx> SpanDecoder for DecodeContext<'a, 'tcx> { + fn decode_attr_id(&mut self) -> rustc_span::AttrId { + let sess = self.sess.expect("can't decode AttrId without Session"); sess.parse_sess.attr_id_generator.mk_attr_id() } -} -impl<'a, 'tcx> Decodable> for SyntaxContext { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SyntaxContext { - let cdata = decoder.cdata(); + fn decode_crate_num(&mut self) -> CrateNum { + let cnum = CrateNum::from_u32(self.read_u32()); + self.map_encoded_cnum_to_current(cnum) + } - let Some(sess) = decoder.sess else { + fn decode_def_index(&mut self) -> DefIndex { + DefIndex::from_u32(self.read_u32()) + } + + fn decode_def_id(&mut self) -> DefId { + DefId { krate: Decodable::decode(self), index: Decodable::decode(self) } + } + + fn decode_syntax_context(&mut self) -> SyntaxContext { + let cdata = self.cdata(); + + let Some(sess) = self.sess else { bug!( "Cannot decode SyntaxContext without Session.\ You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`." @@ -450,7 +445,7 @@ impl<'a, 'tcx> Decodable> for SyntaxContext { }; let cname = cdata.root.name(); - rustc_span::hygiene::decode_syntax_context(decoder, &cdata.hygiene_context, |_, id| { + rustc_span::hygiene::decode_syntax_context(self, &cdata.hygiene_context, |_, id| { debug!("SpecializedDecoder: decoding {}", id); cdata .root @@ -460,21 +455,19 @@ impl<'a, 'tcx> Decodable> for SyntaxContext { .decode((cdata, sess)) }) } -} -impl<'a, 'tcx> Decodable> for ExpnId { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> ExpnId { - let local_cdata = decoder.cdata(); + fn decode_expn_id(&mut self) -> ExpnId { + let local_cdata = self.cdata(); - let Some(sess) = decoder.sess else { + let Some(sess) = self.sess else { bug!( "Cannot decode ExpnId without Session. \ You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`." ); }; - let cnum = CrateNum::decode(decoder); - let index = u32::decode(decoder); + let cnum = CrateNum::decode(self); + let index = u32::decode(self); let expn_id = rustc_span::hygiene::decode_expn_id(cnum, index, |expn_id| { let ExpnId { krate: cnum, local_id: index } = expn_id; @@ -502,27 +495,51 @@ impl<'a, 'tcx> Decodable> for ExpnId { }); expn_id } -} -impl<'a, 'tcx> Decodable> for Span { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Span { - let start = decoder.position(); - let tag = SpanTag(decoder.peek_byte()); + fn decode_span(&mut self) -> Span { + let start = self.position(); + let tag = SpanTag(self.peek_byte()); let data = if tag.kind() == SpanKind::Indirect { // Skip past the tag we just peek'd. - decoder.read_u8(); - let offset_or_position = decoder.read_usize(); + self.read_u8(); + let offset_or_position = self.read_usize(); let position = if tag.is_relative_offset() { start - offset_or_position } else { offset_or_position }; - decoder.with_position(position, SpanData::decode) + self.with_position(position, SpanData::decode) } else { - SpanData::decode(decoder) + SpanData::decode(self) }; Span::new(data.lo, data.hi, data.ctxt, data.parent) } + + fn decode_symbol(&mut self) -> Symbol { + let tag = self.read_u8(); + + match tag { + SYMBOL_STR => { + let s = self.read_str(); + Symbol::intern(s) + } + SYMBOL_OFFSET => { + // read str offset + let pos = self.read_usize(); + + // move to str offset and read + self.opaque.with_position(pos, |d| { + let s = d.read_str(); + Symbol::intern(s) + }) + } + SYMBOL_PREINTERNED => { + let symbol_index = self.read_u32(); + Symbol::new_from_decoded(symbol_index) + } + _ => unreachable!(), + } + } } impl<'a, 'tcx> Decodable> for SpanData { @@ -630,34 +647,6 @@ impl<'a, 'tcx> Decodable> for SpanData { } } -impl<'a, 'tcx> Decodable> for Symbol { - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { - let tag = d.read_u8(); - - match tag { - SYMBOL_STR => { - let s = d.read_str(); - Symbol::intern(s) - } - SYMBOL_OFFSET => { - // read str offset - let pos = d.read_usize(); - - // move to str offset and read - d.opaque.with_position(pos, |d| { - let s = d.read_str(); - Symbol::intern(s) - }) - } - SYMBOL_PREINTERNED => { - let symbol_index = d.read_u32(); - Symbol::new_from_decoded(symbol_index) - } - _ => unreachable!(), - } - } -} - impl<'a, 'tcx> Decodable> for &'tcx [(ty::Clause<'tcx>, Span)] { fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { ty::codec::RefDecodable::decode(d) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 1d12b853b53d..a458b528a97c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -25,7 +25,7 @@ use rustc_session::config::{CrateType, OptLevel}; use rustc_span::hygiene::HygieneEncodeContext; use rustc_span::symbol::sym; use rustc_span::{ - ExternalSource, FileName, SourceFile, SpanData, StableSourceFileId, SyntaxContext, + ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, SyntaxContext, }; use std::borrow::Borrow; use std::collections::hash_map::Entry; @@ -123,70 +123,90 @@ impl<'a, 'tcx, I, T> Encodable> for LazyTable { } } -impl<'a, 'tcx> Encodable> for CrateNum { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - if *self != LOCAL_CRATE && s.is_proc_macro { - panic!("Attempted to encode non-local CrateNum {self:?} for proc-macro crate"); - } - s.emit_u32(self.as_u32()); - } -} - -impl<'a, 'tcx> Encodable> for DefIndex { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - s.emit_u32(self.as_u32()); - } -} - impl<'a, 'tcx> Encodable> for ExpnIndex { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { s.emit_u32(self.as_u32()); } } -impl<'a, 'tcx> Encodable> for SyntaxContext { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_ctxt, s); +impl<'a, 'tcx> SpanEncoder for EncodeContext<'a, 'tcx> { + fn encode_crate_num(&mut self, crate_num: CrateNum) { + if crate_num != LOCAL_CRATE && self.is_proc_macro { + panic!("Attempted to encode non-local CrateNum {crate_num:?} for proc-macro crate"); + } + self.emit_u32(crate_num.as_u32()); } -} -impl<'a, 'tcx> Encodable> for ExpnId { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - if self.krate == LOCAL_CRATE { + fn encode_def_index(&mut self, def_index: DefIndex) { + self.emit_u32(def_index.as_u32()); + } + + fn encode_def_id(&mut self, def_id: DefId) { + def_id.krate.encode(self); + def_id.index.encode(self); + } + + fn encode_syntax_context(&mut self, syntax_context: SyntaxContext) { + rustc_span::hygiene::raw_encode_syntax_context(syntax_context, self.hygiene_ctxt, self); + } + + fn encode_expn_id(&mut self, expn_id: ExpnId) { + if expn_id.krate == LOCAL_CRATE { // We will only write details for local expansions. Non-local expansions will fetch // data from the corresponding crate's metadata. // FIXME(#43047) FIXME(#74731) We may eventually want to avoid relying on external // metadata from proc-macro crates. - s.hygiene_ctxt.schedule_expn_data_for_encoding(*self); + self.hygiene_ctxt.schedule_expn_data_for_encoding(expn_id); } - self.krate.encode(s); - self.local_id.encode(s); + expn_id.krate.encode(self); + expn_id.local_id.encode(self); } -} -impl<'a, 'tcx> Encodable> for Span { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - match s.span_shorthands.entry(*self) { + fn encode_span(&mut self, span: Span) { + match self.span_shorthands.entry(span) { Entry::Occupied(o) => { // If an offset is smaller than the absolute position, we encode with the offset. // This saves space since smaller numbers encode in less bits. let last_location = *o.get(); // This cannot underflow. Metadata is written with increasing position(), so any // previously saved offset must be smaller than the current position. - let offset = s.opaque.position() - last_location; + let offset = self.opaque.position() - last_location; if offset < last_location { - SpanTag::indirect(true).encode(s); - offset.encode(s); + SpanTag::indirect(true).encode(self); + offset.encode(self); } else { - SpanTag::indirect(false).encode(s); - last_location.encode(s); + SpanTag::indirect(false).encode(self); + last_location.encode(self); } } Entry::Vacant(v) => { - let position = s.opaque.position(); + let position = self.opaque.position(); v.insert(position); // Data is encoded with a SpanTag prefix (see below). - self.data().encode(s); + span.data().encode(self); + } + } + } + + fn encode_symbol(&mut self, symbol: Symbol) { + // if symbol preinterned, emit tag and symbol index + if symbol.is_preinterned() { + self.opaque.emit_u8(SYMBOL_PREINTERNED); + self.opaque.emit_u32(symbol.as_u32()); + } else { + // otherwise write it as string or as offset to it + match self.symbol_table.entry(symbol) { + Entry::Vacant(o) => { + self.opaque.emit_u8(SYMBOL_STR); + let pos = self.opaque.position(); + o.insert(pos); + self.emit_str(symbol.as_str()); + } + Entry::Occupied(o) => { + let x = *o.get(); + self.emit_u8(SYMBOL_OFFSET); + self.emit_usize(x); + } } } } @@ -335,31 +355,6 @@ impl<'a, 'tcx> Encodable> for SpanData { } } -impl<'a, 'tcx> Encodable> for Symbol { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - // if symbol preinterned, emit tag and symbol index - if self.is_preinterned() { - s.opaque.emit_u8(SYMBOL_PREINTERNED); - s.opaque.emit_u32(self.as_u32()); - } else { - // otherwise write it as string or as offset to it - match s.symbol_table.entry(*self) { - Entry::Vacant(o) => { - s.opaque.emit_u8(SYMBOL_STR); - let pos = s.opaque.position(); - o.insert(pos); - s.emit_str(self.as_str()); - } - Entry::Occupied(o) => { - let x = *o.get(); - s.emit_u8(SYMBOL_OFFSET); - s.emit_usize(x); - } - } - } - } -} - impl<'a, 'tcx> Encodable> for [u8] { fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) { Encoder::emit_usize(e, self.len()); diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index d45ec8e46469..212e831e1061 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -357,7 +357,6 @@ pub fn struct_lint_level( if let Level::Expect(_) = level { let name = lint.name_lower(); err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn: false }); - decorate(&mut err); err.emit(); return; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index f0885f79657f..36f5ba161d5f 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -263,6 +263,23 @@ pub struct CoroutineInfo<'tcx> { pub coroutine_kind: CoroutineKind, } +impl<'tcx> CoroutineInfo<'tcx> { + // Sets up `CoroutineInfo` for a pre-coroutine-transform MIR body. + pub fn initial( + coroutine_kind: CoroutineKind, + yield_ty: Ty<'tcx>, + resume_ty: Ty<'tcx>, + ) -> CoroutineInfo<'tcx> { + CoroutineInfo { + coroutine_kind, + yield_ty: Some(yield_ty), + resume_ty: Some(resume_ty), + coroutine_drop: None, + coroutine_layout: None, + } + } +} + /// The lowered representation of a single function. #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct Body<'tcx> { @@ -367,7 +384,7 @@ impl<'tcx> Body<'tcx> { arg_count: usize, var_debug_info: Vec>, span: Span, - coroutine_kind: Option, + coroutine: Option>>, tainted_by_errors: Option, ) -> Self { // We need `arg_count` locals, and one for the return place. @@ -384,15 +401,7 @@ impl<'tcx> Body<'tcx> { source, basic_blocks: BasicBlocks::new(basic_blocks), source_scopes, - coroutine: coroutine_kind.map(|coroutine_kind| { - Box::new(CoroutineInfo { - yield_ty: None, - resume_ty: None, - coroutine_drop: None, - coroutine_layout: None, - coroutine_kind, - }) - }), + coroutine, local_decls, user_type_annotations, arg_count, @@ -1307,6 +1316,7 @@ impl<'tcx> BasicBlockData<'tcx> { } /// Does the block have no statements and an unreachable terminator? + #[inline] pub fn is_empty_unreachable(&self) -> bool { self.statements.is_empty() && matches!(self.terminator().kind, TerminatorKind::Unreachable) } @@ -1576,6 +1586,7 @@ impl Location { /// /// Note that if this location represents a terminator, then the /// resulting location would be out of bounds and invalid. + #[inline] pub fn successor_within_block(&self) -> Location { Location { block: self.block, statement_index: self.statement_index + 1 } } @@ -1612,6 +1623,7 @@ impl Location { false } + #[inline] pub fn dominates(&self, other: Location, dominators: &Dominators) -> bool { if self.block == other.block { self.statement_index <= other.statement_index @@ -1631,6 +1643,7 @@ pub enum DefLocation { } impl DefLocation { + #[inline] pub fn dominates(self, location: Location, dominators: &Dominators) -> bool { match self { DefLocation::Argument => true, diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 7be6deb61419..385237b357b4 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -26,6 +26,7 @@ impl SwitchTargets { } /// Inverse of `SwitchTargets::static_if`. + #[inline] pub fn as_static_if(&self) -> Option<(u128, BasicBlock, BasicBlock)> { if let &[value] = &self.values[..] && let &[then, else_] = &self.targets[..] @@ -37,6 +38,7 @@ impl SwitchTargets { } /// Returns the fallback target that is jumped to when none of the values match the operand. + #[inline] pub fn otherwise(&self) -> BasicBlock { *self.targets.last().unwrap() } @@ -47,15 +49,18 @@ impl SwitchTargets { /// including the `otherwise` fallback target. /// /// Note that this may yield 0 elements. Only the `otherwise` branch is mandatory. + #[inline] pub fn iter(&self) -> SwitchTargetsIter<'_> { SwitchTargetsIter { inner: iter::zip(&self.values, &self.targets) } } /// Returns a slice with all possible jump targets (including the fallback target). + #[inline] pub fn all_targets(&self) -> &[BasicBlock] { &self.targets } + #[inline] pub fn all_targets_mut(&mut self) -> &mut [BasicBlock] { &mut self.targets } @@ -63,6 +68,7 @@ impl SwitchTargets { /// Finds the `BasicBlock` to which this `SwitchInt` will branch given the /// specific value. This cannot fail, as it'll return the `otherwise` /// branch if there's not a specific match for the value. + #[inline] pub fn target_for_value(&self, value: u128) -> BasicBlock { self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise()) } @@ -75,10 +81,12 @@ pub struct SwitchTargetsIter<'a> { impl<'a> Iterator for SwitchTargetsIter<'a> { type Item = (u128, BasicBlock); + #[inline] fn next(&mut self) -> Option { self.inner.next().map(|(val, bb)| (*val, *bb)) } + #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } @@ -330,28 +338,34 @@ pub type SuccessorsMut<'a> = iter::Chain, slice::IterMut<'a, BasicBlock>>; impl<'tcx> Terminator<'tcx> { + #[inline] pub fn successors(&self) -> Successors<'_> { self.kind.successors() } + #[inline] pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { self.kind.successors_mut() } + #[inline] pub fn unwind(&self) -> Option<&UnwindAction> { self.kind.unwind() } + #[inline] pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> { self.kind.unwind_mut() } } impl<'tcx> TerminatorKind<'tcx> { + #[inline] pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> { TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) } } + #[inline] pub fn successors(&self) -> Successors<'_> { use self::TerminatorKind::*; match *self { @@ -392,6 +406,7 @@ impl<'tcx> TerminatorKind<'tcx> { } } + #[inline] pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { use self::TerminatorKind::*; match *self { @@ -430,6 +445,7 @@ impl<'tcx> TerminatorKind<'tcx> { } } + #[inline] pub fn unwind(&self) -> Option<&UnwindAction> { match *self { TerminatorKind::Goto { .. } @@ -449,6 +465,7 @@ impl<'tcx> TerminatorKind<'tcx> { } } + #[inline] pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> { match *self { TerminatorKind::Goto { .. } @@ -468,6 +485,7 @@ impl<'tcx> TerminatorKind<'tcx> { } } + #[inline] pub fn as_switch(&self) -> Option<(&Operand<'tcx>, &SwitchTargets)> { match self { TerminatorKind::SwitchInt { discr, targets } => Some((discr, targets)), @@ -475,6 +493,7 @@ impl<'tcx> TerminatorKind<'tcx> { } } + #[inline] pub fn as_goto(&self) -> Option { match self { TerminatorKind::Goto { target } => Some(*target), diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 113763450529..945f17d5df2a 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -40,7 +40,7 @@ pub trait Key: Sized { None } - fn ty_adt_id(&self) -> Option { + fn ty_def_id(&self) -> Option { None } } @@ -406,9 +406,10 @@ impl<'tcx> Key for Ty<'tcx> { DUMMY_SP } - fn ty_adt_id(&self) -> Option { - match self.kind() { + fn ty_def_id(&self) -> Option { + match *self.kind() { ty::Adt(adt, _) => Some(adt.did()), + ty::Coroutine(def_id, ..) => Some(def_id), _ => None, } } @@ -452,6 +453,10 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.value.default_span(tcx) } + + fn ty_def_id(&self) -> Option { + self.value.ty_def_id() + } } impl Key for Symbol { @@ -550,7 +555,7 @@ impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) { DUMMY_SP } - fn ty_adt_id(&self) -> Option { + fn ty_def_id(&self) -> Option { match self.1.value.kind() { ty::Adt(adt, _) => Some(adt.did()), _ => None, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7d5abaceb20a..0e3b9984423f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1387,6 +1387,8 @@ rustc_queries! { ) -> Result, &'tcx ty::layout::LayoutError<'tcx>> { depth_limit desc { "computing layout of `{}`", key.value } + // we emit our own error during query cycle handling + cycle_delay_bug } /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 8abf4a9e341d..31db4ba62fb4 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -22,7 +22,8 @@ use rustc_span::hygiene::{ }; use rustc_span::source_map::SourceMap; use rustc_span::{ - BytePos, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span, StableSourceFileId, + BytePos, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span, SpanDecoder, SpanEncoder, + StableSourceFileId, }; use rustc_span::{CachingSourceMapView, Symbol}; use std::collections::hash_map::Entry; @@ -582,10 +583,10 @@ impl<'a, 'tcx> Decodable> for Vec { } } -impl<'a, 'tcx> Decodable> for SyntaxContext { - fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self { - let syntax_contexts = decoder.syntax_contexts; - rustc_span::hygiene::decode_syntax_context(decoder, decoder.hygiene_context, |this, id| { +impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { + fn decode_syntax_context(&mut self) -> SyntaxContext { + let syntax_contexts = self.syntax_contexts; + rustc_span::hygiene::decode_syntax_context(self, self.hygiene_context, |this, id| { // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing. // We look up the position of the associated `SyntaxData` and decode it. let pos = syntax_contexts.get(&id).unwrap(); @@ -595,11 +596,9 @@ impl<'a, 'tcx> Decodable> for SyntaxContext { }) }) } -} -impl<'a, 'tcx> Decodable> for ExpnId { - fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self { - let hash = ExpnHash::decode(decoder); + fn decode_expn_id(&mut self) -> ExpnId { + let hash = ExpnHash::decode(self); if hash.is_root() { return ExpnId::root(); } @@ -608,23 +607,23 @@ impl<'a, 'tcx> Decodable> for ExpnId { return expn_id; } - let krate = decoder.tcx.stable_crate_id_to_crate_num(hash.stable_crate_id()); + let krate = self.tcx.stable_crate_id_to_crate_num(hash.stable_crate_id()); let expn_id = if krate == LOCAL_CRATE { // We look up the position of the associated `ExpnData` and decode it. - let pos = decoder + let pos = self .expn_data .get(&hash) - .unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, decoder.expn_data)); + .unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, self.expn_data)); - let data: ExpnData = decoder - .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA)); + let data: ExpnData = + self.with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA)); let expn_id = rustc_span::hygiene::register_local_expn_id(data, hash); #[cfg(debug_assertions)] { use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; - let local_hash = decoder.tcx.with_stable_hashing_context(|mut hcx| { + let local_hash = self.tcx.with_stable_hashing_context(|mut hcx| { let mut hasher = StableHasher::new(); expn_id.expn_data().hash_stable(&mut hcx, &mut hasher); hasher.finish() @@ -634,9 +633,9 @@ impl<'a, 'tcx> Decodable> for ExpnId { expn_id } else { - let index_guess = decoder.foreign_expn_data[&hash]; - decoder.tcx.cstore_untracked().expn_hash_to_expn_id( - decoder.tcx.sess, + let index_guess = self.foreign_expn_data[&hash]; + self.tcx.cstore_untracked().expn_hash_to_expn_id( + self.tcx.sess, krate, index_guess, hash, @@ -646,21 +645,19 @@ impl<'a, 'tcx> Decodable> for ExpnId { debug_assert_eq!(expn_id.krate, krate); expn_id } -} -impl<'a, 'tcx> Decodable> for Span { - fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self { - let ctxt = SyntaxContext::decode(decoder); - let parent = Option::::decode(decoder); - let tag: u8 = Decodable::decode(decoder); + fn decode_span(&mut self) -> Span { + let ctxt = SyntaxContext::decode(self); + let parent = Option::::decode(self); + let tag: u8 = Decodable::decode(self); if tag == TAG_PARTIAL_SPAN { return Span::new(BytePos(0), BytePos(0), ctxt, parent); } else if tag == TAG_RELATIVE_SPAN { - let dlo = u32::decode(decoder); - let dto = u32::decode(decoder); + let dlo = u32::decode(self); + let dto = u32::decode(self); - let enclosing = decoder.tcx.source_span_untracked(parent.unwrap()).data_untracked(); + let enclosing = self.tcx.source_span_untracked(parent.unwrap()).data_untracked(); let span = Span::new( enclosing.lo + BytePos::from_u32(dlo), enclosing.lo + BytePos::from_u32(dto), @@ -673,87 +670,81 @@ impl<'a, 'tcx> Decodable> for Span { debug_assert_eq!(tag, TAG_FULL_SPAN); } - let file_lo_index = SourceFileIndex::decode(decoder); - let line_lo = usize::decode(decoder); - let col_lo = RelativeBytePos::decode(decoder); - let len = BytePos::decode(decoder); + let file_lo_index = SourceFileIndex::decode(self); + let line_lo = usize::decode(self); + let col_lo = RelativeBytePos::decode(self); + let len = BytePos::decode(self); - let file_lo = decoder.file_index_to_file(file_lo_index); + let file_lo = self.file_index_to_file(file_lo_index); let lo = file_lo.lines()[line_lo - 1] + col_lo; let lo = file_lo.absolute_position(lo); let hi = lo + len; Span::new(lo, hi, ctxt, parent) } -} -// copy&paste impl from rustc_metadata -impl<'a, 'tcx> Decodable> for Symbol { + // copy&paste impl from rustc_metadata #[inline] - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { - let tag = d.read_u8(); + fn decode_symbol(&mut self) -> Symbol { + let tag = self.read_u8(); match tag { SYMBOL_STR => { - let s = d.read_str(); + let s = self.read_str(); Symbol::intern(s) } SYMBOL_OFFSET => { // read str offset - let pos = d.read_usize(); + let pos = self.read_usize(); // move to str offset and read - d.opaque.with_position(pos, |d| { + self.opaque.with_position(pos, |d| { let s = d.read_str(); Symbol::intern(s) }) } SYMBOL_PREINTERNED => { - let symbol_index = d.read_u32(); + let symbol_index = self.read_u32(); Symbol::new_from_decoded(symbol_index) } _ => unreachable!(), } } -} -impl<'a, 'tcx> Decodable> for CrateNum { - #[inline] - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { - let stable_id = StableCrateId::decode(d); - let cnum = d.tcx.stable_crate_id_to_crate_num(stable_id); + fn decode_crate_num(&mut self) -> CrateNum { + let stable_id = StableCrateId::decode(self); + let cnum = self.tcx.stable_crate_id_to_crate_num(stable_id); cnum } -} -// This impl makes sure that we get a runtime error when we try decode a -// `DefIndex` that is not contained in a `DefId`. Such a case would be problematic -// because we would not know how to transform the `DefIndex` to the current -// context. -impl<'a, 'tcx> Decodable> for DefIndex { - fn decode(_d: &mut CacheDecoder<'a, 'tcx>) -> DefIndex { + // This impl makes sure that we get a runtime error when we try decode a + // `DefIndex` that is not contained in a `DefId`. Such a case would be problematic + // because we would not know how to transform the `DefIndex` to the current + // context. + fn decode_def_index(&mut self) -> DefIndex { panic!("trying to decode `DefIndex` outside the context of a `DefId`") } -} -// Both the `CrateNum` and the `DefIndex` of a `DefId` can change in between two -// compilation sessions. We use the `DefPathHash`, which is stable across -// sessions, to map the old `DefId` to the new one. -impl<'a, 'tcx> Decodable> for DefId { - #[inline] - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { + // Both the `CrateNum` and the `DefIndex` of a `DefId` can change in between two + // compilation sessions. We use the `DefPathHash`, which is stable across + // sessions, to map the old `DefId` to the new one. + fn decode_def_id(&mut self) -> DefId { // Load the `DefPathHash` which is was we encoded the `DefId` as. - let def_path_hash = DefPathHash::decode(d); + let def_path_hash = DefPathHash::decode(self); // Using the `DefPathHash`, we can lookup the new `DefId`. // Subtle: We only encode a `DefId` as part of a query result. // If we get to this point, then all of the query inputs were green, // which means that the definition with this hash is guaranteed to // still exist in the current compilation session. - d.tcx.def_path_hash_to_def_id(def_path_hash, &mut || { + self.tcx.def_path_hash_to_def_id(def_path_hash, &mut || { panic!("Failed to convert DefPathHash {def_path_hash:?}") }) } + + fn decode_attr_id(&mut self) -> rustc_span::AttrId { + panic!("cannot decode `AttrId` with `CacheDecoder`"); + } } impl<'a, 'tcx> Decodable> for &'tcx UnordSet { @@ -859,87 +850,93 @@ impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { } } -impl<'a, 'tcx> Encodable> for SyntaxContext { - fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { - rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_context, s); +impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> { + fn encode_syntax_context(&mut self, syntax_context: SyntaxContext) { + rustc_span::hygiene::raw_encode_syntax_context(syntax_context, self.hygiene_context, self); } -} -impl<'a, 'tcx> Encodable> for ExpnId { - fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { - s.hygiene_context.schedule_expn_data_for_encoding(*self); - self.expn_hash().encode(s); + fn encode_expn_id(&mut self, expn_id: ExpnId) { + self.hygiene_context.schedule_expn_data_for_encoding(expn_id); + expn_id.expn_hash().encode(self); } -} -impl<'a, 'tcx> Encodable> for Span { - fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { - let span_data = self.data_untracked(); - span_data.ctxt.encode(s); - span_data.parent.encode(s); + fn encode_span(&mut self, span: Span) { + let span_data = span.data_untracked(); + span_data.ctxt.encode(self); + span_data.parent.encode(self); if span_data.is_dummy() { - return TAG_PARTIAL_SPAN.encode(s); + return TAG_PARTIAL_SPAN.encode(self); } if let Some(parent) = span_data.parent { - let enclosing = s.tcx.source_span_untracked(parent).data_untracked(); + let enclosing = self.tcx.source_span_untracked(parent).data_untracked(); if enclosing.contains(span_data) { - TAG_RELATIVE_SPAN.encode(s); - (span_data.lo - enclosing.lo).to_u32().encode(s); - (span_data.hi - enclosing.lo).to_u32().encode(s); + TAG_RELATIVE_SPAN.encode(self); + (span_data.lo - enclosing.lo).to_u32().encode(self); + (span_data.hi - enclosing.lo).to_u32().encode(self); return; } } - let pos = s.source_map.byte_pos_to_line_and_col(span_data.lo); + let pos = self.source_map.byte_pos_to_line_and_col(span_data.lo); let partial_span = match &pos { Some((file_lo, _, _)) => !file_lo.contains(span_data.hi), None => true, }; if partial_span { - return TAG_PARTIAL_SPAN.encode(s); + return TAG_PARTIAL_SPAN.encode(self); } let (file_lo, line_lo, col_lo) = pos.unwrap(); let len = span_data.hi - span_data.lo; - let source_file_index = s.source_file_index(file_lo); + let source_file_index = self.source_file_index(file_lo); - TAG_FULL_SPAN.encode(s); - source_file_index.encode(s); - line_lo.encode(s); - col_lo.encode(s); - len.encode(s); + TAG_FULL_SPAN.encode(self); + source_file_index.encode(self); + line_lo.encode(self); + col_lo.encode(self); + len.encode(self); } -} -// copy&paste impl from rustc_metadata -impl<'a, 'tcx> Encodable> for Symbol { - fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { + // copy&paste impl from rustc_metadata + fn encode_symbol(&mut self, symbol: Symbol) { // if symbol preinterned, emit tag and symbol index - if self.is_preinterned() { - s.encoder.emit_u8(SYMBOL_PREINTERNED); - s.encoder.emit_u32(self.as_u32()); + if symbol.is_preinterned() { + self.encoder.emit_u8(SYMBOL_PREINTERNED); + self.encoder.emit_u32(symbol.as_u32()); } else { // otherwise write it as string or as offset to it - match s.symbol_table.entry(*self) { + match self.symbol_table.entry(symbol) { Entry::Vacant(o) => { - s.encoder.emit_u8(SYMBOL_STR); - let pos = s.encoder.position(); + self.encoder.emit_u8(SYMBOL_STR); + let pos = self.encoder.position(); o.insert(pos); - s.emit_str(self.as_str()); + self.emit_str(symbol.as_str()); } Entry::Occupied(o) => { let x = *o.get(); - s.emit_u8(SYMBOL_OFFSET); - s.emit_usize(x); + self.emit_u8(SYMBOL_OFFSET); + self.emit_usize(x); } } } } + + fn encode_crate_num(&mut self, crate_num: CrateNum) { + self.tcx.stable_crate_id(crate_num).encode(self); + } + + fn encode_def_id(&mut self, def_id: DefId) { + self.tcx.def_path_hash(def_id).encode(self); + } + + fn encode_def_index(&mut self, _def_index: DefIndex) { + bug!("encoding `DefIndex` without context"); + } } impl<'a, 'tcx> TyEncoder for CacheEncoder<'a, 'tcx> { @@ -966,26 +963,6 @@ impl<'a, 'tcx> TyEncoder for CacheEncoder<'a, 'tcx> { } } -impl<'a, 'tcx> Encodable> for CrateNum { - #[inline] - fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { - s.tcx.stable_crate_id(*self).encode(s); - } -} - -impl<'a, 'tcx> Encodable> for DefId { - #[inline] - fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { - s.tcx.def_path_hash(*self).encode(s); - } -} - -impl<'a, 'tcx> Encodable> for DefIndex { - fn encode(&self, _: &mut CacheEncoder<'a, 'tcx>) { - bug!("encoding `DefIndex` without context"); - } -} - macro_rules! encoder_methods { ($($name:ident($ty:ty);)*) => { #[inline] diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index d2ff1e3c0944..414d4c8d9496 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -53,7 +53,7 @@ pub struct DynamicQuery<'tcx, C: QueryCache> { fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool, pub hash_result: HashResult, pub value_from_cycle_error: - fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> C::Value, + fn(tcx: TyCtxt<'tcx>, cycle_error: &CycleError, guar: ErrorGuaranteed) -> C::Value, pub format_value: fn(&C::Value) -> String, } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 2b5983314eec..b4b8387c262b 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -86,8 +86,6 @@ macro_rules! thir_with_elements { } } -pub const UPVAR_ENV_PARAM: ParamId = ParamId::from_u32(0); - thir_with_elements! { body_type: BodyTy<'tcx>, diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 2ac3cddfa15a..dd41cb5a61f4 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -293,12 +293,16 @@ impl<'tcx> InstanceDef<'tcx> { fn fmt_instance( f: &mut fmt::Formatter<'_>, instance: &Instance<'_>, - type_length: rustc_session::Limit, + type_length: Option, ) -> fmt::Result { ty::tls::with(|tcx| { let args = tcx.lift(instance.args).expect("could not lift for printing"); - let mut cx = FmtPrinter::new_with_limit(tcx, Namespace::ValueNS, type_length); + let mut cx = if let Some(type_length) = type_length { + FmtPrinter::new_with_limit(tcx, Namespace::ValueNS, type_length) + } else { + FmtPrinter::new(tcx, Namespace::ValueNS) + }; cx.print_def_path(instance.def_id(), args)?; let s = cx.into_buffer(); f.write_str(&s) @@ -324,13 +328,13 @@ pub struct ShortInstance<'a, 'tcx>(pub &'a Instance<'tcx>, pub usize); impl<'a, 'tcx> fmt::Display for ShortInstance<'a, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_instance(f, self.0, rustc_session::Limit(self.1)) + fmt_instance(f, self.0, Some(rustc_session::Limit(self.1))) } } impl<'tcx> fmt::Display for Instance<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ty::tls::with(|tcx| fmt_instance(f, self, tcx.type_length_limit())) + fmt_instance(f, self, None) } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 4af82f124719..9e8d7c2ef3ec 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -51,7 +51,7 @@ use rustc_session::lint::LintBuffer; pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{ExpnId, ExpnKind, Span}; +use rustc_span::{hygiene, ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx}; @@ -2518,21 +2518,21 @@ impl<'tcx> TyCtxt<'tcx> { (ident, scope) } - /// Returns `true` if the debuginfo for `span` should be collapsed to the outermost expansion - /// site. Only applies when `Span` is the result of macro expansion. + /// Returns corrected span if the debuginfo for `span` should be collapsed to the outermost + /// expansion site (with collapse_debuginfo attribute if the corresponding feature enabled). + /// Only applies when `Span` is the result of macro expansion. /// /// - If the `collapse_debuginfo` feature is enabled then debuginfo is not collapsed by default - /// and only when a macro definition is annotated with `#[collapse_debuginfo]`. + /// and only when a (some enclosing) macro definition is annotated with `#[collapse_debuginfo]`. /// - If `collapse_debuginfo` is not enabled, then debuginfo is collapsed by default. /// /// When `-Zdebug-macros` is provided then debuginfo will never be collapsed. - pub fn should_collapse_debuginfo(self, span: Span) -> bool { - !self.sess.opts.unstable_opts.debug_macros - && if self.features().collapse_debuginfo { - span.in_macro_expansion_with_collapse_debuginfo() - } else { - span.from_expansion() - } + pub fn collapsed_debuginfo(self, span: Span, upto: Span) -> Span { + if self.sess.opts.unstable_opts.debug_macros || !span.from_expansion() { + return span; + } + let collapse_debuginfo_enabled = self.features().collapse_debuginfo; + hygiene::walk_chain_collapsed(span, upto, collapse_debuginfo_enabled) } #[inline] diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index fc4d4c9a3d26..d9bcd8d3ae72 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -132,7 +132,7 @@ impl<'tcx> TypeFolder> for ReverseMapper<'tcx> { .tcx .dcx() .struct_span_err(self.span, "non-defining opaque type use in defining scope") - .span_label( + .span_label_mv( self.span, format!( "lifetime `{r}` is part of concrete type but not used in \ diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 3a6fbaec9fd4..7285cdb830e3 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1,7 +1,7 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::query::Providers; +use crate::query::{IntoQueryParam, Providers}; use crate::ty::layout::IntegerExt; use crate::ty::{ self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, @@ -369,7 +369,7 @@ impl<'tcx> TyCtxt<'tcx> { if let Some((old_item_id, _)) = dtor_candidate { self.dcx() .struct_span_err(self.def_span(item_id), "multiple drop impls found") - .span_note(self.def_span(old_item_id), "other impl here") + .span_note_mv(self.def_span(old_item_id), "other impl here") .delay_as_bug(); } @@ -702,6 +702,7 @@ impl<'tcx> TyCtxt<'tcx> { self, def_id: DefId, args: GenericArgsRef<'tcx>, + inspect_coroutine_fields: InspectCoroutineFields, ) -> Result, Ty<'tcx>> { let mut visitor = OpaqueTypeExpander { seen_opaque_tys: FxHashSet::default(), @@ -712,6 +713,7 @@ impl<'tcx> TyCtxt<'tcx> { check_recursion: true, expand_coroutines: true, tcx: self, + inspect_coroutine_fields, }; let expanded_type = visitor.expand_opaque_ty(def_id, args).unwrap(); @@ -729,16 +731,43 @@ impl<'tcx> TyCtxt<'tcx> { DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "method", DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { match coroutine_kind { - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => { - "async closure" - } - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => { - "async gen closure" - } + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Fn, + ) => "async fn", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Block, + ) => "async block", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Closure, + ) => "async closure", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Fn, + ) => "async gen fn", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Block, + ) => "async gen block", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Closure, + ) => "async gen closure", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Fn, + ) => "gen fn", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Block, + ) => "gen block", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Closure, + ) => "gen closure", hir::CoroutineKind::Coroutine(_) => "coroutine", - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => { - "gen closure" - } } } _ => def_kind.descr(def_id), @@ -786,6 +815,13 @@ impl<'tcx> TyCtxt<'tcx> { || self.extern_crate(key.as_def_id()).is_some_and(|e| e.is_direct()) } + /// Whether the item has a host effect param. This is different from `TyCtxt::is_const`, + /// because the item must also be "maybe const", and the crate where the item is + /// defined must also have the effects feature enabled. + pub fn has_host_param(self, def_id: impl IntoQueryParam) -> bool { + self.generics_of(def_id).host_effect_index.is_some() + } + pub fn expected_host_effect_param_for_body(self, def_id: impl Into) -> ty::Const<'tcx> { let def_id = def_id.into(); // FIXME(effects): This is suspicious and should probably not be done, @@ -858,6 +894,13 @@ struct OpaqueTypeExpander<'tcx> { /// recursion, and 'false' otherwise to avoid unnecessary work. check_recursion: bool, tcx: TyCtxt<'tcx>, + inspect_coroutine_fields: InspectCoroutineFields, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum InspectCoroutineFields { + No, + Yes, } impl<'tcx> OpaqueTypeExpander<'tcx> { @@ -899,9 +942,11 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { let expanded_ty = match self.expanded_cache.get(&(def_id, args)) { Some(expanded_ty) => *expanded_ty, None => { - for bty in self.tcx.coroutine_hidden_types(def_id) { - let hidden_ty = bty.instantiate(self.tcx, args); - self.fold_ty(hidden_ty); + if matches!(self.inspect_coroutine_fields, InspectCoroutineFields::Yes) { + for bty in self.tcx.coroutine_hidden_types(def_id) { + let hidden_ty = bty.instantiate(self.tcx, args); + self.fold_ty(hidden_ty); + } } let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args); self.expanded_cache.insert((def_id, args), expanded_ty); @@ -1479,6 +1524,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>( check_recursion: false, expand_coroutines: false, tcx, + inspect_coroutine_fields: InspectCoroutineFields::No, }; val.fold_with(&mut visitor) } diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index b4e45ad56856..27d04dbe3314 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -6,15 +6,17 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::Representability; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_query_system::query::QueryInfo; +use rustc_query_system::query::{report_cycle, CycleError}; use rustc_query_system::Value; use rustc_span::def_id::LocalDefId; use rustc_span::{ErrorGuaranteed, Span}; +use std::collections::VecDeque; use std::fmt::Write; +use std::ops::ControlFlow; impl<'tcx> Value> for Ty<'_> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self { + fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self { // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { std::mem::transmute::, Ty<'_>>(Ty::new_error(tcx, guar)) } @@ -22,13 +24,13 @@ impl<'tcx> Value> for Ty<'_> { } impl<'tcx> Value> for Result>, CyclePlaceholder> { - fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self { + fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self { Err(CyclePlaceholder(guar)) } } impl<'tcx> Value> for ty::SymbolName<'_> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], _guar: ErrorGuaranteed) -> Self { + fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, _guar: ErrorGuaranteed) -> Self { // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { @@ -40,10 +42,14 @@ impl<'tcx> Value> for ty::SymbolName<'_> { } impl<'tcx> Value> for ty::Binder<'_, ty::FnSig<'_>> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo], guar: ErrorGuaranteed) -> Self { + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle_error: &CycleError, + guar: ErrorGuaranteed, + ) -> Self { let err = Ty::new_error(tcx, guar); - let arity = if let Some(frame) = stack.get(0) + let arity = if let Some(frame) = cycle_error.cycle.get(0) && frame.query.dep_kind == dep_kinds::fn_sig && let Some(def_id) = frame.query.def_id && let Some(node) = tcx.hir().get_if_local(def_id) @@ -70,10 +76,14 @@ impl<'tcx> Value> for ty::Binder<'_, ty::FnSig<'_>> { } impl<'tcx> Value> for Representability { - fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self { + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle_error: &CycleError, + _guar: ErrorGuaranteed, + ) -> Self { let mut item_and_field_ids = Vec::new(); let mut representable_ids = FxHashSet::default(); - for info in cycle { + for info in &cycle_error.cycle { if info.query.dep_kind == dep_kinds::representability && let Some(field_id) = info.query.def_id && let Some(field_id) = field_id.as_local() @@ -87,9 +97,9 @@ impl<'tcx> Value> for Representability { item_and_field_ids.push((item_id.expect_local(), field_id)); } } - for info in cycle { + for info in &cycle_error.cycle { if info.query.dep_kind == dep_kinds::representability_adt_ty - && let Some(def_id) = info.query.ty_adt_id + && let Some(def_id) = info.query.ty_def_id && let Some(def_id) = def_id.as_local() && !item_and_field_ids.iter().any(|&(id, _)| id == def_id) { @@ -102,19 +112,128 @@ impl<'tcx> Value> for Representability { } impl<'tcx> Value> for ty::EarlyBinder> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self { - ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle, guar)) + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle_error: &CycleError, + guar: ErrorGuaranteed, + ) -> Self { + ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle_error, guar)) } } impl<'tcx> Value> for ty::EarlyBinder>> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self { - ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle, guar)) + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle_error: &CycleError, + guar: ErrorGuaranteed, + ) -> Self { + ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle_error, guar)) } } +// Take a cycle of `Q` and try `try_cycle` on every permutation, falling back to `otherwise`. +fn search_for_cycle_permutation( + cycle: &[Q], + try_cycle: impl Fn(&mut VecDeque<&Q>) -> ControlFlow, + otherwise: impl FnOnce() -> T, +) -> T { + let mut cycle: VecDeque<_> = cycle.iter().collect(); + for _ in 0..cycle.len() { + match try_cycle(&mut cycle) { + ControlFlow::Continue(_) => { + cycle.rotate_left(1); + } + ControlFlow::Break(t) => return t, + } + } + + otherwise() +} + impl<'tcx, T> Value> for Result> { - fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self { + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle_error: &CycleError, + _guar: ErrorGuaranteed, + ) -> Self { + let diag = search_for_cycle_permutation( + &cycle_error.cycle, + |cycle| { + if cycle[0].query.dep_kind == dep_kinds::layout_of + && let Some(def_id) = cycle[0].query.ty_def_id + && let Some(def_id) = def_id.as_local() + && let def_kind = tcx.def_kind(def_id) + && matches!(def_kind, DefKind::Closure) + && let Some(coroutine_kind) = tcx.coroutine_kind(def_id) + { + // FIXME: `def_span` for an fn-like coroutine will point to the fn's body + // due to interactions between the desugaring into a closure expr and the + // def_span code. I'm not motivated to fix it, because I tried and it was + // not working, so just hack around it by grabbing the parent fn's span. + let span = if coroutine_kind.is_fn_like() { + tcx.def_span(tcx.local_parent(def_id)) + } else { + tcx.def_span(def_id) + }; + let mut diag = struct_span_err!( + tcx.sess.dcx(), + span, + E0733, + "recursion in {} {} requires boxing", + tcx.def_kind_descr_article(def_kind, def_id.to_def_id()), + tcx.def_kind_descr(def_kind, def_id.to_def_id()), + ); + for (i, frame) in cycle.iter().enumerate() { + if frame.query.dep_kind != dep_kinds::layout_of { + continue; + } + let Some(frame_def_id) = frame.query.ty_def_id else { + continue; + }; + let Some(frame_coroutine_kind) = tcx.coroutine_kind(frame_def_id) else { + continue; + }; + let frame_span = + frame.query.default_span(cycle[(i + 1) % cycle.len()].span); + if frame_span.is_dummy() { + continue; + } + if i == 0 { + diag.span_label(frame_span, "recursive call here"); + } else { + let coroutine_span: Span = if frame_coroutine_kind.is_fn_like() { + tcx.def_span(tcx.parent(frame_def_id)) + } else { + tcx.def_span(frame_def_id) + }; + let mut multispan = MultiSpan::from_span(coroutine_span); + multispan + .push_span_label(frame_span, "...leading to this recursive call"); + diag.span_note( + multispan, + format!("which leads to this {}", tcx.def_descr(frame_def_id)), + ); + } + } + // FIXME: We could report a structured suggestion if we had + // enough info here... Maybe we can use a hacky HIR walker. + if matches!( + coroutine_kind, + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) + ) { + diag.note("a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future"); + } + + ControlFlow::Break(diag) + } else { + ControlFlow::Continue(()) + } + }, + || report_cycle(tcx.sess, cycle_error), + ); + + let guar = diag.emit(); + // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really, // tcx.arena.alloc is pretty much equal to leaking). @@ -190,7 +309,7 @@ pub fn recursive_type_error( } s }; - let mut err = struct_span_err!( + struct_span_err!( tcx.dcx(), err_span, E0072, @@ -198,13 +317,13 @@ pub fn recursive_type_error( pluralize!(cycle_len), items_list, pluralize!("has", cycle_len), - ); - err.multipart_suggestion( + ) + .multipart_suggestion_mv( "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle", suggestion, Applicability::HasPlaceholders, - ); - err.emit(); + ) + .emit(); } fn find_item_ty_spans( diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index c4cade839478..b8d08319422d 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -9,7 +9,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{CoroutineKind, Node}; +use rustc_hir::Node; use rustc_index::bit_set::GrowableBitSet; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; @@ -177,7 +177,7 @@ struct Builder<'a, 'tcx> { check_overflow: bool, fn_span: Span, arg_count: usize, - coroutine_kind: Option, + coroutine: Option>>, /// The current set of scopes, updated as we traverse; /// see the `scope` module for more details. @@ -458,7 +458,6 @@ fn construct_fn<'tcx>( ) -> Body<'tcx> { let span = tcx.def_span(fn_def); let fn_id = tcx.local_def_id_to_hir_id(fn_def); - let coroutine_kind = tcx.coroutine_kind(fn_def); // The representation of thir for `-Zunpretty=thir-tree` relies on // the entry expression being the last element of `thir.exprs`. @@ -488,17 +487,15 @@ fn construct_fn<'tcx>( let arguments = &thir.params; - let (resume_ty, yield_ty, return_ty) = if coroutine_kind.is_some() { - let coroutine_ty = arguments[thir::UPVAR_ENV_PARAM].ty; - let coroutine_sig = match coroutine_ty.kind() { - ty::Coroutine(_, gen_args, ..) => gen_args.as_coroutine().sig(), - _ => { - span_bug!(span, "coroutine w/o coroutine type: {:?}", coroutine_ty) - } - }; - (Some(coroutine_sig.resume_ty), Some(coroutine_sig.yield_ty), coroutine_sig.return_ty) - } else { - (None, None, fn_sig.output()) + let return_ty = fn_sig.output(); + let coroutine = match tcx.type_of(fn_def).instantiate_identity().kind() { + ty::Coroutine(_, args) => Some(Box::new(CoroutineInfo::initial( + tcx.coroutine_kind(fn_def).unwrap(), + args.as_coroutine().yield_ty(), + args.as_coroutine().resume_ty(), + ))), + ty::Closure(..) | ty::FnDef(..) => None, + ty => span_bug!(span_with_body, "unexpected type of body: {ty:?}"), }; if let Some(custom_mir_attr) = @@ -529,7 +526,7 @@ fn construct_fn<'tcx>( safety, return_ty, return_ty_span, - coroutine_kind, + coroutine, ); let call_site_scope = @@ -563,11 +560,6 @@ fn construct_fn<'tcx>( None }; - if coroutine_kind.is_some() { - body.coroutine.as_mut().unwrap().yield_ty = yield_ty; - body.coroutine.as_mut().unwrap().resume_ty = resume_ty; - } - body } @@ -632,47 +624,62 @@ fn construct_const<'a, 'tcx>( fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) -> Body<'_> { let span = tcx.def_span(def_id); let hir_id = tcx.local_def_id_to_hir_id(def_id); - let coroutine_kind = tcx.coroutine_kind(def_id); - let (inputs, output, resume_ty, yield_ty) = match tcx.def_kind(def_id) { + let (inputs, output, coroutine) = match tcx.def_kind(def_id) { DefKind::Const | DefKind::AssocConst | DefKind::AnonConst | DefKind::InlineConst - | DefKind::Static(_) => (vec![], tcx.type_of(def_id).instantiate_identity(), None, None), + | DefKind::Static(_) => (vec![], tcx.type_of(def_id).instantiate_identity(), None), DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => { let sig = tcx.liberate_late_bound_regions( def_id.to_def_id(), tcx.fn_sig(def_id).instantiate_identity(), ); - (sig.inputs().to_vec(), sig.output(), None, None) - } - DefKind::Closure if coroutine_kind.is_some() => { - let coroutine_ty = tcx.type_of(def_id).instantiate_identity(); - let ty::Coroutine(_, args) = coroutine_ty.kind() else { - bug!("expected type of coroutine-like closure to be a coroutine") - }; - let args = args.as_coroutine(); - let resume_ty = args.resume_ty(); - let yield_ty = args.yield_ty(); - let return_ty = args.return_ty(); - (vec![coroutine_ty, args.resume_ty()], return_ty, Some(resume_ty), Some(yield_ty)) + (sig.inputs().to_vec(), sig.output(), None) } DefKind::Closure => { let closure_ty = tcx.type_of(def_id).instantiate_identity(); - let ty::Closure(_, args) = closure_ty.kind() else { - bug!("expected type of closure to be a closure") - }; - let args = args.as_closure(); - let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), args.sig()); - let self_ty = match args.kind() { - ty::ClosureKind::Fn => Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, closure_ty), - ty::ClosureKind::FnMut => Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, closure_ty), - ty::ClosureKind::FnOnce => closure_ty, - }; - ([self_ty].into_iter().chain(sig.inputs().to_vec()).collect(), sig.output(), None, None) + match closure_ty.kind() { + ty::Closure(_, args) => { + let args = args.as_closure(); + let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), args.sig()); + let self_ty = match args.kind() { + ty::ClosureKind::Fn => { + Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, closure_ty) + } + ty::ClosureKind::FnMut => { + Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, closure_ty) + } + ty::ClosureKind::FnOnce => closure_ty, + }; + ( + [self_ty].into_iter().chain(sig.inputs().to_vec()).collect(), + sig.output(), + None, + ) + } + ty::Coroutine(_, args) => { + let args = args.as_coroutine(); + let resume_ty = args.resume_ty(); + let yield_ty = args.yield_ty(); + let return_ty = args.return_ty(); + ( + vec![closure_ty, args.resume_ty()], + return_ty, + Some(Box::new(CoroutineInfo::initial( + tcx.coroutine_kind(def_id).unwrap(), + yield_ty, + resume_ty, + ))), + ) + } + _ => { + span_bug!(span, "expected type of closure body to be a closure or coroutine"); + } + } } - dk => bug!("{:?} is not a body: {:?}", def_id, dk), + dk => span_bug!(span, "{:?} is not a body: {:?}", def_id, dk), }; let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }; @@ -696,7 +703,7 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); - let mut body = Body::new( + Body::new( MirSource::item(def_id.to_def_id()), cfg.basic_blocks, source_scopes, @@ -705,16 +712,9 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - inputs.len(), vec![], span, - coroutine_kind, + coroutine, Some(guar), - ); - - body.coroutine.as_mut().map(|gen| { - gen.yield_ty = yield_ty; - gen.resume_ty = resume_ty; - }); - - body + ) } impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -728,7 +728,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { safety: Safety, return_ty: Ty<'tcx>, return_span: Span, - coroutine_kind: Option, + coroutine: Option>>, ) -> Builder<'a, 'tcx> { let tcx = infcx.tcx; let attrs = tcx.hir().attrs(hir_id); @@ -759,7 +759,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { cfg: CFG { basic_blocks: IndexVec::new() }, fn_span: span, arg_count, - coroutine_kind, + coroutine, scopes: scope::Scopes::new(), block_context: BlockContext::new(), source_scopes: IndexVec::new(), @@ -803,7 +803,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.arg_count, self.var_debug_info, self.fn_span, - self.coroutine_kind, + self.coroutine, None, ) } diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 1a700ac7342e..48b237f3ae62 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -706,7 +706,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // If we are emitting a `drop` statement, we need to have the cached // diverge cleanup pads ready in case that drop panics. let needs_cleanup = self.scopes.scopes.last().is_some_and(|scope| scope.needs_cleanup()); - let is_coroutine = self.coroutine_kind.is_some(); + let is_coroutine = self.coroutine.is_some(); let unwind_to = if needs_cleanup { self.diverge_cleanup() } else { DropIdx::MAX }; let scope = self.scopes.scopes.last().expect("leave_top_scope called with no scopes"); @@ -960,7 +960,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // path, we only need to invalidate the cache for drops that happen on // the unwind or coroutine drop paths. This means that for // non-coroutines we don't need to invalidate caches for `DropKind::Storage`. - let invalidate_caches = needs_drop || self.coroutine_kind.is_some(); + let invalidate_caches = needs_drop || self.coroutine.is_some(); for scope in self.scopes.scopes.iter_mut().rev() { if invalidate_caches { scope.invalidate_cache(); @@ -1073,7 +1073,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return cached_drop; } - let is_coroutine = self.coroutine_kind.is_some(); + let is_coroutine = self.coroutine.is_some(); for scope in &mut self.scopes.scopes[uncached_scope..=target] { for drop in &scope.drops { if is_coroutine || drop.kind == DropKind::Value { @@ -1318,7 +1318,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { blocks[ROOT_NODE] = continue_block; drops.build_mir::(&mut self.cfg, &mut blocks); - let is_coroutine = self.coroutine_kind.is_some(); + let is_coroutine = self.coroutine.is_some(); // Link the exit drop tree to unwind drop tree. if drops.drops.iter().any(|(drop, _)| drop.kind == DropKind::Value) { @@ -1355,7 +1355,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { /// Build the unwind and coroutine drop trees. pub(crate) fn build_drop_trees(&mut self) { - if self.coroutine_kind.is_some() { + if self.coroutine.is_some() { self.build_coroutine_drop_trees(); } else { Self::build_unwind_tree( diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs index 3884346076ee..cb5b66b314d6 100644 --- a/compiler/rustc_mir_transform/src/const_goto.rs +++ b/compiler/rustc_mir_transform/src/const_goto.rs @@ -51,7 +51,7 @@ impl<'tcx> MirPass<'tcx> for ConstGoto { // if we applied optimizations, we potentially have some cfg to cleanup to // make it easier for further passes if should_simplify { - simplify_cfg(tcx, body); + simplify_cfg(body); simplify_locals(body, tcx); } } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 99eecb567f27..d0bbca08a406 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -670,6 +670,8 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { // This loop can get very hot for some bodies: it check each local in each bb. // To avoid this quadratic behaviour, we only clear the locals that were modified inside // the current block. + // The order in which we remove consts does not matter. + #[allow(rustc::potential_query_instability)] for local in written_only_inside_own_block_locals.drain() { debug_assert_eq!( self.ecx.machine.can_const_prop[local], diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 33e305497b50..379e96e263c2 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -942,6 +942,7 @@ fn compute_storage_conflicts<'mir, 'tcx>( body, saved_locals: saved_locals, local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()), + eligible_storage_live: BitSet::new_empty(body.local_decls.len()), }; requires_storage.visit_reachable_with(body, &mut visitor); @@ -978,6 +979,8 @@ struct StorageConflictVisitor<'mir, 'tcx, 's> { // FIXME(tmandry): Consider using sparse bitsets here once we have good // benchmarks for coroutines. local_conflicts: BitMatrix, + // We keep this bitset as a buffer to avoid reallocating memory. + eligible_storage_live: BitSet, } impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> @@ -1009,19 +1012,19 @@ impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> impl StorageConflictVisitor<'_, '_, '_> { fn apply_state(&mut self, flow_state: &BitSet, loc: Location) { // Ignore unreachable blocks. - if self.body.basic_blocks[loc.block].terminator().kind == TerminatorKind::Unreachable { + if let TerminatorKind::Unreachable = self.body.basic_blocks[loc.block].terminator().kind { return; } - let mut eligible_storage_live = flow_state.clone(); - eligible_storage_live.intersect(&**self.saved_locals); + self.eligible_storage_live.clone_from(flow_state); + self.eligible_storage_live.intersect(&**self.saved_locals); - for local in eligible_storage_live.iter() { - self.local_conflicts.union_row_with(&eligible_storage_live, local); + for local in self.eligible_storage_live.iter() { + self.local_conflicts.union_row_with(&self.eligible_storage_live, local); } - if eligible_storage_live.count() > 1 { - trace!("at {:?}, eligible_storage_live={:?}", loc, eligible_storage_live); + if self.eligible_storage_live.count() > 1 { + trace!("at {:?}, eligible_storage_live={:?}", loc, self.eligible_storage_live); } } } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index aa7b6b02f74e..dcd7014f4fc9 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -23,7 +23,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::SourceMap; -use rustc_span::{Span, Symbol}; +use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol}; /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen @@ -107,6 +107,12 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { ); let mappings = self.create_mappings(&coverage_spans, &coverage_counters); + if mappings.is_empty() { + // No spans could be converted into valid mappings, so skip this function. + debug!("no spans could be converted into valid mappings; skipping"); + return; + } + self.inject_coverage_statements(bcb_has_coverage_spans, &coverage_counters); self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { @@ -148,9 +154,9 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { // Flatten the spans into individual term/span pairs. .flat_map(|(term, spans)| spans.iter().map(move |&span| (term, span))) // Convert each span to a code region, and create the final mapping. - .map(|(term, span)| { - let code_region = make_code_region(source_map, file_name, span, body_span); - Mapping { term, code_region } + .filter_map(|(term, span)| { + let code_region = make_code_region(source_map, file_name, span, body_span)?; + Some(Mapping { term, code_region }) }) .collect::>() } @@ -252,13 +258,22 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb data.statements.insert(0, statement); } -/// Convert the Span into its file name, start line and column, and end line and column +/// Convert the Span into its file name, start line and column, and end line and column. +/// +/// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by +/// the compiler, these column numbers are denoted in **bytes**, because that's what +/// LLVM's `llvm-cov` tool expects to see in coverage maps. +/// +/// Returns `None` if the conversion failed for some reason. This shouldn't happen, +/// but it's hard to rule out entirely (especially in the presence of complex macros +/// or other expansions), and if it does happen then skipping a span or function is +/// better than an ICE or `llvm-cov` failure that the user might have no way to avoid. fn make_code_region( source_map: &SourceMap, file_name: Symbol, span: Span, body_span: Span, -) -> CodeRegion { +) -> Option { debug!( "Called make_code_region(file_name={}, span={}, body_span={})", file_name, @@ -266,27 +281,62 @@ fn make_code_region( source_map.span_to_diagnostic_string(body_span) ); - let (file, mut start_line, mut start_col, mut end_line, mut end_col) = - source_map.span_to_location_info(span); - if span.hi() == span.lo() { - // Extend an empty span by one character so the region will be counted. - if span.hi() == body_span.hi() { - start_col = start_col.saturating_sub(1); - } else { - end_col = start_col + 1; - } - }; - if let Some(file) = file { - start_line = source_map.doctest_offset_line(&file.name, start_line); - end_line = source_map.doctest_offset_line(&file.name, end_line); + let lo = span.lo(); + let hi = span.hi(); + + let file = source_map.lookup_source_file(lo); + if !file.contains(hi) { + debug!(?span, ?file, ?lo, ?hi, "span crosses multiple files; skipping"); + return None; } - CodeRegion { + + // Column numbers need to be in bytes, so we can't use the more convenient + // `SourceMap` methods for looking up file coordinates. + let rpos_and_line_and_byte_column = |pos: BytePos| -> Option<(RelativeBytePos, usize, usize)> { + let rpos = file.relative_position(pos); + let line_index = file.lookup_line(rpos)?; + let line_start = file.lines()[line_index]; + // Line numbers and column numbers are 1-based, so add 1 to each. + Some((rpos, line_index + 1, (rpos - line_start).to_usize() + 1)) + }; + + let (lo_rpos, mut start_line, mut start_col) = rpos_and_line_and_byte_column(lo)?; + let (hi_rpos, mut end_line, mut end_col) = rpos_and_line_and_byte_column(hi)?; + + // If the span is empty, try to expand it horizontally by one character's + // worth of bytes, so that it is more visible in `llvm-cov` reports. + // We do this after resolving line/column numbers, so that empty spans at the + // end of a line get an extra column instead of wrapping to the next line. + if span.is_empty() + && body_span.contains(span) + && let Some(src) = &file.src + { + // Prefer to expand the end position, if it won't go outside the body span. + if hi < body_span.hi() { + let hi_rpos = hi_rpos.to_usize(); + let nudge_bytes = src.ceil_char_boundary(hi_rpos + 1) - hi_rpos; + end_col += nudge_bytes; + } else if lo > body_span.lo() { + let lo_rpos = lo_rpos.to_usize(); + let nudge_bytes = lo_rpos - src.floor_char_boundary(lo_rpos - 1); + // Subtract the nudge, but don't go below column 1. + start_col = start_col.saturating_sub(nudge_bytes).max(1); + } + // If neither nudge could be applied, stick with the empty span coordinates. + } + + // Apply an offset so that code in doctests has correct line numbers. + // FIXME(#79417): Currently we have no way to offset doctest _columns_. + start_line = source_map.doctest_offset_line(&file.name, start_line); + end_line = source_map.doctest_offset_line(&file.name, end_line); + + Some(CodeRegion { file_name, start_line: start_line as u32, start_col: start_col as u32, end_line: end_line as u32, end_col: end_col as u32, - } + }) } fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index ed091752187e..5983189984d9 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,11 +1,9 @@ -use std::cell::OnceCell; - use rustc_data_structures::graph::WithNumNodes; use rustc_index::IndexVec; use rustc_middle::mir; -use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP}; +use rustc_span::{BytePos, Span, DUMMY_SP}; -use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; +use super::graph::{BasicCoverageBlock, CoverageGraph}; use crate::coverage::ExtractedHirInfo; mod from_mir; @@ -70,35 +68,17 @@ impl CoverageSpans { /// `dominates()` the `BasicBlock`s in this `CoverageSpan`. #[derive(Debug, Clone)] struct CoverageSpan { - pub span: Span, - pub expn_span: Span, - pub current_macro_or_none: OnceCell>, - pub bcb: BasicCoverageBlock, + span: Span, + bcb: BasicCoverageBlock, /// List of all the original spans from MIR that have been merged into this /// span. Mainly used to precisely skip over gaps when truncating a span. - pub merged_spans: Vec, - pub is_closure: bool, + merged_spans: Vec, + is_closure: bool, } impl CoverageSpan { - pub fn for_fn_sig(fn_sig_span: Span) -> Self { - Self::new(fn_sig_span, fn_sig_span, START_BCB, false) - } - - pub(super) fn new( - span: Span, - expn_span: Span, - bcb: BasicCoverageBlock, - is_closure: bool, - ) -> Self { - Self { - span, - expn_span, - current_macro_or_none: Default::default(), - bcb, - merged_spans: vec![span], - is_closure, - } + fn new(span: Span, bcb: BasicCoverageBlock, is_closure: bool) -> Self { + Self { span, bcb, merged_spans: vec![span], is_closure } } pub fn merge_from(&mut self, other: &Self) { @@ -123,37 +103,6 @@ impl CoverageSpan { pub fn is_in_same_bcb(&self, other: &Self) -> bool { self.bcb == other.bcb } - - /// If the span is part of a macro, returns the macro name symbol. - pub fn current_macro(&self) -> Option { - self.current_macro_or_none - .get_or_init(|| { - if let ExpnKind::Macro(MacroKind::Bang, current_macro) = - self.expn_span.ctxt().outer_expn_data().kind - { - return Some(current_macro); - } - None - }) - .map(|symbol| symbol) - } - - /// If the span is part of a macro, and the macro is visible (expands directly to the given - /// body_span), returns the macro name symbol. - pub fn visible_macro(&self, body_span: Span) -> Option { - let current_macro = self.current_macro()?; - let parent_callsite = self.expn_span.parent_callsite()?; - - // In addition to matching the context of the body span, the parent callsite - // must also be the source callsite, i.e. the parent must have no parent. - let is_visible_macro = - parent_callsite.parent_callsite().is_none() && parent_callsite.eq_ctxt(body_span); - is_visible_macro.then_some(current_macro) - } - - pub fn is_macro_expansion(&self) -> bool { - self.current_macro().is_some() - } } /// Converts the initial set of `CoverageSpan`s (one per MIR `Statement` or `Terminator`) into a @@ -164,10 +113,6 @@ impl CoverageSpan { /// execution /// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures) struct CoverageSpansGenerator<'a> { - /// A `Span` covering the function body of the MIR (typically from left curly brace to right - /// curly brace). - body_span: Span, - /// The BasicCoverageBlock Control Flow Graph (BCB CFG). basic_coverage_blocks: &'a CoverageGraph, @@ -244,7 +189,6 @@ impl<'a> CoverageSpansGenerator<'a> { ); let coverage_spans = Self { - body_span: hir_info.body_span, basic_coverage_blocks, sorted_spans_iter: sorted_spans.into_iter(), some_curr: None, @@ -266,7 +210,6 @@ impl<'a> CoverageSpansGenerator<'a> { // span-processing steps don't make sense yet. if self.some_prev.is_none() { debug!(" initial span"); - self.maybe_push_macro_name_span(); continue; } @@ -278,7 +221,6 @@ impl<'a> CoverageSpansGenerator<'a> { debug!(" same bcb (and neither is a closure), merge with prev={prev:?}"); let prev = self.take_prev(); self.curr_mut().merge_from(&prev); - self.maybe_push_macro_name_span(); // Note that curr.span may now differ from curr_original_span } else if prev.span.hi() <= curr.span.lo() { debug!( @@ -286,7 +228,6 @@ impl<'a> CoverageSpansGenerator<'a> { ); let prev = self.take_prev(); self.refined_spans.push(prev); - self.maybe_push_macro_name_span(); } else if prev.is_closure { // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the // next iter @@ -297,35 +238,11 @@ impl<'a> CoverageSpansGenerator<'a> { } else if curr.is_closure { self.carve_out_span_for_closure(); } else if self.prev_original_span == curr.span { - // Note that this compares the new (`curr`) span to `prev_original_span`. - // In this branch, the actual span byte range of `prev_original_span` is not - // important. What is important is knowing whether the new `curr` span was - // **originally** the same as the original span of `prev()`. The original spans - // reflect their original sort order, and for equal spans, conveys a partial - // ordering based on CFG dominator priority. - if prev.is_macro_expansion() && curr.is_macro_expansion() { - // Macros that expand to include branching (such as - // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or - // `trace!()`) typically generate callee spans with identical - // ranges (typically the full span of the macro) for all - // `BasicBlocks`. This makes it impossible to distinguish - // the condition (`if val1 != val2`) from the optional - // branched statements (such as the call to `panic!()` on - // assert failure). In this case it is better (or less - // worse) to drop the optional branch bcbs and keep the - // non-conditional statements, to count when reached. - debug!( - " curr and prev are part of a macro expansion, and curr has the same span \ - as prev, but is in a different bcb. Drop curr and keep prev for next iter. \ - prev={prev:?}", - ); - self.take_curr(); // Discards curr. - } else { - self.update_pending_dups(); - } + // `prev` and `curr` have the same span, or would have had the + // same span before `prev` was modified by other spans. + self.update_pending_dups(); } else { self.cutoff_prev_at_overlapping_curr(); - self.maybe_push_macro_name_span(); } } @@ -360,41 +277,6 @@ impl<'a> CoverageSpansGenerator<'a> { self.refined_spans } - /// If `curr` is part of a new macro expansion, carve out and push a separate - /// span that ends just after the macro name and its subsequent `!`. - fn maybe_push_macro_name_span(&mut self) { - let curr = self.curr(); - - let Some(visible_macro) = curr.visible_macro(self.body_span) else { return }; - if let Some(prev) = &self.some_prev - && prev.expn_span.eq_ctxt(curr.expn_span) - { - return; - } - - // The split point is relative to `curr_original_span`, - // because `curr.span` may have been merged with preceding spans. - let split_point_after_macro_bang = self.curr_original_span.lo() - + BytePos(visible_macro.as_str().len() as u32) - + BytePos(1); // add 1 for the `!` - debug_assert!(split_point_after_macro_bang <= curr.span.hi()); - if split_point_after_macro_bang > curr.span.hi() { - // Something is wrong with the macro name span; - // return now to avoid emitting malformed mappings (e.g. #117788). - return; - } - - let mut macro_name_cov = curr.clone(); - macro_name_cov.span = macro_name_cov.span.with_hi(split_point_after_macro_bang); - self.curr_mut().span = curr.span.with_lo(split_point_after_macro_bang); - - debug!( - " and curr starts a new macro expansion, so add a new span just for \ - the macro `{visible_macro}!`, new span={macro_name_cov:?}", - ); - self.refined_spans.push(macro_name_cov); - } - #[track_caller] fn curr(&self) -> &CoverageSpan { self.some_curr.as_ref().unwrap_or_else(|| bug!("some_curr is None (curr)")) diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 8f6592afe85c..1b6dfccd5749 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,11 +1,14 @@ use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::{ self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; -use rustc_span::Span; +use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; -use crate::coverage::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; +use crate::coverage::graph::{ + BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB, +}; use crate::coverage::spans::CoverageSpan; use crate::coverage::ExtractedHirInfo; @@ -15,26 +18,29 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( basic_coverage_blocks: &CoverageGraph, ) -> Vec { let &ExtractedHirInfo { is_async_fn, fn_sig_span, body_span, .. } = hir_info; + + let mut initial_spans = vec![SpanFromMir::for_fn_sig(fn_sig_span)]; + if is_async_fn { // An async function desugars into a function that returns a future, // with the user code wrapped in a closure. Any spans in the desugared - // outer function will be unhelpful, so just produce a single span - // associating the function signature with its entry BCB. - return vec![CoverageSpan::for_fn_sig(fn_sig_span)]; + // outer function will be unhelpful, so just keep the signature span + // and ignore all of the spans in the MIR body. + } else { + for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { + initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data)); + } + + // If no spans were extracted from the body, discard the signature span. + // FIXME: This preserves existing behavior; consider getting rid of it. + if initial_spans.len() == 1 { + initial_spans.clear(); + } } - let mut initial_spans = Vec::with_capacity(mir_body.basic_blocks.len() * 2); - for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { - initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data)); - } - - if initial_spans.is_empty() { - // This can happen if, for example, the function is unreachable (contains only a - // `BasicBlock`(s) with an `Unreachable` terminator). - return initial_spans; - } - - initial_spans.push(CoverageSpan::for_fn_sig(fn_sig_span)); + initial_spans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)); + remove_unwanted_macro_spans(&mut initial_spans); + split_visible_macro_spans(&mut initial_spans); initial_spans.sort_by(|a, b| { // First sort by span start. @@ -53,7 +59,62 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( .then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse()) }); - initial_spans + initial_spans.into_iter().map(SpanFromMir::into_coverage_span).collect::>() +} + +/// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate +/// multiple condition/consequent blocks that have the span of the whole macro +/// invocation, which is unhelpful. Keeping only the first such span seems to +/// give better mappings, so remove the others. +/// +/// (The input spans should be sorted in BCB dominator order, so that the +/// retained "first" span is likely to dominate the others.) +fn remove_unwanted_macro_spans(initial_spans: &mut Vec) { + let mut seen_macro_spans = FxHashSet::default(); + initial_spans.retain(|covspan| { + // Ignore (retain) closure spans and non-macro-expansion spans. + if covspan.is_closure || covspan.visible_macro.is_none() { + return true; + } + + // Retain only the first macro-expanded covspan with this span. + seen_macro_spans.insert(covspan.span) + }); +} + +/// When a span corresponds to a macro invocation that is visible from the +/// function body, split it into two parts. The first part covers just the +/// macro name plus `!`, and the second part covers the rest of the macro +/// invocation. This seems to give better results for code that uses macros. +fn split_visible_macro_spans(initial_spans: &mut Vec) { + let mut extra_spans = vec![]; + + initial_spans.retain(|covspan| { + if covspan.is_closure { + return true; + } + + let Some(visible_macro) = covspan.visible_macro else { return true }; + + let split_len = visible_macro.as_str().len() as u32 + 1; + let (before, after) = covspan.span.split_at(split_len); + if !covspan.span.contains(before) || !covspan.span.contains(after) { + // Something is unexpectedly wrong with the split point. + // The debug assertion in `split_at` will have already caught this, + // but in release builds it's safer to do nothing and maybe get a + // bug report for unexpected coverage, rather than risk an ICE. + return true; + } + + assert!(!covspan.is_closure); + extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb, false)); + extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb, false)); + false // Discard the original covspan that we just split. + }); + + // The newly-split spans are added at the end, so any previous sorting + // is not preserved. + initial_spans.extend(extra_spans); } // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of @@ -66,22 +127,24 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( body_span: Span, bcb: BasicCoverageBlock, bcb_data: &'a BasicCoverageBlockData, -) -> impl Iterator + Captures<'a> + Captures<'tcx> { +) -> impl Iterator + Captures<'a> + Captures<'tcx> { bcb_data.basic_blocks.iter().flat_map(move |&bb| { let data = &mir_body[bb]; let statement_spans = data.statements.iter().filter_map(move |statement| { let expn_span = filtered_statement_span(statement)?; - let span = unexpand_into_body_span(expn_span, body_span)?; + let (span, visible_macro) = + unexpand_into_body_span_with_visible_macro(expn_span, body_span)?; - Some(CoverageSpan::new(span, expn_span, bcb, is_closure_or_coroutine(statement))) + Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_or_coroutine(statement))) }); let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| { let expn_span = filtered_terminator_span(terminator)?; - let span = unexpand_into_body_span(expn_span, body_span)?; + let (span, visible_macro) = + unexpand_into_body_span_with_visible_macro(expn_span, body_span)?; - Some(CoverageSpan::new(span, expn_span, bcb, false)) + Some(SpanFromMir::new(span, visible_macro, bcb, false)) }); statement_spans.chain(terminator_span) @@ -202,7 +265,83 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option { /// /// [^1]Expansions result from Rust syntax including macros, syntactic sugar, /// etc.). -#[inline] -fn unexpand_into_body_span(span: Span, body_span: Span) -> Option { - span.find_ancestor_inside_same_ctxt(body_span) +fn unexpand_into_body_span_with_visible_macro( + original_span: Span, + body_span: Span, +) -> Option<(Span, Option)> { + let (span, prev) = unexpand_into_body_span_with_prev(original_span, body_span)?; + + let visible_macro = prev + .map(|prev| match prev.ctxt().outer_expn_data().kind { + ExpnKind::Macro(MacroKind::Bang, name) => Some(name), + _ => None, + }) + .flatten(); + + Some((span, visible_macro)) +} + +/// Walks through the expansion ancestors of `original_span` to find a span that +/// is contained in `body_span` and has the same [`SyntaxContext`] as `body_span`. +/// The ancestor that was traversed just before the matching span (if any) is +/// also returned. +/// +/// For example, a return value of `Some((ancestor, Some(prev))` means that: +/// - `ancestor == original_span.find_ancestor_inside_same_ctxt(body_span)` +/// - `ancestor == prev.parent_callsite()` +/// +/// [`SyntaxContext`]: rustc_span::SyntaxContext +fn unexpand_into_body_span_with_prev( + original_span: Span, + body_span: Span, +) -> Option<(Span, Option)> { + let mut prev = None; + let mut curr = original_span; + + while !body_span.contains(curr) || !curr.eq_ctxt(body_span) { + prev = Some(curr); + curr = curr.parent_callsite()?; + } + + debug_assert_eq!(Some(curr), original_span.find_ancestor_in_same_ctxt(body_span)); + if let Some(prev) = prev { + debug_assert_eq!(Some(curr), prev.parent_callsite()); + } + + Some((curr, prev)) +} + +#[derive(Debug)] +struct SpanFromMir { + /// A span that has been extracted from MIR and then "un-expanded" back to + /// within the current function's `body_span`. After various intermediate + /// processing steps, this span is emitted as part of the final coverage + /// mappings. + /// + /// With the exception of `fn_sig_span`, this should always be contained + /// within `body_span`. + span: Span, + visible_macro: Option, + bcb: BasicCoverageBlock, + is_closure: bool, +} + +impl SpanFromMir { + fn for_fn_sig(fn_sig_span: Span) -> Self { + Self::new(fn_sig_span, None, START_BCB, false) + } + + fn new( + span: Span, + visible_macro: Option, + bcb: BasicCoverageBlock, + is_closure: bool, + ) -> Self { + Self { span, visible_macro, bcb, is_closure } + } + + fn into_coverage_span(self) -> CoverageSpan { + let Self { span, visible_macro: _, bcb, is_closure } = self; + CoverageSpan::new(span, bcb, is_closure) + } } diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs index b40b2ec8bfdc..824974970bb3 100644 --- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs +++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs @@ -25,7 +25,7 @@ impl<'tcx> MirPass<'tcx> for DeduplicateBlocks { if has_opts_to_apply { let mut opt_applier = OptApplier { tcx, duplicates }; opt_applier.visit_body(body); - simplify_cfg(tcx, body); + simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index cd80f423466b..49b0edc0db88 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -131,10 +131,8 @@ //! [attempt 2]: https://github.com/rust-lang/rust/pull/71003 //! [attempt 3]: https://github.com/rust-lang/rust/pull/72632 -use std::collections::hash_map::{Entry, OccupiedEntry}; - use crate::MirPass; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxIndexMap, IndexEntry, IndexOccupiedEntry}; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::HasLocalDecls; @@ -211,7 +209,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { let mut merged_locals: BitSet = BitSet::new_empty(body.local_decls.len()); // This is the set of merges we will apply this round. It is a subset of the candidates. - let mut merges = FxHashMap::default(); + let mut merges = FxIndexMap::default(); for (src, candidates) in candidates.c.iter() { if merged_locals.contains(*src) { @@ -250,8 +248,8 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { /// frequently. Everything with a `&'alloc` lifetime points into here. #[derive(Default)] struct Allocations { - candidates: FxHashMap>, - candidates_reverse: FxHashMap>, + candidates: FxIndexMap>, + candidates_reverse: FxIndexMap>, write_info: WriteInfo, // PERF: Do this for `MaybeLiveLocals` allocations too. } @@ -272,11 +270,11 @@ struct Candidates<'alloc> { /// /// We will still report that we would like to merge `_1` and `_2` in an attempt to allow us to /// remove that assignment. - c: &'alloc mut FxHashMap>, + c: &'alloc mut FxIndexMap>, /// A reverse index of the `c` set; if the `c` set contains `a => Place { local: b, proj }`, /// then this contains `b => a`. // PERF: Possibly these should be `SmallVec`s? - reverse: &'alloc mut FxHashMap>, + reverse: &'alloc mut FxIndexMap>, } ////////////////////////////////////////////////////////// @@ -287,7 +285,7 @@ struct Candidates<'alloc> { fn apply_merges<'tcx>( body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>, - merges: &FxHashMap, + merges: &FxIndexMap, merged_locals: &BitSet, ) { let mut merger = Merger { tcx, merges, merged_locals }; @@ -296,7 +294,7 @@ fn apply_merges<'tcx>( struct Merger<'a, 'tcx> { tcx: TyCtxt<'tcx>, - merges: &'a FxHashMap, + merges: &'a FxIndexMap, merged_locals: &'a BitSet, } @@ -379,7 +377,7 @@ impl<'alloc> Candidates<'alloc> { /// `vec_filter_candidates` but for an `Entry` fn entry_filter_candidates( - mut entry: OccupiedEntry<'_, Local, Vec>, + mut entry: IndexOccupiedEntry<'_, Local, Vec>, p: Local, f: impl FnMut(Local) -> CandidateFilter, at: Location, @@ -399,7 +397,7 @@ impl<'alloc> Candidates<'alloc> { at: Location, ) { // Cover the cases where `p` appears as a `src` - if let Entry::Occupied(entry) = self.c.entry(p) { + if let IndexEntry::Occupied(entry) = self.c.entry(p) { Self::entry_filter_candidates(entry, p, &mut f, at); } // And the cases where `p` appears as a `dest` @@ -412,7 +410,7 @@ impl<'alloc> Candidates<'alloc> { if f(*src) == CandidateFilter::Keep { return true; } - let Entry::Occupied(entry) = self.c.entry(*src) else { + let IndexEntry::Occupied(entry) = self.c.entry(*src) else { return false; }; Self::entry_filter_candidates( @@ -721,8 +719,8 @@ fn places_to_candidate_pair<'tcx>( fn find_candidates<'alloc, 'tcx>( body: &Body<'tcx>, borrowed: &BitSet, - candidates: &'alloc mut FxHashMap>, - candidates_reverse: &'alloc mut FxHashMap>, + candidates: &'alloc mut FxIndexMap>, + candidates_reverse: &'alloc mut FxIndexMap>, ) -> Candidates<'alloc> { candidates.clear(); candidates_reverse.clear(); @@ -744,7 +742,7 @@ fn find_candidates<'alloc, 'tcx>( struct FindAssignments<'a, 'alloc, 'tcx> { body: &'a Body<'tcx>, - candidates: &'alloc mut FxHashMap>, + candidates: &'alloc mut FxIndexMap>, borrowed: &'a BitSet, } diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 6eb6cb069fec..0d600f0f937d 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -212,7 +212,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { // Since this optimization adds new basic blocks and invalidates others, // clean up the cfg to make it nicer for other passes if should_cleanup { - simplify_cfg(tcx, body); + simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index bde442049b1d..446f13feff08 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -181,8 +181,7 @@ pub(crate) struct UnsafeOpInUnsafeFn { impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn { #[track_caller] fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { - let dcx = diag.dcx().expect("lint should not yet be emitted"); - let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter()); + let desc = diag.dcx.eagerly_translate_to_string(self.details.label(), [].into_iter()); diag.arg("details", desc); diag.span_label(self.details.span, self.details.label()); self.details.add_subdiagnostics(diag); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 8ad804bf3e7a..ebefc3b47cc4 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -15,7 +15,7 @@ use rustc_target::abi::FieldIdx; use rustc_target::spec::abi::Abi; use crate::cost_checker::CostChecker; -use crate::simplify::{remove_dead_blocks, CfgSimplifier}; +use crate::simplify::simplify_cfg; use crate::util; use std::iter; use std::ops::{Range, RangeFrom}; @@ -56,8 +56,7 @@ impl<'tcx> MirPass<'tcx> for Inline { let _guard = span.enter(); if inline(tcx, body) { debug!("running simplify cfg on {:?}", body.source); - CfgSimplifier::new(body).simplify(); - remove_dead_blocks(body); + simplify_cfg(body); deref_finder(tcx, body); } } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index a41d8e212454..dcab124505e2 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -43,6 +43,7 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, State, TrackElem}; +use rustc_target::abi::{TagEncoding, Variants}; use crate::cost_checker::CostChecker; @@ -391,8 +392,25 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { StatementKind::SetDiscriminant { box place, variant_index } => { let discr_target = self.map.find_discr(place.as_ref())?; let enum_ty = place.ty(self.body, self.tcx).ty; - let discr = discriminant_for_variant(enum_ty, *variant_index)?; - self.process_operand(bb, discr_target, &discr, state)?; + // `SetDiscriminant` may be a no-op if the assigned variant is the untagged variant + // of a niche encoding. If we cannot ensure that we write to the discriminant, do + // nothing. + let enum_layout = self.tcx.layout_of(self.param_env.and(enum_ty)).ok()?; + let writes_discriminant = match enum_layout.variants { + Variants::Single { index } => { + assert_eq!(index, *variant_index); + true + } + Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => true, + Variants::Multiple { + tag_encoding: TagEncoding::Niche { untagged_variant, .. }, + .. + } => *variant_index != untagged_variant, + }; + if writes_discriminant { + let discr = discriminant_for_variant(enum_ty, *variant_index)?; + self.process_operand(bb, discr_target, &discr, state)?; + } } // If we expect `lhs ?= true`, we have an opportunity if we assume `lhs == true`. StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume( diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 164b6b9c4f5c..43c5b3873b91 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,6 +1,6 @@ -#![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![feature(assert_matches)] #![feature(box_patterns)] #![feature(cow_is_borrowed)] #![feature(decl_macro)] @@ -10,6 +10,7 @@ #![feature(min_specialization)] #![feature(never_type)] #![feature(option_get_or_insert_default)] +#![feature(round_char_boundary)] #![feature(trusted_step)] #![feature(try_blocks)] #![feature(yeet_expr)] @@ -94,6 +95,7 @@ mod multiple_return_terminators; mod normalize_array_len; mod nrvo; mod prettify; +mod promote_consts; mod ref_prop; mod remove_noop_landing_pads; mod remove_storage_markers; @@ -115,7 +117,6 @@ mod uninhabited_enum_branching; mod unreachable_prop; use rustc_const_eval::transform::check_consts::{self, ConstCx}; -use rustc_const_eval::transform::promote_consts; use rustc_const_eval::transform::validate; use rustc_mir_dataflow::rustc_peek; diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 1c4aa37d57ff..6d4332793af3 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -174,7 +174,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { } if should_cleanup { - simplify_cfg(tcx, body); + simplify_cfg(body); } } } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs similarity index 73% rename from compiler/rustc_const_eval/src/transform/promote_consts.rs rename to compiler/rustc_mir_transform/src/promote_consts.rs index 8b2ea2dc21dd..841b86fed454 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -12,6 +12,7 @@ //! initialization and can otherwise silence errors, if //! move analysis runs after promotion on broken MIR. +use either::{Left, Right}; use rustc_hir as hir; use rustc_middle::mir; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; @@ -22,10 +23,11 @@ use rustc_span::Span; use rustc_index::{Idx, IndexSlice, IndexVec}; +use std::assert_matches::assert_matches; use std::cell::Cell; use std::{cmp, iter, mem}; -use crate::transform::check_consts::{qualifs, ConstCx}; +use rustc_const_eval::transform::check_consts::{qualifs, ConstCx}; /// A `MirPass` for promotion. /// @@ -64,7 +66,7 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { /// State of a temporary during collection and promotion. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum TempState { +enum TempState { /// No references to this temp. Undefined, /// One direct assignment and any number of direct uses. @@ -78,18 +80,11 @@ pub enum TempState { PromotedOut, } -impl TempState { - pub fn is_promotable(&self) -> bool { - debug!("is_promotable: self={:?}", self); - matches!(self, TempState::Defined { .. }) - } -} - /// A "root candidate" for promotion, which will become the /// returned value in a promoted MIR, unless it's a subset /// of a larger candidate. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Candidate { +struct Candidate { location: Location, } @@ -123,46 +118,43 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { let temp = &mut self.temps[index]; debug!("visit_local: temp={:?}", temp); - if *temp == TempState::Undefined { - match context { + *temp = match *temp { + TempState::Undefined => match context { PlaceContext::MutatingUse(MutatingUseContext::Store) | PlaceContext::MutatingUse(MutatingUseContext::Call) => { - *temp = TempState::Defined { location, uses: 0, valid: Err(()) }; + TempState::Defined { location, uses: 0, valid: Err(()) } + } + _ => TempState::Unpromotable, + }, + TempState::Defined { ref mut uses, .. } => { + // We always allow borrows, even mutable ones, as we need + // to promote mutable borrows of some ZSTs e.g., `&mut []`. + let allowed_use = match context { + PlaceContext::MutatingUse(MutatingUseContext::Borrow) + | PlaceContext::NonMutatingUse(_) => true, + PlaceContext::MutatingUse(_) | PlaceContext::NonUse(_) => false, + }; + debug!("visit_local: allowed_use={:?}", allowed_use); + if allowed_use { + *uses += 1; return; } - _ => { /* mark as unpromotable below */ } + TempState::Unpromotable } - } else if let TempState::Defined { uses, .. } = temp { - // We always allow borrows, even mutable ones, as we need - // to promote mutable borrows of some ZSTs e.g., `&mut []`. - let allowed_use = match context { - PlaceContext::MutatingUse(MutatingUseContext::Borrow) - | PlaceContext::NonMutatingUse(_) => true, - PlaceContext::MutatingUse(_) | PlaceContext::NonUse(_) => false, - }; - debug!("visit_local: allowed_use={:?}", allowed_use); - if allowed_use { - *uses += 1; - return; - } - /* mark as unpromotable below */ - } - *temp = TempState::Unpromotable; + TempState::Unpromotable | TempState::PromotedOut => TempState::Unpromotable, + }; } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { self.super_rvalue(rvalue, location); - match *rvalue { - Rvalue::Ref(..) => { - self.candidates.push(Candidate { location }); - } - _ => {} + if let Rvalue::Ref(..) = *rvalue { + self.candidates.push(Candidate { location }); } } } -pub fn collect_temps_and_candidates<'tcx>( +fn collect_temps_and_candidates<'tcx>( ccx: &ConstCx<'_, 'tcx>, ) -> (IndexVec, Vec) { let mut collector = Collector { @@ -196,230 +188,165 @@ struct Unpromotable; impl<'tcx> Validator<'_, 'tcx> { fn validate_candidate(&mut self, candidate: Candidate) -> Result<(), Unpromotable> { - let loc = candidate.location; - let statement = &self.body[loc.block].statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => { - // We can only promote interior borrows of promotable temps (non-temps - // don't get promoted anyway). - self.validate_local(place.local)?; + let Left(statement) = self.body.stmt_at(candidate.location) else { bug!() }; + let Some((_, Rvalue::Ref(_, kind, place))) = statement.kind.as_assign() else { bug!() }; - // The reference operation itself must be promotable. - // (Needs to come after `validate_local` to avoid ICEs.) - self.validate_ref(*kind, place)?; + // We can only promote interior borrows of promotable temps (non-temps + // don't get promoted anyway). + self.validate_local(place.local)?; - // We do not check all the projections (they do not get promoted anyway), - // but we do stay away from promoting anything involving a dereference. - if place.projection.contains(&ProjectionElem::Deref) { - return Err(Unpromotable); - } + // The reference operation itself must be promotable. + // (Needs to come after `validate_local` to avoid ICEs.) + self.validate_ref(*kind, place)?; - Ok(()) - } - _ => bug!(), + // We do not check all the projections (they do not get promoted anyway), + // but we do stay away from promoting anything involving a dereference. + if place.projection.contains(&ProjectionElem::Deref) { + return Err(Unpromotable); } + + Ok(()) } // FIXME(eddyb) maybe cache this? fn qualif_local(&mut self, local: Local) -> bool { - if let TempState::Defined { location: loc, .. } = self.temps[local] { - let num_stmts = self.body[loc.block].statements.len(); + let TempState::Defined { location: loc, .. } = self.temps[local] else { + return false; + }; - if loc.statement_index < num_stmts { - let statement = &self.body[loc.block].statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box (_, rhs)) => qualifs::in_rvalue::( - self.ccx, - &mut |l| self.qualif_local::(l), - rhs, - ), - _ => { - span_bug!( - statement.source_info.span, - "{:?} is not an assignment", - statement - ); - } - } - } else { - let terminator = self.body[loc.block].terminator(); - match &terminator.kind { - TerminatorKind::Call { .. } => { - let return_ty = self.body.local_decls[local].ty; - Q::in_any_value_of_ty(self.ccx, return_ty) - } - kind => { - span_bug!(terminator.source_info.span, "{:?} not promotable", kind); - } - } + let stmt_or_term = self.body.stmt_at(loc); + match stmt_or_term { + Left(statement) => { + let Some((_, rhs)) = statement.kind.as_assign() else { + span_bug!(statement.source_info.span, "{:?} is not an assignment", statement) + }; + qualifs::in_rvalue::(self.ccx, &mut |l| self.qualif_local::(l), rhs) + } + Right(terminator) => { + assert_matches!(terminator.kind, TerminatorKind::Call { .. }); + let return_ty = self.body.local_decls[local].ty; + Q::in_any_value_of_ty(self.ccx, return_ty) } - } else { - false } } fn validate_local(&mut self, local: Local) -> Result<(), Unpromotable> { - if let TempState::Defined { location: loc, uses, valid } = self.temps[local] { - // We cannot promote things that need dropping, since the promoted value - // would not get dropped. - if self.qualif_local::(local) { - return Err(Unpromotable); - } - valid.or_else(|_| { - let ok = { - let block = &self.body[loc.block]; - let num_stmts = block.statements.len(); + let TempState::Defined { location: loc, uses, valid } = self.temps[local] else { + return Err(Unpromotable); + }; - if loc.statement_index < num_stmts { - let statement = &block.statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs), - _ => { - span_bug!( - statement.source_info.span, - "{:?} is not an assignment", - statement - ); - } - } - } else { - let terminator = block.terminator(); - match &terminator.kind { - TerminatorKind::Call { func, args, .. } => { - self.validate_call(func, args) - } - TerminatorKind::Yield { .. } => Err(Unpromotable), - kind => { - span_bug!(terminator.source_info.span, "{:?} not promotable", kind); - } - } - } - }; - self.temps[local] = match ok { - Ok(()) => TempState::Defined { location: loc, uses, valid: Ok(()) }, - Err(_) => TempState::Unpromotable, - }; - ok - }) - } else { - Err(Unpromotable) + // We cannot promote things that need dropping, since the promoted value would not get + // dropped. + if self.qualif_local::(local) { + return Err(Unpromotable); } + + if valid.is_ok() { + return Ok(()); + } + + let ok = { + let stmt_or_term = self.body.stmt_at(loc); + match stmt_or_term { + Left(statement) => { + let Some((_, rhs)) = statement.kind.as_assign() else { + span_bug!( + statement.source_info.span, + "{:?} is not an assignment", + statement + ) + }; + self.validate_rvalue(rhs) + } + Right(terminator) => match &terminator.kind { + TerminatorKind::Call { func, args, .. } => self.validate_call(func, args), + TerminatorKind::Yield { .. } => Err(Unpromotable), + kind => { + span_bug!(terminator.source_info.span, "{:?} not promotable", kind); + } + }, + } + }; + + self.temps[local] = match ok { + Ok(()) => TempState::Defined { location: loc, uses, valid: Ok(()) }, + Err(_) => TempState::Unpromotable, + }; + + ok } fn validate_place(&mut self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> { - match place.last_projection() { - None => self.validate_local(place.local), - Some((place_base, elem)) => { - // Validate topmost projection, then recurse. - match elem { - ProjectionElem::Deref => { - let mut promotable = false; - // When a static is used by-value, that gets desugared to `*STATIC_ADDR`, - // and we need to be able to promote this. So check if this deref matches - // that specific pattern. + let Some((place_base, elem)) = place.last_projection() else { + return self.validate_local(place.local); + }; - // We need to make sure this is a `Deref` of a local with no further projections. - // Discussion can be found at - // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247 - if let Some(local) = place_base.as_local() { - if let TempState::Defined { location, .. } = self.temps[local] { - let def_stmt = self.body[location.block] - .statements - .get(location.statement_index); - if let Some(Statement { - kind: - StatementKind::Assign(box ( - _, - Rvalue::Use(Operand::Constant(c)), - )), - .. - }) = def_stmt - { - if let Some(did) = c.check_static_ptr(self.tcx) { - // Evaluating a promoted may not read statics except if it got - // promoted from a static (this is a CTFE check). So we - // can only promote static accesses inside statics. - if let Some(hir::ConstContext::Static(..)) = self.const_kind - { - if !self.tcx.is_thread_local_static(did) { - promotable = true; - } - } - } - } - } - } - if !promotable { - return Err(Unpromotable); - } - } - ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => { - return Err(Unpromotable); - } + // Validate topmost projection, then recurse. + match elem { + // Recurse directly. + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subtype(_) + | ProjectionElem::Subslice { .. } => {} - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subtype(_) - | ProjectionElem::Subslice { .. } => {} + // Never recurse. + ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => { + return Err(Unpromotable); + } - ProjectionElem::Index(local) => { - let mut promotable = false; - // Only accept if we can predict the index and are indexing an array. - let val = if let TempState::Defined { location: loc, .. } = - self.temps[local] - { - let block = &self.body[loc.block]; - if loc.statement_index < block.statements.len() { - let statement = &block.statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box ( - _, - Rvalue::Use(Operand::Constant(c)), - )) => c.const_.try_eval_target_usize(self.tcx, self.param_env), - _ => None, - } - } else { - None - } - } else { - None - }; - if let Some(idx) = val { - // Determine the type of the thing we are indexing. - let ty = place_base.ty(self.body, self.tcx).ty; - match ty.kind() { - ty::Array(_, len) => { - // It's an array; determine its length. - if let Some(len) = - len.try_eval_target_usize(self.tcx, self.param_env) - { - // If the index is in-bounds, go ahead. - if idx < len { - promotable = true; - } - } - } - _ => {} - } - } - if !promotable { - return Err(Unpromotable); - } + ProjectionElem::Deref => { + // When a static is used by-value, that gets desugared to `*STATIC_ADDR`, + // and we need to be able to promote this. So check if this deref matches + // that specific pattern. - self.validate_local(local)?; - } - - ProjectionElem::Field(..) => { - let base_ty = place_base.ty(self.body, self.tcx).ty; - if base_ty.is_union() { - // No promotion of union field accesses. - return Err(Unpromotable); - } - } + // We need to make sure this is a `Deref` of a local with no further projections. + // Discussion can be found at + // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247 + if let Some(local) = place_base.as_local() + && let TempState::Defined { location, .. } = self.temps[local] + && let Left(def_stmt) = self.body.stmt_at(location) + && let Some((_, Rvalue::Use(Operand::Constant(c)))) = def_stmt.kind.as_assign() + && let Some(did) = c.check_static_ptr(self.tcx) + // Evaluating a promoted may not read statics except if it got + // promoted from a static (this is a CTFE check). So we + // can only promote static accesses inside statics. + && let Some(hir::ConstContext::Static(..)) = self.const_kind + && !self.tcx.is_thread_local_static(did) + { + // Recurse. + } else { + return Err(Unpromotable); } + } + ProjectionElem::Index(local) => { + // Only accept if we can predict the index and are indexing an array. + if let TempState::Defined { location: loc, .. } = self.temps[local] + && let Left(statement) = self.body.stmt_at(loc) + && let Some((_, Rvalue::Use(Operand::Constant(c)))) = statement.kind.as_assign() + && let Some(idx) = c.const_.try_eval_target_usize(self.tcx, self.param_env) + // Determine the type of the thing we are indexing. + && let ty::Array(_, len) = place_base.ty(self.body, self.tcx).ty.kind() + // It's an array; determine its length. + && let Some(len) = len.try_eval_target_usize(self.tcx, self.param_env) + // If the index is in-bounds, go ahead. + && idx < len + { + self.validate_local(local)?; + // Recurse. + } else { + return Err(Unpromotable); + } + } - self.validate_place(place_base) + ProjectionElem::Field(..) => { + let base_ty = place_base.ty(self.body, self.tcx).ty; + if base_ty.is_union() { + // No promotion of union field accesses. + return Err(Unpromotable); + } } } + + self.validate_place(place_base) } fn validate_operand(&mut self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> { @@ -676,7 +603,7 @@ impl<'tcx> Validator<'_, 'tcx> { } // FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`. -pub fn validate_candidates( +fn validate_candidates( ccx: &ConstCx<'_, '_>, temps: &mut IndexSlice, candidates: &[Candidate], @@ -930,7 +857,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { } } -pub fn promote_candidates<'tcx>( +fn promote_candidates<'tcx>( body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>, mut temps: IndexVec, @@ -969,7 +896,7 @@ pub fn promote_candidates<'tcx>( 0, vec![], body.span, - body.coroutine_kind(), + None, body.tainted_by_errors, ); promoted.phase = MirPhase::Analysis(AnalysisPhase::Initial); diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs index 5d528bed3564..2778d91e17b9 100644 --- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs @@ -38,7 +38,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { // if we applied optimizations, we potentially have some cfg to cleanup to // make it easier for further passes if should_simplify { - simplify_cfg(tcx, body); + simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 6e22690d8dad..7120ef721427 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -50,11 +50,11 @@ impl<'tcx> MirPass<'tcx> for SeparateConstSwitch { sess.mir_opt_level() >= 2 && sess.opts.unstable_opts.unsound_mir_opts } - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // If execution did something, applying a simplification layer // helps later passes optimize the copy away. if separate_const_switch(body) > 0 { - super::simplify::simplify_cfg(tcx, body); + super::simplify::simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 856a0f227714..8c8818bd68e6 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -27,7 +27,6 @@ //! naively generate still contains the `_a = ()` write in the unreachable block "after" the //! return. -use rustc_data_structures::fx::FxIndexSet; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -62,9 +61,8 @@ impl SimplifyCfg { } } -pub fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +pub(crate) fn simplify_cfg(body: &mut Body<'_>) { CfgSimplifier::new(body).simplify(); - remove_duplicate_unreachable_blocks(tcx, body); remove_dead_blocks(body); // FIXME: Should probably be moved into some kind of pass manager @@ -76,9 +74,9 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg { self.name() } - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("SimplifyCfg({:?}) - simplifying {:?}", self.name(), body.source); - simplify_cfg(tcx, body); + simplify_cfg(body); } } @@ -289,55 +287,25 @@ pub fn simplify_duplicate_switch_targets(terminator: &mut Terminator<'_>) { } } -pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - struct OptApplier<'tcx> { - tcx: TyCtxt<'tcx>, - duplicates: FxIndexSet, - } +pub(crate) fn remove_dead_blocks(body: &mut Body<'_>) { + let should_deduplicate_unreachable = |bbdata: &BasicBlockData<'_>| { + // CfgSimplifier::simplify leaves behind some unreachable basic blocks without a + // terminator. Those blocks will be deleted by remove_dead_blocks, but we run just + // before then so we need to handle missing terminators. + // We also need to prevent confusing cleanup and non-cleanup blocks. In practice we + // don't emit empty unreachable cleanup blocks, so this simple check suffices. + bbdata.terminator.is_some() && bbdata.is_empty_unreachable() && !bbdata.is_cleanup + }; - impl<'tcx> MutVisitor<'tcx> for OptApplier<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { - for target in terminator.successors_mut() { - // We don't have to check whether `target` is a cleanup block, because have - // entirely excluded cleanup blocks in building the set of duplicates. - if self.duplicates.contains(target) { - *target = self.duplicates[0]; - } - } - - simplify_duplicate_switch_targets(terminator); - - self.super_terminator(terminator, location); - } - } - - let unreachable_blocks = body + let reachable = traversal::reachable_as_bitset(body); + let empty_unreachable_blocks = body .basic_blocks .iter_enumerated() - .filter(|(_, bb)| { - // CfgSimplifier::simplify leaves behind some unreachable basic blocks without a - // terminator. Those blocks will be deleted by remove_dead_blocks, but we run just - // before then so we need to handle missing terminators. - // We also need to prevent confusing cleanup and non-cleanup blocks. In practice we - // don't emit empty unreachable cleanup blocks, so this simple check suffices. - bb.terminator.is_some() && bb.is_empty_unreachable() && !bb.is_cleanup - }) - .map(|(block, _)| block) - .collect::>(); + .filter(|(bb, bbdata)| should_deduplicate_unreachable(bbdata) && reachable.contains(*bb)) + .count(); - if unreachable_blocks.len() > 1 { - OptApplier { tcx, duplicates: unreachable_blocks }.visit_body(body); - } -} - -pub fn remove_dead_blocks(body: &mut Body<'_>) { - let reachable = traversal::reachable_as_bitset(body); let num_blocks = body.basic_blocks.len(); - if num_blocks == reachable.count() { + if num_blocks == reachable.count() && empty_unreachable_blocks <= 1 { return; } @@ -346,14 +314,28 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); let mut orig_index = 0; let mut used_index = 0; - basic_blocks.raw.retain(|_| { - let keep = reachable.contains(BasicBlock::new(orig_index)); - if keep { - replacements[orig_index] = BasicBlock::new(used_index); - used_index += 1; + let mut kept_unreachable = None; + basic_blocks.raw.retain(|bbdata| { + let orig_bb = BasicBlock::new(orig_index); + if !reachable.contains(orig_bb) { + orig_index += 1; + return false; } + + let used_bb = BasicBlock::new(used_index); + if should_deduplicate_unreachable(bbdata) { + let kept_unreachable = *kept_unreachable.get_or_insert(used_bb); + if kept_unreachable != used_bb { + replacements[orig_index] = kept_unreachable; + orig_index += 1; + return false; + } + } + + replacements[orig_index] = used_bb; + used_index += 1; orig_index += 1; - keep + true }); for block in basic_blocks { diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index 3a6e1ef34883..1ed3b14e7550 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -94,6 +94,7 @@ impl SsaLocals { self.direct_uses[local] } + #[inline] pub fn assignment_dominates( &self, dominators: &Dominators, diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index f12a6aa2429c..bff59aa60237 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -54,6 +54,8 @@ impl MirPass<'_> for UnreachablePropagation { patch.apply(body); // We do want do keep some unreachable blocks, but make them empty. + // The order in which we clear bb statements does not matter. + #[allow(rustc::potential_query_instability)] for bb in unreachable_blocks { body.basic_blocks_mut()[bb].statements.clear(); } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 4819ed6021d0..a45bc5812402 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -67,7 +67,7 @@ pub(crate) fn parse_token_trees<'a>( let (stream, res, unmatched_delims) = tokentrees::TokenTreesReader::parse_all_token_trees(string_reader); match res { - Ok(_open_spacing) if unmatched_delims.is_empty() => Ok(stream), + Ok(()) if unmatched_delims.is_empty() => Ok(stream), _ => { // Return error if there are unmatched delimiters or unclosed delimiters. // We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch @@ -249,9 +249,9 @@ impl<'a> StringReader<'a> { let lifetime_name = self.str_from(start); if starts_with_number { let span = self.mk_sp(start, self.pos); - let mut diag = self.dcx().struct_err("lifetimes cannot start with a number"); - diag.span(span); - diag.stash(span, StashKey::LifetimeIsChar); + self.dcx().struct_err("lifetimes cannot start with a number") + .span_mv(span) + .stash(span, StashKey::LifetimeIsChar); } let ident = Symbol::intern(lifetime_name); token::Lifetime(ident) @@ -395,51 +395,58 @@ impl<'a> StringReader<'a> { match kind { rustc_lexer::LiteralKind::Char { terminated } => { if !terminated { - self.dcx().span_fatal_with_code( - self.mk_sp(start, end), - "unterminated character literal", - error_code!(E0762), - ) + self.dcx() + .struct_span_fatal(self.mk_sp(start, end), "unterminated character literal") + .code_mv(error_code!(E0762)) + .emit() } self.cook_quoted(token::Char, Mode::Char, start, end, 1, 1) // ' ' } rustc_lexer::LiteralKind::Byte { terminated } => { if !terminated { - self.dcx().span_fatal_with_code( - self.mk_sp(start + BytePos(1), end), - "unterminated byte constant", - error_code!(E0763), - ) + self.dcx() + .struct_span_fatal( + self.mk_sp(start + BytePos(1), end), + "unterminated byte constant", + ) + .code_mv(error_code!(E0763)) + .emit() } self.cook_quoted(token::Byte, Mode::Byte, start, end, 2, 1) // b' ' } rustc_lexer::LiteralKind::Str { terminated } => { if !terminated { - self.dcx().span_fatal_with_code( - self.mk_sp(start, end), - "unterminated double quote string", - error_code!(E0765), - ) + self.dcx() + .struct_span_fatal( + self.mk_sp(start, end), + "unterminated double quote string", + ) + .code_mv(error_code!(E0765)) + .emit() } self.cook_quoted(token::Str, Mode::Str, start, end, 1, 1) // " " } rustc_lexer::LiteralKind::ByteStr { terminated } => { if !terminated { - self.dcx().span_fatal_with_code( - self.mk_sp(start + BytePos(1), end), - "unterminated double quote byte string", - error_code!(E0766), - ) + self.dcx() + .struct_span_fatal( + self.mk_sp(start + BytePos(1), end), + "unterminated double quote byte string", + ) + .code_mv(error_code!(E0766)) + .emit() } self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" " } rustc_lexer::LiteralKind::CStr { terminated } => { if !terminated { - self.dcx().span_fatal_with_code( - self.mk_sp(start + BytePos(1), end), - "unterminated C string", - error_code!(E0767), - ) + self.dcx() + .struct_span_fatal( + self.mk_sp(start + BytePos(1), end), + "unterminated C string", + ) + .code_mv(error_code!(E0767)) + .emit() } self.cook_c_string(token::CStr, Mode::CStr, start, end, 2, 1) // c" " } @@ -573,12 +580,9 @@ impl<'a> StringReader<'a> { possible_offset: Option, found_terminators: u32, ) -> ! { - let mut err = self.dcx().struct_span_fatal_with_code( - self.mk_sp(start, start), - "unterminated raw string", - error_code!(E0748), - ); - + let mut err = + self.dcx().struct_span_fatal(self.mk_sp(start, start), "unterminated raw string"); + err.code(error_code!(E0748)); err.span_label(self.mk_sp(start, start), "unterminated raw string"); if n_hashes > 0 { @@ -609,11 +613,8 @@ impl<'a> StringReader<'a> { None => "unterminated block comment", }; let last_bpos = self.pos; - let mut err = self.dcx().struct_span_fatal_with_code( - self.mk_sp(start, last_bpos), - msg, - error_code!(E0758), - ); + let mut err = self.dcx().struct_span_fatal(self.mk_sp(start, last_bpos), msg); + err.code(error_code!(E0758)); let mut nested_block_comment_open_idxs = vec![]; let mut last_nested_block_comment_idxs = None; let mut content_chars = self.str_from(start).char_indices().peekable(); diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index b6cccd275ee6..64b3928689af 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -277,9 +277,9 @@ impl<'a> TokenTreesReader<'a> { parser.bump(); } if !diff_errs.is_empty() { - errs.iter_mut().for_each(|err| { - err.delay_as_bug(); - }); + for err in errs { + err.cancel(); + } return diff_errs; } return errs; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 579c3cffcfbf..d7604d7cebca 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -245,9 +245,9 @@ pub fn parse_cfg_attr( crate::validate_attr::check_cfg_attr_bad_delim(parse_sess, dspan, delim); match parse_in(parse_sess, tokens.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) { Ok(r) => return Some(r), - Err(mut e) => { - e.help(format!("the valid syntax is `{CFG_ATTR_GRAMMAR_HELP}`")) - .note(CFG_ATTR_NOTE_REF) + Err(e) => { + e.help_mv(format!("the valid syntax is `{CFG_ATTR_GRAMMAR_HELP}`")) + .note_mv(CFG_ATTR_NOTE_REF) .emit(); } } diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index c8629069968a..cec657f7b67a 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -55,11 +55,10 @@ impl<'a> Parser<'a> { } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind { if attr_style != ast::AttrStyle::Outer { let span = self.token.span; - let mut err = self.dcx().struct_span_err_with_code( - span, - fluent::parse_inner_doc_comment_not_permitted, - error_code!(E0753), - ); + let mut err = self + .dcx() + .struct_span_err(span, fluent::parse_inner_doc_comment_not_permitted); + err.code(error_code!(E0753)); if let Some(replacement_span) = self.annotate_following_item_if_applicable( &mut err, span, @@ -200,23 +199,22 @@ impl<'a> Parser<'a> { if let InnerAttrPolicy::Forbidden(reason) = policy { let mut diag = match reason.as_ref().copied() { Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span }) => { - let mut diag = self.dcx().struct_span_err( - attr_sp, - fluent::parse_inner_attr_not_permitted_after_outer_doc_comment, - ); - diag.span_label(attr_sp, fluent::parse_label_attr) - .span_label(prev_doc_comment_span, fluent::parse_label_prev_doc_comment); - diag + self.dcx() + .struct_span_err( + attr_sp, + fluent::parse_inner_attr_not_permitted_after_outer_doc_comment, + ) + .span_label_mv(attr_sp, fluent::parse_label_attr) + .span_label_mv(prev_doc_comment_span, fluent::parse_label_prev_doc_comment) } - Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => { - let mut diag = self.dcx().struct_span_err( + Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => self + .dcx() + .struct_span_err( attr_sp, fluent::parse_inner_attr_not_permitted_after_outer_attr, - ); - diag.span_label(attr_sp, fluent::parse_label_attr) - .span_label(prev_outer_attr_sp, fluent::parse_label_prev_attr); - diag - } + ) + .span_label_mv(attr_sp, fluent::parse_label_attr) + .span_label_mv(prev_outer_attr_sp, fluent::parse_label_prev_attr), Some(InnerAttrForbiddenReason::InCodeBlock) | None => { self.dcx().struct_span_err(attr_sp, fluent::parse_inner_attr_not_permitted) } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index aed5e11133bc..a9cf26d991c7 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -34,8 +34,8 @@ use rustc_ast::{ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, FatalError, - PResult, + pluralize, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, + ErrorGuaranteed, FatalError, PErr, PResult, }; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; @@ -896,7 +896,7 @@ impl<'a> Parser<'a> { let struct_expr = snapshot.parse_expr_struct(None, path, false); let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No); return Some(match (struct_expr, block_tail) { - (Ok(expr), Err(mut err)) => { + (Ok(expr), Err(err)) => { // We have encountered the following: // fn foo() -> Foo { // field: value, @@ -1049,9 +1049,9 @@ impl<'a> Parser<'a> { &mut self, segment: &PathSegment, end: &[&TokenKind], - ) -> bool { + ) -> Option { if !self.may_recover() { - return false; + return None; } // This function is intended to be invoked after parsing a path segment where there are two @@ -1086,7 +1086,7 @@ impl<'a> Parser<'a> { parsed_angle_bracket_args, ); if !parsed_angle_bracket_args { - return false; + return None; } // Keep the span at the start so we can highlight the sequence of `>` characters to be @@ -1124,7 +1124,7 @@ impl<'a> Parser<'a> { number_of_gt, number_of_shr, ); if number_of_gt < 1 && number_of_shr < 1 { - return false; + return None; } // Finally, double check that we have our end token as otherwise this is the @@ -1139,10 +1139,9 @@ impl<'a> Parser<'a> { let span = lo.until(self.token.span); let num_extra_brackets = number_of_gt + number_of_shr * 2; - self.dcx().emit_err(UnmatchedAngleBrackets { span, num_extra_brackets }); - return true; + return Some(self.dcx().emit_err(UnmatchedAngleBrackets { span, num_extra_brackets })); } - false + None } /// Check if a method call with an intended turbofish has been written without surrounding @@ -1212,29 +1211,32 @@ impl<'a> Parser<'a> { match x { Ok((_, _, false)) => { if self.eat(&token::Gt) { + // We made sense of it. Improve the error message. e.span_suggestion_verbose( binop.span.shrink_to_lo(), fluent::parse_sugg_turbofish_syntax, "::", Applicability::MaybeIncorrect, - ) - .emit(); + ); match self.parse_expr() { Ok(_) => { + // The subsequent expression is valid. Mark + // `expr` as erroneous and emit `e` now, but + // return `Ok` so parsing can continue. + e.emit(); *expr = self.mk_expr_err(expr.span.to(self.prev_token.span)); return Ok(()); } Err(err) => { - *expr = self.mk_expr_err(expr.span); err.cancel(); } } } } + Ok((_, _, true)) => {} Err(err) => { err.cancel(); } - _ => {} } } Err(e) @@ -2041,17 +2043,12 @@ impl<'a> Parser<'a> { &mut self, delim: Delimiter, lo: Span, - result: PResult<'a, P>, + err: PErr<'a>, ) -> P { - match result { - Ok(x) => x, - Err(mut err) => { - err.emit(); - // Recover from parse error, callers expect the closing delim to be consumed. - self.consume_block(delim, ConsumeClosingDelim::Yes); - self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err) - } - } + err.emit(); + // Recover from parse error, callers expect the closing delim to be consumed. + self.consume_block(delim, ConsumeClosingDelim::Yes); + self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err) } /// Eats tokens until we can be relatively sure we reached the end of the @@ -2470,7 +2467,7 @@ impl<'a> Parser<'a> { return Ok(true); // Continue } } - Err(mut err) => { + Err(err) => { args.push(arg); // We will emit a more generic error later. err.delay_as_bug(); @@ -2848,15 +2845,16 @@ impl<'a> Parser<'a> { let label = self.eat_label().expect("just checked if a label exists"); self.bump(); // eat `:` let span = label.ident.span.to(self.prev_token.span); - let mut err = self.dcx().struct_span_err(span, "block label not supported here"); - err.span_label(span, "not supported here"); - err.tool_only_span_suggestion( - label.ident.span.until(self.token.span), - "remove this block label", - "", - Applicability::MachineApplicable, - ); - err.emit(); + self.dcx() + .struct_span_err(span, "block label not supported here") + .span_label_mv(span, "not supported here") + .tool_only_span_suggestion_mv( + label.ident.span.until(self.token.span), + "remove this block label", + "", + Applicability::MachineApplicable, + ) + .emit(); true } @@ -2946,7 +2944,7 @@ impl<'a> Parser<'a> { } pub fn recover_diff_marker(&mut self) { - if let Err(mut err) = self.err_diff_marker() { + if let Err(err) = self.err_diff_marker() { err.emit(); FatalError.raise(); } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0b24e7841263..db777266b59d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -127,7 +127,7 @@ impl<'a> Parser<'a> { fn parse_expr_catch_underscore(&mut self, restrictions: Restrictions) -> PResult<'a, P> { match self.parse_expr_res(restrictions, None) { Ok(expr) => Ok(expr), - Err(mut err) => match self.token.ident() { + Err(err) => match self.token.ident() { Some((Ident { name: kw::Underscore, .. }, false)) if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) => { @@ -1272,15 +1272,13 @@ impl<'a> Parser<'a> { }; let open_paren = self.token.span; - let mut seq = self + let seq = self .parse_expr_paren_seq() .map(|args| self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args))); - if let Some(expr) = - self.maybe_recover_struct_lit_bad_delims(lo, open_paren, &mut seq, snapshot) - { - return expr; + match self.maybe_recover_struct_lit_bad_delims(lo, open_paren, seq, snapshot) { + Ok(expr) => expr, + Err(err) => self.recover_seq_parse_error(Delimiter::Parenthesis, lo, err), } - self.recover_seq_parse_error(Delimiter::Parenthesis, lo, seq) } /// If we encounter a parser state that looks like the user has written a `struct` literal with @@ -1290,14 +1288,11 @@ impl<'a> Parser<'a> { &mut self, lo: Span, open_paren: Span, - seq: &mut PResult<'a, P>, + seq: PResult<'a, P>, snapshot: Option<(SnapshotParser<'a>, ExprKind)>, - ) -> Option> { - if !self.may_recover() { - return None; - } - match (seq.as_mut(), snapshot) { - (Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => { + ) -> PResult<'a, P> { + match (self.may_recover(), seq, snapshot) { + (true, Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => { snapshot.bump(); // `(` match snapshot.parse_struct_fields(path.clone(), false, Delimiter::Parenthesis) { Ok((fields, ..)) @@ -1315,11 +1310,13 @@ impl<'a> Parser<'a> { if !fields.is_empty() && // `token.kind` should not be compared here. // This is because the `snapshot.token.kind` is treated as the same as - // that of the open delim in `TokenTreesReader::parse_token_tree`, even if they are different. + // that of the open delim in `TokenTreesReader::parse_token_tree`, even + // if they are different. self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")") { - let mut replacement_err = - self.dcx().create_err(errors::ParenthesesWithStructFields { + err.cancel(); + self.dcx() + .create_err(errors::ParenthesesWithStructFields { span, r#type: path, braces_for_struct: errors::BracesForStructLiteral { @@ -1332,23 +1329,22 @@ impl<'a> Parser<'a> { .map(|field| field.span.until(field.expr.span)) .collect(), }, - }); - replacement_err.emit(); - - let old_err = mem::replace(err, replacement_err); - old_err.cancel(); + }) + .emit(); } else { err.emit(); } - return Some(self.mk_expr_err(span)); + Ok(self.mk_expr_err(span)) + } + Ok(_) => Err(err), + Err(err2) => { + err2.cancel(); + Err(err) } - Ok(_) => {} - Err(err) => err.cancel(), } } - _ => {} + (_, seq, _) => seq, } - None } /// Parse an indexing expression `expr[...]`. @@ -1552,7 +1548,7 @@ impl<'a> Parser<'a> { ) { Ok(x) => x, Err(err) => { - return Ok(self.recover_seq_parse_error(Delimiter::Parenthesis, lo, Err(err))); + return Ok(self.recover_seq_parse_error(Delimiter::Parenthesis, lo, err)); } }; let kind = if es.len() == 1 && !trailing_comma { @@ -1756,9 +1752,8 @@ impl<'a> Parser<'a> { mk_lit_char: impl FnOnce(Symbol, Span) -> L, err: impl FnOnce(&Self) -> DiagnosticBuilder<'a>, ) -> L { - if let Some(mut diag) = self.dcx().steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar) - { - diag.span_suggestion_verbose( + if let Some(diag) = self.dcx().steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar) { + diag.span_suggestion_verbose_mv( lifetime.span.shrink_to_hi(), "add `'` to close the char literal", "'", @@ -1767,7 +1762,7 @@ impl<'a> Parser<'a> { .emit(); } else { err(self) - .span_suggestion_verbose( + .span_suggestion_verbose_mv( lifetime.span.shrink_to_hi(), "add `'` to close the char literal", "'", @@ -2489,7 +2484,7 @@ impl<'a> Parser<'a> { } ExprKind::Block(_, None) => { this.dcx().emit_err(errors::IfExpressionMissingCondition { - if_span: lo.shrink_to_hi(), + if_span: lo.with_neighbor(cond.span).shrink_to_hi(), block_span: self.sess.source_map().start_point(cond_span), }); std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi())) @@ -2903,7 +2898,7 @@ impl<'a> Parser<'a> { while self.token != token::CloseDelim(Delimiter::Brace) { match self.parse_arm() { Ok(arm) => arms.push(arm), - Err(mut e) => { + Err(e) => { // Recover by skipping to the end of the block. e.emit(); self.recover_stmt(); @@ -3437,7 +3432,7 @@ impl<'a> Parser<'a> { } match self.parse_expr() { Ok(e) => base = ast::StructRest::Base(e), - Err(mut e) if recover => { + Err(e) if recover => { e.emit(); self.recover_stmt(); } @@ -3735,7 +3730,7 @@ impl<'a> Parser<'a> { } pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind) -> P { - P(Expr { kind, span, attrs: AttrVec::new(), id: DUMMY_NODE_ID, tokens: None }) + self.mk_expr_with_attrs(span, kind, AttrVec::new()) } pub(super) fn mk_expr_err(&self, span: Span) -> P { diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 7e243c1c32a9..66aa8cbcda4a 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -77,7 +77,6 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ); } - err.emit(); return Err(err); } } @@ -141,17 +140,18 @@ impl<'a> Parser<'a> { // Parse optional const generics default value. let default = if self.eat(&token::Eq) { Some(self.parse_const_arg()?) } else { None }; - let mut err = self.dcx().struct_span_err( - mistyped_const_ident.span, - format!("`const` keyword was mistyped as `{}`", mistyped_const_ident.as_str()), - ); - err.span_suggestion_verbose( - mistyped_const_ident.span, - "use the `const` keyword", - kw::Const.as_str(), - Applicability::MachineApplicable, - ); - err.emit(); + self.dcx() + .struct_span_err( + mistyped_const_ident.span, + format!("`const` keyword was mistyped as `{}`", mistyped_const_ident.as_str()), + ) + .span_suggestion_verbose_mv( + mistyped_const_ident.span, + "use the `const` keyword", + kw::Const.as_str(), + Applicability::MachineApplicable, + ) + .emit(); Ok(GenericParam { ident, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 0ac0b678abac..fed3c83a81d1 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -739,11 +739,14 @@ impl<'a> Parser<'a> { break; } Ok(Some(item)) => items.extend(item), - Err(mut err) => { + Err(err) => { self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes); - err.span_label(open_brace_span, "while parsing this item list starting here") - .span_label(self.prev_token.span, "the item list ends here") - .emit(); + err.span_label_mv( + open_brace_span, + "while parsing this item list starting here", + ) + .span_label_mv(self.prev_token.span, "the item list ends here") + .emit(); break; } } @@ -762,8 +765,8 @@ impl<'a> Parser<'a> { E0584, "found a documentation comment that doesn't document anything", ) - .span_label(self.token.span, "this doc comment doesn't document anything") - .help( + .span_label_mv(self.token.span, "this doc comment doesn't document anything") + .help_mv( "doc comments must come before what they document, if a comment was \ intended use `//`", ) @@ -1106,8 +1109,7 @@ impl<'a> Parser<'a> { && self.token.is_keyword(kw::Unsafe) && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Brace)) { - let mut err = self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err(); - err.emit(); + self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err().emit(); unsafety = Unsafe::Yes(self.token.span); self.eat_keyword(kw::Unsafe); } @@ -1198,7 +1200,7 @@ impl<'a> Parser<'a> { defaultness: Defaultness, ) -> PResult<'a, ItemInfo> { let impl_span = self.token.span; - let mut err = self.expected_ident_found_err(); + let err = self.expected_ident_found_err(); // Only try to recover if this is implementing a trait for a type let mut impl_info = match self.parse_item_impl(attrs, defaultness) { @@ -1216,7 +1218,7 @@ impl<'a> Parser<'a> { let before_trait = trai.path.span.shrink_to_lo(); let const_up_to_impl = const_span.with_hi(impl_span.lo()); - err.multipart_suggestion( + err.multipart_suggestion_mv( "you might have meant to write a const trait impl", vec![(const_up_to_impl, "".to_owned()), (before_trait, "const ".to_owned())], Applicability::MaybeIncorrect, @@ -1454,8 +1456,8 @@ impl<'a> Parser<'a> { let ident = this.parse_field_ident("enum", vlo)?; if this.token == token::Not { - if let Err(mut err) = this.unexpected::<()>() { - err.note(fluent::parse_macro_expands_to_enum_variant).emit(); + if let Err(err) = this.unexpected::<()>() { + err.note_mv(fluent::parse_macro_expands_to_enum_variant).emit(); } this.bump(); @@ -1791,37 +1793,36 @@ impl<'a> Parser<'a> { } _ => { let sp = self.prev_token.span.shrink_to_hi(); - let mut err = self.dcx().struct_span_err( - sp, - format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)), - ); + let msg = + format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)); // Try to recover extra trailing angle brackets - let mut recovered = false; if let TyKind::Path(_, Path { segments, .. }) = &a_var.ty.kind { if let Some(last_segment) = segments.last() { - recovered = self.check_trailing_angle_brackets( + let guar = self.check_trailing_angle_brackets( last_segment, &[&token::Comma, &token::CloseDelim(Delimiter::Brace)], ); - if recovered { + if let Some(_guar) = guar { // Handle a case like `Vec>,` where we can continue parsing fields // after the comma self.eat(&token::Comma); - // `check_trailing_angle_brackets` already emitted a nicer error - // NOTE(eddyb) this was `.cancel()`, but `err` - // gets returned, so we can't fully defuse it. - err.delay_as_bug(); + + // `check_trailing_angle_brackets` already emitted a nicer error, as + // proven by the presence of `_guar`. We can continue parsing. + return Ok(a_var); } } } + let mut err = self.dcx().struct_span_err(sp, msg); + if self.token.is_ident() || (self.token.kind == TokenKind::Pound && (self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Bracket)))) { - // This is likely another field, TokenKind::Pound is used for `#[..]` attribute for next field, - // emit the diagnostic and keep going + // This is likely another field, TokenKind::Pound is used for `#[..]` + // attribute for next field. Emit the diagnostic and continue parsing. err.span_suggestion( sp, "try adding a comma", @@ -1829,14 +1830,6 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ); err.emit(); - recovered = true; - } - - if recovered { - // Make sure an error was emitted (either by recovering an angle bracket, - // or by finding an identifier as the next token), since we're - // going to continue parsing - assert!(self.dcx().has_errors().is_some()); } else { return Err(err); } @@ -1846,7 +1839,7 @@ impl<'a> Parser<'a> { } fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> { - if let Err(mut err) = self.expect(&token::Colon) { + if let Err(err) = self.expect(&token::Colon) { let sm = self.sess.source_map(); let eq_typo = self.token.kind == token::Eq && self.look_ahead(1, |t| t.is_path_start()); let semi_typo = self.token.kind == token::Semi @@ -1862,7 +1855,7 @@ impl<'a> Parser<'a> { if eq_typo || semi_typo { self.bump(); // Gracefully handle small typos. - err.span_suggestion_short( + err.span_suggestion_short_mv( self.prev_token.span, "field names and their types are separated with `:`", ":", @@ -1938,15 +1931,14 @@ impl<'a> Parser<'a> { Case::Insensitive, ) { Ok(_) => { - let mut err = self.dcx().struct_span_err( + self.dcx().struct_span_err( lo.to(self.prev_token.span), format!("functions are not allowed in {adt_ty} definitions"), - ); - err.help( + ) + .help_mv( "unlike in C++, Java, and C#, functions are declared in `impl` blocks", - ); - err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information"); - err + ) + .help_mv("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information") } Err(err) => { err.cancel(); @@ -1956,14 +1948,13 @@ impl<'a> Parser<'a> { } } else if self.eat_keyword(kw::Struct) { match self.parse_item_struct() { - Ok((ident, _)) => { - let mut err = self.dcx().struct_span_err( + Ok((ident, _)) => self + .dcx() + .struct_span_err( lo.with_hi(ident.span.hi()), format!("structs are not allowed in {adt_ty} definitions"), - ); - err.help("consider creating a new `struct` definition instead of nesting"); - err - } + ) + .help_mv("consider creating a new `struct` definition instead of nesting"), Err(err) => { err.cancel(); self.restore_snapshot(snapshot); @@ -2118,7 +2109,7 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); err.span_suggestion( - span.shrink_to_hi(), + span.with_neighbor(self.token.span).shrink_to_hi(), "add a semicolon", ';', Applicability::MaybeIncorrect, @@ -2598,7 +2589,7 @@ impl<'a> Parser<'a> { let (mut params, _) = self.parse_paren_comma_seq(|p| { p.recover_diff_marker(); let snapshot = p.create_snapshot_for_diagnostic(); - let param = p.parse_param_general(req_name, first_param).or_else(|mut e| { + let param = p.parse_param_general(req_name, first_param).or_else(|e| { e.emit(); let lo = p.prev_token.span; p.restore_snapshot(snapshot); @@ -2632,7 +2623,7 @@ impl<'a> Parser<'a> { let is_name_required = match this.token.kind { token::DotDotDot => false, - _ => req_name(this.token.span.edition()), + _ => req_name(this.token.span.with_neighbor(this.prev_token.span).edition()), }; let (pat, ty) = if is_name_required || this.is_named_param() { debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index b201d36455e6..c13adfb0532d 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -499,7 +499,7 @@ impl<'a> Parser<'a> { let (ident, is_raw) = self.ident_or_err(recover)?; if !is_raw && ident.is_reserved() { - let mut err = self.expected_ident_found_err(); + let err = self.expected_ident_found_err(); if recover { err.emit(); } else { @@ -847,7 +847,7 @@ impl<'a> Parser<'a> { pprust::token_to_string(&self.prev_token) ); expect_err - .span_suggestion_verbose( + .span_suggestion_verbose_mv( self.prev_token.span.shrink_to_hi().until(self.token.span), msg, " @ ", @@ -863,7 +863,7 @@ impl<'a> Parser<'a> { // Parsed successfully, therefore most probably the code only // misses a separator. expect_err - .span_suggestion_short( + .span_suggestion_short_mv( sp, format!("missing `{token_str}`"), token_str, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 7d17b1d4c4d6..00dc307ab60a 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -144,7 +144,7 @@ impl<'a> Parser<'a> { // Parse the first pattern (`p_0`). let mut first_pat = match self.parse_pat_no_top_alt(expected, syntax_loc) { Ok(pat) => pat, - Err(mut err) + Err(err) if self.token.is_reserved_ident() && !self.token.is_keyword(kw::In) && !self.token.is_keyword(kw::If) => @@ -242,7 +242,7 @@ impl<'a> Parser<'a> { Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat }) }; - let mut err = self.dcx().create_err(match syntax_loc { + let err = self.dcx().create_err(match syntax_loc { PatternLocation::LetBinding => { TopLevelOrPatternNotAllowed::LetBinding { span, sub } } @@ -252,8 +252,9 @@ impl<'a> Parser<'a> { }); if trailing_vert { err.delay_as_bug(); + } else { + err.emit(); } - err.emit(); } Ok((pat, colon)) @@ -460,9 +461,10 @@ impl<'a> Parser<'a> { super::token_descr(&self_.token) ); - let mut err = self_.dcx().struct_span_err(self_.token.span, msg); - err.span_label(self_.token.span, format!("expected {expected}")); - err + self_ + .dcx() + .struct_span_err(self_.token.span, msg) + .span_label_mv(self_.token.span, format!("expected {expected}")) }); PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit))) } else { @@ -1028,7 +1030,7 @@ impl<'a> Parser<'a> { let attrs = match self.parse_outer_attributes() { Ok(attrs) => attrs, Err(err) => { - if let Some(mut delayed) = delayed_err { + if let Some(delayed) = delayed_err { delayed.emit(); } return Err(err); @@ -1040,7 +1042,7 @@ impl<'a> Parser<'a> { if !ate_comma { let mut err = self.dcx().create_err(ExpectedCommaAfterPatternField { span: self.token.span }); - if let Some(mut delayed) = delayed_err { + if let Some(delayed) = delayed_err { delayed.emit(); } self.recover_misplaced_pattern_modifiers(&fields, &mut err); @@ -1113,14 +1115,14 @@ impl<'a> Parser<'a> { // This way we avoid "pattern missing fields" errors afterwards. // We delay this error until the end in order to have a span for a // suggested fix. - if let Some(mut delayed_err) = delayed_err { + if let Some(delayed_err) = delayed_err { delayed_err.emit(); return Err(err); } else { delayed_err = Some(err); } } else { - if let Some(mut err) = delayed_err { + if let Some(err) = delayed_err { err.emit(); } return Err(err); @@ -1132,7 +1134,7 @@ impl<'a> Parser<'a> { let field = match this.parse_pat_field(lo, attrs) { Ok(field) => Ok(field), Err(err) => { - if let Some(mut delayed_err) = delayed_err.take() { + if let Some(delayed_err) = delayed_err.take() { delayed_err.emit(); } return Err(err); diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 4253c0ae421a..5ad17a30980f 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -128,7 +128,7 @@ impl<'a> Parser<'a> { self.prev_token.span, "found single colon before projection in qualified path", ) - .span_suggestion( + .span_suggestion_mv( self.prev_token.span, "use double colon", "::", @@ -493,7 +493,7 @@ impl<'a> Parser<'a> { self.angle_bracket_nesting -= 1; Ok(args) } - Err(mut e) if self.angle_bracket_nesting > 10 => { + Err(e) if self.angle_bracket_nesting > 10 => { self.angle_bracket_nesting -= 1; // When encountering severely malformed code where there are several levels of // nested unclosed angle args (`f:: Parser<'a> { /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. // Public for rustfmt usage. pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option> { - Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|mut e| { + Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|e| { e.emit(); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); None @@ -663,7 +663,7 @@ impl<'a> Parser<'a> { match expect_result { // Recover from parser, skip type error to avoid extra errors. Ok(true) => true, - Err(mut e) => { + Err(e) => { if self.recover_colon_as_semi() { // recover_colon_as_semi has already emitted a nicer error. e.delay_as_bug(); @@ -716,7 +716,7 @@ impl<'a> Parser<'a> { _ => {} } - if let Err(mut e) = + if let Err(e) = self.check_mistyped_turbofish_with_multiple_type_params(e, expr) { if recover.no() { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 4be2c662d035..61d72857c36b 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -300,7 +300,7 @@ impl<'a> Parser<'a> { let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); let kind = self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?; - let mut err = self.dcx().create_err(errors::TransposeDynOrImpl { + let err = self.dcx().create_err(errors::TransposeDynOrImpl { span: kw.span, kw: kw.name.as_str(), sugg: errors::TransposeDynOrImplSugg { @@ -487,7 +487,7 @@ impl<'a> Parser<'a> { fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> { let elt_ty = match self.parse_ty() { Ok(ty) => ty, - Err(mut err) + Err(err) if self.look_ahead(1, |t| t.kind == token::CloseDelim(Delimiter::Bracket)) | self.look_ahead(1, |t| t.kind == token::Semi) => { @@ -1109,20 +1109,19 @@ impl<'a> Parser<'a> { lifetime_defs.append(&mut generic_params); let generic_args_span = generic_args.span(); - let mut err = self - .dcx() - .struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters"); let snippet = format!( "for<{}> ", lifetimes.iter().map(|lt| lt.ident.as_str()).intersperse(", ").collect::(), ); let before_fn_path = fn_path.span.shrink_to_lo(); - err.multipart_suggestion( - "consider using a higher-ranked trait bound instead", - vec![(generic_args_span, "".to_owned()), (before_fn_path, snippet)], - Applicability::MaybeIncorrect, - ) - .emit(); + self.dcx() + .struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters") + .multipart_suggestion_mv( + "consider using a higher-ranked trait bound instead", + vec![(generic_args_span, "".to_owned()), (before_fn_path, snippet)], + Applicability::MaybeIncorrect, + ) + .emit(); Ok(()) } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 4efb1be03bee..724d574349a8 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -29,7 +29,7 @@ pub fn check_attr(sess: &ParseSess, attr: &Attribute) { _ if let AttrArgs::Eq(..) = attr.get_normal_item().args => { // All key-value attributes are restricted to meta-item syntax. parse_meta(sess, attr) - .map_err(|mut err| { + .map_err(|err| { err.emit(); }) .ok(); @@ -139,7 +139,7 @@ pub fn check_builtin_attribute( ) { match parse_meta(sess, attr) { Ok(meta) => check_builtin_meta_item(sess, &meta, attr.style, name, template), - Err(mut err) => { + Err(err) => { err.emit(); } } @@ -208,7 +208,7 @@ fn emit_malformed_attribute( } else { sess.dcx .struct_span_err(span, error_msg) - .span_suggestions( + .span_suggestions_mv( span, if suggestions.len() == 1 { "must be of the form" diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index e886db3da296..1e1d45d6f702 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -289,10 +289,10 @@ impl<'a> Iterator for Parser<'a> { } } else { if let Some(&(_, maybe)) = self.cur.peek() { - if maybe == '?' { - self.suggest_format(); - } else { - self.suggest_positional_arg_instead_of_captured_arg(arg); + match maybe { + '?' => self.suggest_format_debug(), + '<' | '^' | '>' => self.suggest_format_align(maybe), + _ => self.suggest_positional_arg_instead_of_captured_arg(arg), } } } @@ -868,10 +868,9 @@ impl<'a> Parser<'a> { found.then_some(cur) } - fn suggest_format(&mut self) { + fn suggest_format_debug(&mut self) { if let (Some(pos), Some(_)) = (self.consume_pos('?'), self.consume_pos(':')) { let word = self.word(); - let _end = self.current_pos(); let pos = self.to_span_index(pos); self.errors.insert( 0, @@ -887,6 +886,23 @@ impl<'a> Parser<'a> { } } + fn suggest_format_align(&mut self, alignment: char) { + if let Some(pos) = self.consume_pos(alignment) { + let pos = self.to_span_index(pos); + self.errors.insert( + 0, + ParseError { + description: "expected format parameter to occur after `:`".to_owned(), + note: None, + label: format!("expected `{}` to occur after `:`", alignment).to_owned(), + span: pos.to(pos), + secondary_label: None, + suggestion: Suggestion::None, + }, + ); + } + } + fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) { if let Some(end) = self.consume_pos('.') { let byte_pos = self.to_span_index(end); diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index f4cd2fbc91fc..42e929bde2ca 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -48,7 +48,7 @@ impl DebuggerVisualizerCollector<'_> { let file = match resolve_path(&self.sess.parse_sess, visualizer_path.as_str(), attr.span) { Ok(file) => file, - Err(mut err) => { + Err(err) => { err.emit(); return; } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 9bd9dd41cf69..d934e959a417 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1040,7 +1040,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'_, G> for BreakNonLoop<'a> { // This error is redundant, we will have already emitted a // suggestion to use the label when `segment` wasn't found // (hence the `Res::Err` check). - diag.delay_as_bug(); + diag.downgrade_to_delayed_bug(); } _ => { diag.span_suggestion( diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 8fa4fa1e3848..aba08e8b5ca1 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1621,7 +1621,7 @@ impl<'tcx> Liveness<'_, 'tcx> { let from_macro = non_shorthands .iter() .find(|(_, pat_span, ident_span)| { - pat_span.ctxt() != ident_span.ctxt() && pat_span.from_expansion() + !pat_span.eq_ctxt(*ident_span) && pat_span.from_expansion() }) .map(|(_, pat_span, _)| *pat_span); let non_shorthands = non_shorthands diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs index 83210a4a5562..f1237ecf83c6 100644 --- a/compiler/rustc_pattern_analysis/src/lints.rs +++ b/compiler/rustc_pattern_analysis/src/lints.rs @@ -83,8 +83,9 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> { (0..arity).map(|_| Self { patterns: Vec::new() }).collect(); let relevant_patterns = self.patterns.iter().filter(|pat| ctor.is_covered_by(pcx, pat.ctor())); + let ctor_sub_tys = pcx.ctor_sub_tys(ctor); for pat in relevant_patterns { - let specialized = pat.specialize(pcx, ctor); + let specialized = pat.specialize(pcx, ctor, ctor_sub_tys); for (subpat, column) in specialized.iter().zip(&mut specialized_columns) { if subpat.is_or_pat() { column.patterns.extend(subpat.flatten_or_pat()) diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index db41d2824a1e..4438d20a3579 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -81,10 +81,11 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { &self, pcx: &PlaceCtxt<'_, 'p, Cx>, other_ctor: &Constructor, + ctor_sub_tys: &[Cx::Ty], ) -> SmallVec<[&'p DeconstructedPat<'p, Cx>; 2]> { let wildcard_sub_tys = || { - let tys = pcx.ctor_sub_tys(other_ctor); - tys.iter() + ctor_sub_tys + .iter() .map(|ty| DeconstructedPat::wildcard(*ty)) .map(|pat| pcx.mcx.wildcard_arena.alloc(pat) as &_) .collect() diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 68da13861aa8..16bf709881b6 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -717,7 +717,7 @@ use std::fmt; use crate::constructor::{Constructor, ConstructorSet}; use crate::pat::{DeconstructedPat, WitnessPat}; -use crate::{Captures, MatchArm, MatchCtxt, TypeCx, TypedArena}; +use crate::{Captures, MatchArm, MatchCtxt, TypeCx}; use self::ValidityConstraint::*; @@ -874,11 +874,12 @@ impl<'p, Cx: TypeCx> PatStack<'p, Cx> { &self, pcx: &PlaceCtxt<'_, 'p, Cx>, ctor: &Constructor, + ctor_sub_tys: &[Cx::Ty], ctor_is_relevant: bool, ) -> PatStack<'p, Cx> { // We pop the head pattern and push the new fields extracted from the arguments of // `self.head()`. - let mut new_pats = self.head().specialize(pcx, ctor); + let mut new_pats = self.head().specialize(pcx, ctor, ctor_sub_tys); new_pats.extend_from_slice(&self.pats[1..]); // `ctor` is relevant for this row if it is the actual constructor of this row, or if the // row has a wildcard and `ctor` is relevant for wildcards. @@ -950,11 +951,12 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> { &self, pcx: &PlaceCtxt<'_, 'p, Cx>, ctor: &Constructor, + ctor_sub_tys: &[Cx::Ty], ctor_is_relevant: bool, parent_row: usize, ) -> MatrixRow<'p, Cx> { MatrixRow { - pats: self.pats.pop_head_constructor(pcx, ctor, ctor_is_relevant), + pats: self.pats.pop_head_constructor(pcx, ctor, ctor_sub_tys, ctor_is_relevant), parent_row, is_under_guard: self.is_under_guard, useful: false, @@ -984,11 +986,13 @@ struct Matrix<'p, Cx: TypeCx> { /// each column must have the same type. Each column corresponds to a place within the /// scrutinee. rows: Vec>, - /// Stores an extra fictitious row full of wildcards. Mostly used to keep track of the type of - /// each column. This must obey the same invariants as the real rows. - wildcard_row: PatStack<'p, Cx>, + /// Track the type of each column/place. + place_ty: SmallVec<[Cx::Ty; 2]>, /// Track for each column/place whether it contains a known valid value. place_validity: SmallVec<[ValidityConstraint; 2]>, + /// Track whether the virtual wildcard row used to compute exhaustiveness is relevant. See top + /// of the file for details on relevancy. + wildcard_row_is_relevant: bool, } impl<'p, Cx: TypeCx> Matrix<'p, Cx> { @@ -1007,17 +1011,15 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { /// Build a new matrix from an iterator of `MatchArm`s. fn new( - wildcard_arena: &'p TypedArena>, arms: &[MatchArm<'p, Cx>], scrut_ty: Cx::Ty, scrut_validity: ValidityConstraint, ) -> Self { - let wild_pattern = wildcard_arena.alloc(DeconstructedPat::wildcard(scrut_ty)); - let wildcard_row = PatStack::from_pattern(wild_pattern); let mut matrix = Matrix { rows: Vec::with_capacity(arms.len()), - wildcard_row, + place_ty: smallvec![scrut_ty], place_validity: smallvec![scrut_validity], + wildcard_row_is_relevant: true, }; for (row_id, arm) in arms.iter().enumerate() { let v = MatrixRow { @@ -1032,10 +1034,10 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { } fn head_ty(&self) -> Option { - self.wildcard_row.head_opt().map(|pat| pat.ty()) + self.place_ty.first().copied() } fn column_count(&self) -> usize { - self.wildcard_row.len() + self.place_ty.len() } fn rows( @@ -1063,17 +1065,24 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { ctor: &Constructor, ctor_is_relevant: bool, ) -> Matrix<'p, Cx> { - let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor, ctor_is_relevant); - let new_validity = self.place_validity[0].specialize(ctor); - let new_place_validity = std::iter::repeat(new_validity) + let ctor_sub_tys = pcx.ctor_sub_tys(ctor); + let specialized_place_ty = + ctor_sub_tys.iter().chain(self.place_ty[1..].iter()).copied().collect(); + let ctor_sub_validity = self.place_validity[0].specialize(ctor); + let specialized_place_validity = std::iter::repeat(ctor_sub_validity) .take(ctor.arity(pcx)) .chain(self.place_validity[1..].iter().copied()) .collect(); - let mut matrix = - Matrix { rows: Vec::new(), wildcard_row, place_validity: new_place_validity }; + let mut matrix = Matrix { + rows: Vec::new(), + place_ty: specialized_place_ty, + place_validity: specialized_place_validity, + wildcard_row_is_relevant: self.wildcard_row_is_relevant && ctor_is_relevant, + }; for (i, row) in self.rows().enumerate() { if ctor.is_covered_by(pcx, row.head().ctor()) { - let new_row = row.pop_head_constructor(pcx, ctor, ctor_is_relevant, i); + let new_row = + row.pop_head_constructor(pcx, ctor, ctor_sub_tys, ctor_is_relevant, i); matrix.expand_and_push(new_row); } } @@ -1335,7 +1344,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( ) -> WitnessMatrix { debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count())); - if !matrix.wildcard_row.relevant && matrix.rows().all(|r| !r.pats.relevant) { + if !matrix.wildcard_row_is_relevant && matrix.rows().all(|r| !r.pats.relevant) { // Here we know that nothing will contribute further to exhaustiveness or usefulness. This // is purely an optimization: skipping this check doesn't affect correctness. See the top of // the file for details. @@ -1356,7 +1365,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( } // No (unguarded) rows, so the match is not exhaustive. We return a new witness unless // irrelevant. - return if matrix.wildcard_row.relevant { + return if matrix.wildcard_row_is_relevant { WitnessMatrix::unit_witness() } else { // We choose to not report anything here; see at the top for details. @@ -1466,7 +1475,7 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>( scrut_ty: Cx::Ty, scrut_validity: ValidityConstraint, ) -> UsefulnessReport<'p, Cx> { - let mut matrix = Matrix::new(cx.wildcard_arena, arms, scrut_ty, scrut_validity); + let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity); let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(cx, &mut matrix, true); let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column(); diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index d5883f528199..b5e8ac4018df 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -35,7 +35,7 @@ use rustc_middle::ty::TyCtxt; use rustc_query_system::dep_graph::SerializedDepNodeIndex; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ - get_query_incr, get_query_non_incr, HashResult, QueryCache, QueryConfig, QueryInfo, QueryMap, + get_query_incr, get_query_non_incr, CycleError, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode, QueryState, }; use rustc_query_system::HandleCycleError; @@ -144,10 +144,10 @@ where fn value_from_cycle_error( self, tcx: TyCtxt<'tcx>, - cycle: &[QueryInfo], + cycle_error: &CycleError, guar: ErrorGuaranteed, ) -> Self::Value { - (self.dynamic.value_from_cycle_error)(tcx, cycle, guar) + (self.dynamic.value_from_cycle_error)(tcx, cycle_error, guar) } #[inline(always)] diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index f131a0f75932..a827717d9bbd 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -69,7 +69,7 @@ impl QueryContext for QueryCtxt<'_> { fn next_job_id(self) -> QueryJobId { QueryJobId( NonZeroU64::new( - self.query_system.jobs.fetch_add(1, rustc_data_structures::sync::Ordering::Relaxed), + self.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed), ) .unwrap(), ) @@ -342,9 +342,9 @@ pub(crate) fn create_query_frame< hasher.finish::() }) }; - let ty_adt_id = key.ty_adt_id(); + let ty_def_id = key.ty_def_id(); - QueryStackFrame::new(description, span, def_id, def_kind, kind, ty_adt_id, hash) + QueryStackFrame::new(description, span, def_id, def_kind, kind, ty_def_id, hash) } pub(crate) fn encode_query_results<'a, 'tcx, Q>( diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 9b06823dfbaf..1f09de0ed70c 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -4,7 +4,7 @@ use rustc_data_structures::profiling::{EventId, QueryInvocationId, SelfProfilerR use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; +use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc}; use rustc_data_structures::unord::UnordMap; use rustc_index::IndexVec; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; @@ -13,7 +13,7 @@ use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; -use std::sync::atomic::Ordering::Relaxed; +use std::sync::atomic::Ordering; use super::query::DepGraphQuery; use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex}; @@ -476,7 +476,7 @@ impl DepGraph { let task_deps = &mut *task_deps; if cfg!(debug_assertions) { - data.current.total_read_count.fetch_add(1, Relaxed); + data.current.total_read_count.fetch_add(1, Ordering::Relaxed); } // As long as we only have a low number of reads we can avoid doing a hash @@ -506,7 +506,7 @@ impl DepGraph { } } } else if cfg!(debug_assertions) { - data.current.total_duplicate_read_count.fetch_add(1, Relaxed); + data.current.total_duplicate_read_count.fetch_add(1, Ordering::Relaxed); } }) } @@ -976,8 +976,8 @@ impl DepGraph { pub fn print_incremental_info(&self) { if let Some(data) = &self.data { data.current.encoder.borrow().print_incremental_info( - data.current.total_read_count.load(Relaxed), - data.current.total_duplicate_read_count.load(Relaxed), + data.current.total_read_count.load(Ordering::Relaxed), + data.current.total_duplicate_read_count.load(Ordering::Relaxed), ) } } @@ -992,7 +992,7 @@ impl DepGraph { pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex { debug_assert!(self.data.is_none()); - let index = self.virtual_dep_node_index.fetch_add(1, Relaxed); + let index = self.virtual_dep_node_index.fetch_add(1, Ordering::Relaxed); DepNodeIndex::from_u32(index) } } diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index c025fac2631a..958d9fdb52ae 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -5,7 +5,7 @@ use crate::error::HandleCycleError; use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; use crate::query::DepNodeIndex; -use crate::query::{QueryContext, QueryInfo, QueryState}; +use crate::query::{CycleError, QueryContext, QueryState}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_span::ErrorGuaranteed; @@ -57,7 +57,7 @@ pub trait QueryConfig: Copy { fn value_from_cycle_error( self, tcx: Qcx::DepContext, - cycle: &[QueryInfo], + cycle_error: &CycleError, guar: ErrorGuaranteed, ) -> Self::Value; diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 982b9ee94da9..3ef9de7da74b 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -556,7 +556,7 @@ pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) { #[inline(never)] #[cold] -pub(crate) fn report_cycle<'a>( +pub fn report_cycle<'a>( sess: &'a Session, CycleError { usage, cycle: stack }: &CycleError, ) -> DiagnosticBuilder<'a> { diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 96a0c7a033aa..9ff04c4e910d 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -4,7 +4,9 @@ pub use self::plumbing::*; mod job; #[cfg(parallel_compiler)] pub use self::job::deadlock; -pub use self::job::{print_query_stack, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap}; +pub use self::job::{ + print_query_stack, report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap, +}; mod caches; pub use self::caches::{ @@ -33,7 +35,8 @@ pub struct QueryStackFrame { span: Option, pub def_id: Option, pub def_kind: Option, - pub ty_adt_id: Option, + /// A def-id that is extracted from a `Ty` in a query key + pub ty_def_id: Option, pub dep_kind: DepKind, /// This hash is used to deterministically pick /// a query to remove cycles in the parallel compiler. @@ -49,7 +52,7 @@ impl QueryStackFrame { def_id: Option, def_kind: Option, dep_kind: DepKind, - ty_adt_id: Option, + ty_def_id: Option, _hash: impl FnOnce() -> Hash64, ) -> Self { Self { @@ -57,7 +60,7 @@ impl QueryStackFrame { span, def_id, def_kind, - ty_adt_id, + ty_def_id, dep_kind, #[cfg(parallel_compiler)] hash: _hash(), diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 51842664eeb7..c5a0cc753a8f 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -124,7 +124,7 @@ fn handle_cycle_error( query: Q, qcx: Qcx, cycle_error: &CycleError, - mut error: DiagnosticBuilder<'_>, + error: DiagnosticBuilder<'_>, ) -> Q::Value where Q: QueryConfig, @@ -134,7 +134,7 @@ where match query.handle_cycle_error() { Error => { let guar = error.emit(); - query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar) + query.value_from_cycle_error(*qcx.dep_context(), cycle_error, guar) } Fatal => { error.emit(); @@ -143,7 +143,7 @@ where } DelayBug => { let guar = error.delay_as_bug(); - query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar) + query.value_from_cycle_error(*qcx.dep_context(), cycle_error, guar) } Stash => { let guar = if let Some(root) = cycle_error.cycle.first() @@ -154,7 +154,7 @@ where } else { error.emit() }; - query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar) + query.value_from_cycle_error(*qcx.dep_context(), cycle_error, guar) } } } @@ -211,7 +211,7 @@ where } #[derive(Clone, Debug)] -pub(crate) struct CycleError { +pub struct CycleError { /// The query and related span that uses the cycle. pub usage: Option<(Span, QueryStackFrame)>, pub cycle: Vec, diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs index 4f1c182cdb8e..133904f59af1 100644 --- a/compiler/rustc_query_system/src/values.rs +++ b/compiler/rustc_query_system/src/values.rs @@ -1,20 +1,21 @@ use rustc_span::ErrorGuaranteed; use crate::dep_graph::DepContext; -use crate::query::QueryInfo; +use crate::query::CycleError; pub trait Value: Sized { - fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self; + fn from_cycle_error(tcx: Tcx, cycle_error: &CycleError, guar: ErrorGuaranteed) -> Self; } impl Value for T { - default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> T { + default fn from_cycle_error(tcx: Tcx, cycle_error: &CycleError, _guar: ErrorGuaranteed) -> T { tcx.sess().dcx().abort_if_errors(); // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's // non-trivial to define it earlier. panic!( - "<{} as Value>::from_cycle_error called without errors: {cycle:#?}", - std::any::type_name::() + "<{} as Value>::from_cycle_error called without errors: {:#?}", + std::any::type_name::(), + cycle_error.cycle, ); } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 4e1fda5479c8..e176b8b4043c 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -818,7 +818,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r .dcx() .struct_span_err(item.span, "`extern crate self;` requires renaming") - .span_suggestion( + .span_suggestion_mv( item.span, "rename the `self` crate to be able to import it", "extern crate self as name;", @@ -999,7 +999,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let msg = format!("`{name}` is already in scope"); let note = "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; - self.r.dcx().struct_span_err(span, msg).note(note).emit(); + self.r.dcx().struct_span_err(span, msg).note_mv(note).emit(); } } @@ -1110,10 +1110,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let msg = "`#[macro_escape]` is a deprecated synonym for `#[macro_use]`"; let mut err = self.r.dcx().struct_span_warn(attr.span, msg); if let ast::AttrStyle::Inner = attr.style { - err.help("try an outer attribute: `#[macro_use]`").emit(); - } else { - err.emit(); + err.help("try an outer attribute: `#[macro_use]`"); } + err.emit(); } else if !attr.has_name(sym::macro_use) { continue; } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c1cb20f6bb09..57f23200e795 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -944,16 +944,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { trait_item_span, trait_path, } => { - let mut err = self.dcx().struct_span_err_with_code( + self.dcx().struct_span_err( span, format!( "item `{name}` is an associated {kind}, which doesn't match its trait `{trait_path}`", ), - code, - ); - err.span_label(span, "does not match trait"); - err.span_label(trait_item_span, "item in trait"); - err + ) + .code_mv(code) + .span_label_mv(span, "does not match trait") + .span_label_mv(trait_item_span, "item in trait") } ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self .dcx() diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 972976622002..c5bd7ffa038c 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1233,7 +1233,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ); } else { if ns == TypeNS { - let mut err = if crate_private_reexport { + let err = if crate_private_reexport { self.dcx().create_err(CannotBeReexportedCratePublicNS { span: import.span, ident, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index a82f7bdfbf3f..059ccaebc820 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2600,7 +2600,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { E0637, "`'_` cannot be used here" ) - .span_label(param.ident.span, "`'_` is a reserved lifetime name") + .span_label_mv(param.ident.span, "`'_` is a reserved lifetime name") .emit(); // Record lifetime res, so lowering knows there is something fishy. self.record_lifetime_param(param.id, LifetimeRes::Error); @@ -2615,7 +2615,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { "invalid lifetime parameter name: `{}`", param.ident, ) - .span_label(param.ident.span, "'static is a reserved lifetime name") + .span_label_mv(param.ident.span, "'static is a reserved lifetime name") .emit(); // Record lifetime res, so lowering knows there is something fishy. self.record_lifetime_param(param.id, LifetimeRes::Error); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 0fe606cacf52..a36d1377ab5f 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -429,8 +429,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let base_error = self.make_base_error(path, span, source, res); let code = source.error_code(res.is_some()); - let mut err = - self.r.dcx().struct_span_err_with_code(base_error.span, base_error.msg.clone(), code); + let mut err = self.r.dcx().struct_span_err(base_error.span, base_error.msg.clone()); + err.code(code); self.suggest_at_operator_in_slice_pat_with_range(&mut err, path); self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span); @@ -1755,11 +1755,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .filter_map(|item| { // Only assoc fns that return `Self` let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder(); - let ret_ty = fn_sig.output(); - let ret_ty = self - .r - .tcx - .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), ret_ty); + // Don't normalize the return type, because that can cause cycle errors. + let ret_ty = fn_sig.output().skip_binder(); let ty::Adt(def, _args) = ret_ty.kind() else { return None; }; @@ -2606,25 +2603,23 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ) { debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime); let mut err = if let Some(outer) = outer_lifetime_ref { - let mut err = struct_span_err!( + struct_span_err!( self.r.dcx(), lifetime_ref.ident.span, E0401, "can't use generic parameters from outer item", - ); - err.span_label(lifetime_ref.ident.span, "use of generic parameter from outer item"); - err.span_label(outer.span, "lifetime parameter from outer item"); - err + ) + .span_label_mv(lifetime_ref.ident.span, "use of generic parameter from outer item") + .span_label_mv(outer.span, "lifetime parameter from outer item") } else { - let mut err = struct_span_err!( + struct_span_err!( self.r.dcx(), lifetime_ref.ident.span, E0261, "use of undeclared lifetime name `{}`", lifetime_ref.ident - ); - err.span_label(lifetime_ref.ident.span, "undeclared lifetime"); - err + ) + .span_label_mv(lifetime_ref.ident.span, "undeclared lifetime") }; self.suggest_introducing_lifetime( &mut err, @@ -3287,16 +3282,16 @@ fn mk_where_bound_predicate( /// Report lifetime/lifetime shadowing as an error. pub(super) fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) { - let mut err = struct_span_err!( + struct_span_err!( sess.dcx(), shadower.span, E0496, "lifetime name `{}` shadows a lifetime name that is already in scope", orig.name, - ); - err.span_label(orig.span, "first declared here"); - err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name)); - err.emit(); + ) + .span_label_mv(orig.span, "first declared here") + .span_label_mv(shadower.span, format!("lifetime `{}` already in scope", orig.name)) + .emit(); } struct LifetimeFinder<'ast> { @@ -3322,11 +3317,12 @@ impl<'ast> Visitor<'ast> for LifetimeFinder<'ast> { pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) { let name = shadower.name; let shadower = shadower.span; - let mut err = sess.dcx().struct_span_warn( - shadower, - format!("label name `{name}` shadows a label name that is already in scope"), - ); - err.span_label(orig, "first declared here"); - err.span_label(shadower, format!("label `{name}` already in scope")); - err.emit(); + sess.dcx() + .struct_span_warn( + shadower, + format!("label name `{name}` shadows a label name that is already in scope"), + ) + .span_label_mv(orig, "first declared here") + .span_label_mv(shadower, format!("label `{name}` already in scope")) + .emit(); } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 0f7294cdad09..fc55481cb015 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -128,7 +128,7 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { let msg = format!("{} `{}` was already registered", "tool", ident); tcx.dcx() .struct_span_err(ident.span, msg) - .span_label(old_ident.span, "already registered here") + .span_label_mv(old_ident.span, "already registered here") .emit(); } } @@ -137,7 +137,7 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { let span = nested_meta.span(); tcx.dcx() .struct_span_err(span, msg) - .span_label(span, "not an identifier") + .span_label_mv(span, "not an identifier") .emit(); } } @@ -576,10 +576,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str }); } - let mut err = self.dcx().create_err(err); - err.span_label(path.span, format!("not {article} {expected}")); - - err.emit(); + self.dcx() + .create_err(err) + .span_label_mv(path.span, format!("not {article} {expected}")) + .emit(); return Ok((self.dummy_ext(kind), Res::Err)); } @@ -830,7 +830,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { expected, ident, }); - self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident, krate); err.emit(); } @@ -955,7 +954,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { E0773, "attempted to define built-in macro more than once" ) - .span_note(span, "previously defined here") + .span_note_mv(span, "previously defined here") .emit(); } } diff --git a/compiler/rustc_serialize/tests/opaque.rs b/compiler/rustc_serialize/tests/opaque.rs index 861091688bb2..45ff85f38d2b 100644 --- a/compiler/rustc_serialize/tests/opaque.rs +++ b/compiler/rustc_serialize/tests/opaque.rs @@ -1,12 +1,12 @@ #![allow(rustc::internal)] -use rustc_macros::{Decodable, Encodable}; -use rustc_serialize::opaque::{MemDecoder, FileEncoder}; +use rustc_macros::{Decodable_Generic, Encodable_Generic}; +use rustc_serialize::opaque::{FileEncoder, MemDecoder}; use rustc_serialize::{Decodable, Encodable}; use std::fmt::Debug; use std::fs; -#[derive(PartialEq, Clone, Debug, Encodable, Decodable)] +#[derive(PartialEq, Clone, Debug, Encodable_Generic, Decodable_Generic)] struct Struct { a: (), b: u8, @@ -209,7 +209,7 @@ fn test_struct() { }]); } -#[derive(PartialEq, Clone, Debug, Encodable, Decodable)] +#[derive(PartialEq, Clone, Debug, Encodable_Generic, Decodable_Generic)] enum Enum { Variant1, Variant2(usize, u32), @@ -258,7 +258,7 @@ fn test_tuples() { #[test] fn test_unit_like_struct() { - #[derive(Encodable, Decodable, PartialEq, Debug)] + #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)] struct UnitLikeStruct; check_round_trip(vec![UnitLikeStruct]); @@ -266,7 +266,7 @@ fn test_unit_like_struct() { #[test] fn test_box() { - #[derive(Encodable, Decodable, PartialEq, Debug)] + #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)] struct A { foo: Box<[bool]>, } @@ -279,12 +279,12 @@ fn test_box() { fn test_cell() { use std::cell::{Cell, RefCell}; - #[derive(Encodable, Decodable, PartialEq, Debug)] + #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)] struct A { baz: isize, } - #[derive(Encodable, Decodable, PartialEq, Debug)] + #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)] struct B { foo: Cell, bar: RefCell, diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 12d8293ecd2f..61796d7a6caf 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1146,7 +1146,6 @@ impl UnstableOptions { DiagCtxtFlags { can_emit_warnings, treat_err_as_bug: self.treat_err_as_bug, - dont_buffer_diagnostics: self.dont_buffer_diagnostics, macro_backtrace: self.macro_backtrace, deduplicate_diagnostics: self.deduplicate_diagnostics, track_diagnostics: self.track_diagnostics, diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 758c31224045..8baa5d892a5c 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -18,10 +18,9 @@ pub struct FeatureGateError { impl<'a> IntoDiagnostic<'a> for FeatureGateError { #[track_caller] fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a> { - let mut diag = DiagnosticBuilder::new(dcx, level, self.explain); - diag.span(self.span); - diag.code(error_code!(E0658)); - diag + DiagnosticBuilder::new(dcx, level, self.explain) + .span_mv(self.span) + .code_mv(error_code!(E0658)) } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 842bf1d60f66..c97b18ebd66a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1553,9 +1553,6 @@ options! { dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], "in dep-info output, omit targets for tracking dependencies of the dep-info files \ themselves (default: no)"), - dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED], - "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \ - (default: no)"), dual_proc_macros: bool = (false, parse_bool, [TRACKED], "load proc macros for both target and host, but only link to the target (default: no)"), dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], @@ -1844,6 +1841,8 @@ written to standard error output)"), query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"), share_generics: Option = (None, parse_opt_bool, [TRACKED], "make the current crate share its generic instantiations"), + shell_argfiles: bool = (false, parse_bool, [UNTRACKED], + "allow argument files to be specified with POSIX \"shell-style\" argument quoting"), show_span: Option = (None, parse_opt_string, [TRACKED], "show spans for compiler debugging (expr|pat|ty)"), simulate_remapped_rust_src_base: Option = (None, parse_opt_pathbuf, [TRACKED], @@ -1960,6 +1959,8 @@ written to standard error output)"), "adds unstable command line options to rustc interface (default: no)"), use_ctors_section: Option = (None, parse_opt_bool, [TRACKED], "use legacy .ctors section for initializers rather than .init_array"), + use_sync_unwind: Option = (None, parse_opt_bool, [TRACKED], + "Generate sync unwind tables instead of async unwind tables (default: no)"), validate_mir: bool = (false, parse_bool, [UNTRACKED], "validate MIR after each transformation"), #[rustc_lint_opt_deny_field_access("use `Session::verbose_internals` instead of this field")] diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ce166ae352fd..720599f60954 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -14,9 +14,7 @@ use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::jobserver::{self, Client}; use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; -use rustc_data_structures::sync::{ - AtomicU64, DynSend, DynSync, Lock, Lrc, OneThread, Ordering::SeqCst, -}; +use rustc_data_structures::sync::{AtomicU64, DynSend, DynSync, Lock, Lrc, OneThread}; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use rustc_errors::emitter::{DynEmitter, HumanEmitter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; @@ -44,7 +42,7 @@ use std::fmt; use std::ops::{Div, Mul}; use std::path::{Path, PathBuf}; use std::str::FromStr; -use std::sync::{atomic::AtomicBool, Arc}; +use std::sync::{atomic::AtomicBool, atomic::Ordering::SeqCst, Arc}; struct OptimizationFuel { /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`. @@ -1491,7 +1489,10 @@ impl EarlyDiagCtxt { jobserver::initialize_checked(|err| { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - self.dcx.struct_warn(err).note("the build environment is likely misconfigured").emit() + self.dcx + .struct_warn(err) + .note_mv("the build environment is likely misconfigured") + .emit() }); } } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 9f1db227a7ce..0c811d7dff1d 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -1,4 +1,4 @@ -use crate::{HashStableContext, Symbol}; +use crate::{HashStableContext, SpanDecoder, SpanEncoder, Symbol}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{ Hash64, HashStable, StableHasher, StableOrd, ToStableHashKey, @@ -7,7 +7,7 @@ use rustc_data_structures::unhash::Unhasher; use rustc_data_structures::AtomicRef; use rustc_index::Idx; use rustc_macros::HashStable_Generic; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use rustc_serialize::{Decodable, Encodable}; use std::fmt; use std::hash::{BuildHasherDefault, Hash, Hasher}; @@ -48,20 +48,6 @@ impl fmt::Display for CrateNum { } } -/// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx. -/// Therefore, make sure to include the context when encode a `CrateNum`. -impl Encodable for CrateNum { - default fn encode(&self, s: &mut E) { - s.emit_u32(self.as_u32()); - } -} - -impl Decodable for CrateNum { - default fn decode(d: &mut D) -> CrateNum { - CrateNum::from_u32(d.read_u32()) - } -} - /// A `DefPathHash` is a fixed-size representation of a `DefPath` that is /// stable across crate and compilation session boundaries. It consists of two /// separate 64-bit hashes. The first uniquely identifies the crate this @@ -227,18 +213,6 @@ rustc_index::newtype_index! { } } -impl Encodable for DefIndex { - default fn encode(&self, _: &mut E) { - panic!("cannot encode `DefIndex` with `{}`", std::any::type_name::()); - } -} - -impl Decodable for DefIndex { - default fn decode(_: &mut D) -> DefIndex { - panic!("cannot decode `DefIndex` with `{}`", std::any::type_name::()); - } -} - /// A `DefId` identifies a particular *definition*, by combining a crate /// index and a def index. /// @@ -354,19 +328,6 @@ impl From for DefId { } } -impl Encodable for DefId { - default fn encode(&self, s: &mut E) { - self.krate.encode(s); - self.index.encode(s); - } -} - -impl Decodable for DefId { - default fn decode(d: &mut D) -> DefId { - DefId { krate: Decodable::decode(d), index: Decodable::decode(d) } - } -} - pub fn default_def_id_debug(def_id: DefId, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DefId").field("krate", &def_id.krate).field("index", &def_id.index).finish() } @@ -430,13 +391,13 @@ impl fmt::Debug for LocalDefId { } } -impl Encodable for LocalDefId { +impl Encodable for LocalDefId { fn encode(&self, s: &mut E) { self.to_def_id().encode(s); } } -impl Decodable for LocalDefId { +impl Decodable for LocalDefId { fn decode(d: &mut D) -> LocalDefId { DefId::decode(d).expect_local() } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index b717229b68df..d03965b539c8 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -27,7 +27,7 @@ use crate::def_id::{CrateNum, DefId, StableCrateId, CRATE_DEF_ID, LOCAL_CRATE}; use crate::edition::Edition; use crate::symbol::{kw, sym, Symbol}; -use crate::{with_session_globals, HashStableContext, Span, DUMMY_SP}; +use crate::{with_session_globals, HashStableContext, Span, SpanDecoder, SpanEncoder, DUMMY_SP}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{Hash64, HashStable, HashingControls, StableHasher}; @@ -295,11 +295,13 @@ impl ExpnId { pub fn expansion_cause(mut self) -> Option { let mut last_macro = None; loop { + // Fast path to avoid locking. + if self == ExpnId::root() { + break; + } let expn_data = self.expn_data(); // Stop going up the backtrace once include! is encountered - if expn_data.is_root() - || expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) - { + if expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) { break; } self = expn_data.call_site.ctxt().outer_expn(); @@ -433,7 +435,7 @@ impl HygieneData { fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> { let mut marks = Vec::new(); - while ctxt != SyntaxContext::root() { + while !ctxt.is_root() { debug!("marks: getting parent of {:?}", ctxt); marks.push(self.outer_mark(ctxt)); ctxt = self.parent_ctxt(ctxt); @@ -443,18 +445,46 @@ impl HygieneData { } fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span { + let orig_span = span; debug!("walk_chain({:?}, {:?})", span, to); debug!("walk_chain: span ctxt = {:?}", span.ctxt()); - while span.from_expansion() && span.ctxt() != to { + while span.ctxt() != to && span.from_expansion() { let outer_expn = self.outer_expn(span.ctxt()); debug!("walk_chain({:?}): outer_expn={:?}", span, outer_expn); let expn_data = self.expn_data(outer_expn); debug!("walk_chain({:?}): expn_data={:?}", span, expn_data); span = expn_data.call_site; } + debug!("walk_chain: for span {:?} >>> return span = {:?}", orig_span, span); span } + // We need to walk up and update return span if we meet macro instantiation to be collapsed + fn walk_chain_collapsed( + &self, + mut span: Span, + to: Span, + collapse_debuginfo_enabled: bool, + ) -> Span { + let orig_span = span; + let mut ret_span = span; + + debug!("walk_chain_collapsed({:?}, {:?})", span, to); + debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt()); + while !span.eq_ctxt(to) && span.from_expansion() { + let outer_expn = self.outer_expn(span.ctxt()); + debug!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn); + let expn_data = self.expn_data(outer_expn); + debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data); + span = expn_data.call_site; + if !collapse_debuginfo_enabled || expn_data.collapse_debuginfo { + ret_span = span; + } + } + debug!("walk_chain_collapsed: for span {:?} >>> return span = {:?}", orig_span, ret_span); + ret_span + } + fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option { let mut scope = None; while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) { @@ -571,6 +601,10 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span { HygieneData::with(|data| data.walk_chain(span, to)) } +pub fn walk_chain_collapsed(span: Span, to: Span, collapse_debuginfo_enabled: bool) -> Span { + HygieneData::with(|hdata| hdata.walk_chain_collapsed(span, to, collapse_debuginfo_enabled)) +} + pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) { // The new contexts that need updating are at the end of the list and have `$crate` as a name. let (len, to_update) = HygieneData::with(|data| { @@ -656,7 +690,7 @@ impl SyntaxContext { } /// Extend a syntax context with a given expansion and transparency. - pub(crate) fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { + pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { HygieneData::with(|data| data.apply_mark(self, expn_id, transparency)) } @@ -850,21 +884,6 @@ impl fmt::Debug for SyntaxContext { } impl Span { - /// Creates a fresh expansion with given properties. - /// Expansions are normally created by macros, but in some cases expansions are created for - /// other compiler-generated code to set per-span properties like allowed unstable features. - /// The returned span belongs to the created expansion and has the new properties, - /// but its location is inherited from the current span. - pub fn fresh_expansion(self, expn_id: LocalExpnId) -> Span { - HygieneData::with(|data| { - self.with_ctxt(data.apply_mark( - self.ctxt(), - expn_id.to_expn_id(), - Transparency::Transparent, - )) - }) - } - /// Reuses the span but adds information like the kind of the desugaring and features that are /// allowed inside this span. pub fn mark_with_reason( @@ -879,7 +898,7 @@ impl Span { ..ExpnData::default(ExpnKind::Desugaring(reason), self, edition, None, None) }; let expn_id = LocalExpnId::fresh(expn_data, ctx); - self.fresh_expansion(expn_id) + self.apply_mark(expn_id.to_expn_id(), Transparency::Transparent) } } @@ -1431,30 +1450,18 @@ fn for_all_expns_in( } } -impl Encodable for LocalExpnId { +impl Encodable for LocalExpnId { fn encode(&self, e: &mut E) { self.to_expn_id().encode(e); } } -impl Encodable for ExpnId { - default fn encode(&self, _: &mut E) { - panic!("cannot encode `ExpnId` with `{}`", std::any::type_name::()); - } -} - -impl Decodable for LocalExpnId { +impl Decodable for LocalExpnId { fn decode(d: &mut D) -> Self { ExpnId::expect_local(ExpnId::decode(d)) } } -impl Decodable for ExpnId { - default fn decode(_: &mut D) -> Self { - panic!("cannot decode `ExpnId` with `{}`", std::any::type_name::()); - } -} - pub fn raw_encode_syntax_context( ctxt: SyntaxContext, context: &HygieneEncodeContext, @@ -1466,18 +1473,6 @@ pub fn raw_encode_syntax_context( ctxt.0.encode(e); } -impl Encodable for SyntaxContext { - default fn encode(&self, _: &mut E) { - panic!("cannot encode `SyntaxContext` with `{}`", std::any::type_name::()); - } -} - -impl Decodable for SyntaxContext { - default fn decode(_: &mut D) -> Self { - panic!("cannot decode `SyntaxContext` with `{}`", std::any::type_name::()); - } -} - /// Updates the `disambiguator` field of the corresponding `ExpnData` /// such that the `Fingerprint` of the `ExpnData` does not collide with /// any other `ExpnIds`. diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 8f64eed9a870..4235293823c2 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -35,6 +35,8 @@ #![feature(rustdoc_internals)] // tidy-alphabetical-end +extern crate self as rustc_span; + #[macro_use] extern crate rustc_macros; @@ -43,6 +45,7 @@ extern crate tracing; use rustc_data_structures::{outline, AtomicRef}; use rustc_macros::HashStable_Generic; +use rustc_serialize::opaque::{FileEncoder, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; mod caching_source_map_view; @@ -58,7 +61,7 @@ pub use hygiene::{DesugaringKind, ExpnKind, MacroKind}; pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext}; use rustc_data_structures::stable_hasher::HashingControls; pub mod def_id; -use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, StableCrateId, LOCAL_CRATE}; +use def_id::{CrateNum, DefId, DefIndex, DefPathHash, LocalDefId, StableCrateId, LOCAL_CRATE}; pub mod edit_distance; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -541,10 +544,6 @@ impl Span { self.data().with_hi(hi) } #[inline] - pub fn eq_ctxt(self, other: Span) -> bool { - self.data_untracked().ctxt == other.data_untracked().ctxt - } - #[inline] pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span { self.data_untracked().with_ctxt(ctxt) } @@ -565,14 +564,7 @@ impl Span { /// Returns `true` if this span comes from any kind of macro, desugaring or inlining. #[inline] pub fn from_expansion(self) -> bool { - self.ctxt() != SyntaxContext::root() - } - - /// Returns `true` if `span` originates in a macro's expansion where debuginfo should be - /// collapsed. - pub fn in_macro_expansion_with_collapse_debuginfo(self) -> bool { - let outer_expn = self.ctxt().outer_expn_data(); - matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo + !self.ctxt().is_root() } /// Returns `true` if `span` originates in a derive-macro's expansion. @@ -654,15 +646,15 @@ impl Span { /// Returns the source span -- this is either the supplied span, or the span for /// the macro callsite that expanded to it. pub fn source_callsite(self) -> Span { - let expn_data = self.ctxt().outer_expn_data(); - if !expn_data.is_root() { expn_data.call_site.source_callsite() } else { self } + let ctxt = self.ctxt(); + if !ctxt.is_root() { ctxt.outer_expn_data().call_site.source_callsite() } else { self } } /// The `Span` for the tokens in the previous macro expansion from which `self` was generated, /// if any. pub fn parent_callsite(self) -> Option { - let expn_data = self.ctxt().outer_expn_data(); - if !expn_data.is_root() { Some(expn_data.call_site) } else { None } + let ctxt = self.ctxt(); + (!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site) } /// Walk down the expansion ancestors to find a span that's contained within `outer`. @@ -747,15 +739,14 @@ impl Span { /// else returns the `ExpnData` for the macro definition /// corresponding to the source callsite. pub fn source_callee(self) -> Option { - let expn_data = self.ctxt().outer_expn_data(); - - // Create an iterator of call site expansions - iter::successors(Some(expn_data), |expn_data| { - Some(expn_data.call_site.ctxt().outer_expn_data()) - }) - // Find the last expansion which is not root - .take_while(|expn_data| !expn_data.is_root()) - .last() + let mut ctxt = self.ctxt(); + let mut opt_expn_data = None; + while !ctxt.is_root() { + let expn_data = ctxt.outer_expn_data(); + ctxt = expn_data.call_site.ctxt(); + opt_expn_data = Some(expn_data); + } + opt_expn_data } /// Checks if a span is "internal" to a macro in which `#[unstable]` @@ -796,11 +787,12 @@ impl Span { let mut prev_span = DUMMY_SP; iter::from_fn(move || { loop { - let expn_data = self.ctxt().outer_expn_data(); - if expn_data.is_root() { + let ctxt = self.ctxt(); + if ctxt.is_root() { return None; } + let expn_data = ctxt.outer_expn_data(); let is_recursive = expn_data.call_site.source_equal(prev_span); prev_span = self; @@ -826,6 +818,39 @@ impl Span { ) } + /// Prepare two spans to a combine operation like `to` or `between`. + /// FIXME: consider using declarative macro metavariable spans for the given spans if they are + /// better suitable for combining (#119412). + fn prepare_to_combine( + a_orig: Span, + b_orig: Span, + ) -> Result<(SpanData, SpanData, Option), Span> { + let (a, b) = (a_orig.data(), b_orig.data()); + + if a.ctxt != b.ctxt { + // Context mismatches usually happen when procedural macros combine spans copied from + // the macro input with spans produced by the macro (`Span::*_site`). + // In that case we consider the combined span to be produced by the macro and return + // the original macro-produced span as the result. + // Otherwise we just fall back to returning the first span. + // Combining locations typically doesn't make sense in case of context mismatches. + // `is_root` here is a fast path optimization. + let a_is_callsite = a.ctxt.is_root() || a.ctxt == b.span().source_callsite().ctxt(); + return Err(if a_is_callsite { b_orig } else { a_orig }); + } + + let parent = if a.parent == b.parent { a.parent } else { None }; + Ok((a, b, parent)) + } + + /// This span, but in a larger context, may switch to the metavariable span if suitable. + pub fn with_neighbor(self, neighbor: Span) -> Span { + match Span::prepare_to_combine(self, neighbor) { + Ok((this, ..)) => Span::new(this.lo, this.hi, this.ctxt, this.parent), + Err(_) => self, + } + } + /// Returns a `Span` that would enclose both `self` and `end`. /// /// Note that this can also be used to extend the span "backwards": @@ -837,26 +862,12 @@ impl Span { /// ^^^^^^^^^^^^^^^^^^^^ /// ``` pub fn to(self, end: Span) -> Span { - let span_data = self.data(); - let end_data = end.data(); - // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480). - // Return the macro span on its own to avoid weird diagnostic output. It is preferable to - // have an incomplete span than a completely nonsensical one. - if span_data.ctxt != end_data.ctxt { - if span_data.ctxt.is_root() { - return end; - } else if end_data.ctxt.is_root() { - return self; + match Span::prepare_to_combine(self, end) { + Ok((from, to, parent)) => { + Span::new(cmp::min(from.lo, to.lo), cmp::max(from.hi, to.hi), from.ctxt, parent) } - // Both spans fall within a macro. - // FIXME(estebank): check if it is the *same* macro. + Err(fallback) => fallback, } - Span::new( - cmp::min(span_data.lo, end_data.lo), - cmp::max(span_data.hi, end_data.hi), - if span_data.ctxt.is_root() { end_data.ctxt } else { span_data.ctxt }, - if span_data.parent == end_data.parent { span_data.parent } else { None }, - ) } /// Returns a `Span` between the end of `self` to the beginning of `end`. @@ -867,14 +878,12 @@ impl Span { /// ^^^^^^^^^^^^^ /// ``` pub fn between(self, end: Span) -> Span { - let span = self.data(); - let end = end.data(); - Span::new( - span.hi, - end.lo, - if end.ctxt.is_root() { end.ctxt } else { span.ctxt }, - if span.parent == end.parent { span.parent } else { None }, - ) + match Span::prepare_to_combine(self, end) { + Ok((from, to, parent)) => { + Span::new(cmp::min(from.hi, to.hi), cmp::max(from.lo, to.lo), from.ctxt, parent) + } + Err(fallback) => fallback, + } } /// Returns a `Span` from the beginning of `self` until the beginning of `end`. @@ -885,31 +894,12 @@ impl Span { /// ^^^^^^^^^^^^^^^^^ /// ``` pub fn until(self, end: Span) -> Span { - // Most of this function's body is copied from `to`. - // We can't just do `self.to(end.shrink_to_lo())`, - // because to also does some magic where it uses min/max so - // it can handle overlapping spans. Some advanced mis-use of - // `until` with different ctxts makes this visible. - let span_data = self.data(); - let end_data = end.data(); - // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480). - // Return the macro span on its own to avoid weird diagnostic output. It is preferable to - // have an incomplete span than a completely nonsensical one. - if span_data.ctxt != end_data.ctxt { - if span_data.ctxt.is_root() { - return end; - } else if end_data.ctxt.is_root() { - return self; + match Span::prepare_to_combine(self, end) { + Ok((from, to, parent)) => { + Span::new(cmp::min(from.lo, to.lo), cmp::max(from.lo, to.lo), from.ctxt, parent) } - // Both spans fall within a macro. - // FIXME(estebank): check if it is the *same* macro. + Err(fallback) => fallback, } - Span::new( - span_data.lo, - end_data.lo, - if end_data.ctxt.is_root() { end_data.ctxt } else { span_data.ctxt }, - if span_data.parent == end_data.parent { span_data.parent } else { None }, - ) } pub fn from_inner(self, inner: InnerSpan) -> Span { @@ -1016,20 +1006,203 @@ impl Default for Span { } } -impl Encodable for Span { - default fn encode(&self, s: &mut E) { - let span = self.data(); - span.lo.encode(s); - span.hi.encode(s); +rustc_index::newtype_index! { + #[orderable] + #[debug_format = "AttrId({})"] + pub struct AttrId {} +} + +/// This trait is used to allow encoder specific encodings of certain types. +/// It is similar to rustc_type_ir's TyEncoder. +pub trait SpanEncoder: Encoder { + fn encode_span(&mut self, span: Span); + fn encode_symbol(&mut self, symbol: Symbol); + fn encode_expn_id(&mut self, expn_id: ExpnId); + fn encode_syntax_context(&mut self, syntax_context: SyntaxContext); + /// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx. + /// Therefore, make sure to include the context when encode a `CrateNum`. + fn encode_crate_num(&mut self, crate_num: CrateNum); + fn encode_def_index(&mut self, def_index: DefIndex); + fn encode_def_id(&mut self, def_id: DefId); +} + +impl SpanEncoder for FileEncoder { + fn encode_span(&mut self, span: Span) { + let span = span.data(); + span.lo.encode(self); + span.hi.encode(self); + } + + fn encode_symbol(&mut self, symbol: Symbol) { + self.emit_str(symbol.as_str()); + } + + fn encode_expn_id(&mut self, _expn_id: ExpnId) { + panic!("cannot encode `ExpnId` with `FileEncoder`"); + } + + fn encode_syntax_context(&mut self, _syntax_context: SyntaxContext) { + panic!("cannot encode `SyntaxContext` with `FileEncoder`"); + } + + fn encode_crate_num(&mut self, crate_num: CrateNum) { + self.emit_u32(crate_num.as_u32()); + } + + fn encode_def_index(&mut self, _def_index: DefIndex) { + panic!("cannot encode `DefIndex` with `FileEncoder`"); + } + + fn encode_def_id(&mut self, def_id: DefId) { + def_id.krate.encode(self); + def_id.index.encode(self); } } -impl Decodable for Span { - default fn decode(s: &mut D) -> Span { - let lo = Decodable::decode(s); - let hi = Decodable::decode(s); + +impl Encodable for Span { + fn encode(&self, s: &mut E) { + s.encode_span(*self); + } +} + +impl Encodable for Symbol { + fn encode(&self, s: &mut E) { + s.encode_symbol(*self); + } +} + +impl Encodable for ExpnId { + fn encode(&self, s: &mut E) { + s.encode_expn_id(*self) + } +} + +impl Encodable for SyntaxContext { + fn encode(&self, s: &mut E) { + s.encode_syntax_context(*self) + } +} + +impl Encodable for CrateNum { + fn encode(&self, s: &mut E) { + s.encode_crate_num(*self) + } +} + +impl Encodable for DefIndex { + fn encode(&self, s: &mut E) { + s.encode_def_index(*self) + } +} + +impl Encodable for DefId { + fn encode(&self, s: &mut E) { + s.encode_def_id(*self) + } +} + +impl Encodable for AttrId { + fn encode(&self, _s: &mut E) { + // A fresh id will be generated when decoding + } +} + +/// This trait is used to allow decoder specific encodings of certain types. +/// It is similar to rustc_type_ir's TyDecoder. +pub trait SpanDecoder: Decoder { + fn decode_span(&mut self) -> Span; + fn decode_symbol(&mut self) -> Symbol; + fn decode_expn_id(&mut self) -> ExpnId; + fn decode_syntax_context(&mut self) -> SyntaxContext; + fn decode_crate_num(&mut self) -> CrateNum; + fn decode_def_index(&mut self) -> DefIndex; + fn decode_def_id(&mut self) -> DefId; + fn decode_attr_id(&mut self) -> AttrId; +} + +impl SpanDecoder for MemDecoder<'_> { + fn decode_span(&mut self) -> Span { + let lo = Decodable::decode(self); + let hi = Decodable::decode(self); Span::new(lo, hi, SyntaxContext::root(), None) } + + fn decode_symbol(&mut self) -> Symbol { + Symbol::intern(self.read_str()) + } + + fn decode_expn_id(&mut self) -> ExpnId { + panic!("cannot decode `ExpnId` with `MemDecoder`"); + } + + fn decode_syntax_context(&mut self) -> SyntaxContext { + panic!("cannot decode `SyntaxContext` with `MemDecoder`"); + } + + fn decode_crate_num(&mut self) -> CrateNum { + CrateNum::from_u32(self.read_u32()) + } + + fn decode_def_index(&mut self) -> DefIndex { + panic!("cannot decode `DefIndex` with `MemDecoder`"); + } + + fn decode_def_id(&mut self) -> DefId { + DefId { krate: Decodable::decode(self), index: Decodable::decode(self) } + } + + fn decode_attr_id(&mut self) -> AttrId { + panic!("cannot decode `AttrId` with `MemDecoder`"); + } +} + +impl Decodable for Span { + fn decode(s: &mut D) -> Span { + s.decode_span() + } +} + +impl Decodable for Symbol { + fn decode(s: &mut D) -> Symbol { + s.decode_symbol() + } +} + +impl Decodable for ExpnId { + fn decode(s: &mut D) -> ExpnId { + s.decode_expn_id() + } +} + +impl Decodable for SyntaxContext { + fn decode(s: &mut D) -> SyntaxContext { + s.decode_syntax_context() + } +} + +impl Decodable for CrateNum { + fn decode(s: &mut D) -> CrateNum { + s.decode_crate_num() + } +} + +impl Decodable for DefIndex { + fn decode(s: &mut D) -> DefIndex { + s.decode_def_index() + } +} + +impl Decodable for DefId { + fn decode(s: &mut D) -> DefId { + s.decode_def_id() + } +} + +impl Decodable for AttrId { + fn decode(s: &mut D) -> AttrId { + s.decode_attr_id() + } } /// Insert `source_map` into the session globals for the duration of the @@ -1360,7 +1533,7 @@ impl Clone for SourceFile { } } -impl Encodable for SourceFile { +impl Encodable for SourceFile { fn encode(&self, s: &mut S) { self.name.encode(s); self.src_hash.encode(s); @@ -1434,7 +1607,7 @@ impl Encodable for SourceFile { } } -impl Decodable for SourceFile { +impl Decodable for SourceFile { fn decode(d: &mut D) -> SourceFile { let name: FileName = Decodable::decode(d); let src_hash: SourceFileHash = Decodable::decode(d); diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index c61dbcaae954..8253ffefcaa7 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -23,9 +23,15 @@ mod tests; /// otherwise return the call site span up to the `enclosing_sp` by /// following the `expn_data` chain. pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span { - let expn_data1 = sp.ctxt().outer_expn_data(); - let expn_data2 = enclosing_sp.ctxt().outer_expn_data(); - if expn_data1.is_root() || !expn_data2.is_root() && expn_data1.call_site == expn_data2.call_site + let ctxt = sp.ctxt(); + if ctxt.is_root() { + return sp; + } + + let enclosing_ctxt = enclosing_sp.ctxt(); + let expn_data1 = ctxt.outer_expn_data(); + if !enclosing_ctxt.is_root() + && expn_data1.call_site == enclosing_ctxt.outer_expn_data().call_site { sp } else { diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 130522a302dd..5788d11ed43c 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -18,7 +18,7 @@ impl SourceMap { /// * the LHS span must start at or before the RHS span. fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option { // Ensure we're at the same expansion ID. - if sp_lhs.ctxt() != sp_rhs.ctxt() { + if !sp_lhs.eq_ctxt(sp_rhs) { return None; } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index f7d17a267d69..e162695a13be 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -210,12 +210,10 @@ impl Span { } } - /// This function is used as a fast path when decoding the full `SpanData` is not necessary. - /// It's a cut-down version of `data_untracked`. - #[cfg_attr(not(test), rustc_diagnostic_item = "SpanCtxt")] - #[inline] - pub fn ctxt(self) -> SyntaxContext { - if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { + // Returns either syntactic context, if it can be retrieved without taking the interner lock, + // or an index into the interner if it cannot. + fn inline_ctxt(self) -> Result { + Ok(if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { if self.len_with_tag_or_marker & PARENT_TAG == 0 { // Inline-context format. SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32) @@ -223,17 +221,36 @@ impl Span { // Inline-parent format. We know that the SyntaxContext is root. SyntaxContext::root() } + } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { + // Partially-interned format. This path avoids looking up the + // interned value, and is the whole point of the + // partially-interned format. + SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32) } else { - if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { - // Partially-interned format. This path avoids looking up the - // interned value, and is the whole point of the - // partially-interned format. - SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32) - } else { - // Fully-interned format. - let index = self.lo_or_index; - with_span_interner(|interner| interner.spans[index as usize].ctxt) + // Fully-interned format. + return Err(self.lo_or_index as usize); + }) + } + + /// This function is used as a fast path when decoding the full `SpanData` is not necessary. + /// It's a cut-down version of `data_untracked`. + #[cfg_attr(not(test), rustc_diagnostic_item = "SpanCtxt")] + #[inline] + pub fn ctxt(self) -> SyntaxContext { + self.inline_ctxt() + .unwrap_or_else(|index| with_span_interner(|interner| interner.spans[index].ctxt)) + } + + #[inline] + pub fn eq_ctxt(self, other: Span) -> bool { + match (self.inline_ctxt(), other.inline_ctxt()) { + (Ok(ctxt1), Ok(ctxt2)) => ctxt1 == ctxt2, + (Ok(ctxt), Err(index)) | (Err(index), Ok(ctxt)) => { + with_span_interner(|interner| ctxt == interner.spans[index].ctxt) } + (Err(index1), Err(index2)) => with_span_interner(|interner| { + interner.spans[index1].ctxt == interner.spans[index2].ctxt + }), } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 03af77cb3fb0..8ed1255c010f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -9,7 +9,6 @@ use rustc_data_structures::stable_hasher::{ }; use rustc_data_structures::sync::Lock; use rustc_macros::HashStable_Generic; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; use std::hash::{Hash, Hasher}; @@ -2078,19 +2077,6 @@ impl ToString for Symbol { } } -impl Encodable for Symbol { - default fn encode(&self, s: &mut S) { - s.emit_str(self.as_str()); - } -} - -impl Decodable for Symbol { - #[inline] - default fn decode(d: &mut D) -> Symbol { - Symbol::intern(d.read_str()) - } -} - impl HashStable for Symbol { #[inline] fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs index 0fa59d2ddfba..746783ab7e3e 100644 --- a/compiler/rustc_symbol_mangling/src/errors.rs +++ b/compiler/rustc_symbol_mangling/src/errors.rs @@ -18,9 +18,7 @@ impl IntoDiagnostic<'_, G> for TestOutput { let TestOutput { span, kind, content } = self; #[allow(rustc::untranslatable_diagnostic)] - let mut diag = DiagnosticBuilder::new(dcx, level, format!("{kind}({content})")); - diag.span(span); - diag + DiagnosticBuilder::new(dcx, level, format!("{kind}({content})")).span_mv(span) } } diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index a274790bffcf..24e49ff648f2 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -120,11 +120,11 @@ impl<'a> Layout<'a> { /// Whether the layout is from a type that implements [`std::marker::PointerLike`]. /// /// Currently, that means that the type is pointer-sized, pointer-aligned, - /// and has a scalar ABI. + /// and has a initialized (non-union), scalar ABI. pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool { self.size() == data_layout.pointer_size && self.align().abi == data_layout.pointer_align.abi - && matches!(self.abi(), Abi::Scalar(..)) + && matches!(self.abi(), Abi::Scalar(Scalar::Initialized { .. })) } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 9d25388b90fd..8e26327196a1 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1601,6 +1601,8 @@ supported_targets! { ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf), ("riscv32imc-esp-espidf", riscv32imc_esp_espidf), ("riscv32imac-esp-espidf", riscv32imac_esp_espidf), + ("riscv32imafc-esp-espidf", riscv32imafc_esp_espidf), + ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf), ("riscv32imafc-unknown-none-elf", riscv32imafc_unknown_none_elf), ("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf), diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs index 9102673ef779..6884e078c27e 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.cpu = "pentiumpro".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = StackProbeType::Inline; Target { llvm_target: "i686-unknown-hurd-gnu".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs new file mode 100644 index 000000000000..6c7c920bd180 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs @@ -0,0 +1,30 @@ +use crate::spec::{cvs, PanicStrategy, RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), + llvm_target: "riscv32".into(), + pointer_width: 32, + arch: "riscv32".into(), + + options: TargetOptions { + families: cvs!["unix"], + os: "espidf".into(), + env: "newlib".into(), + vendor: "espressif".into(), + linker: Some("riscv32-esp-elf-gcc".into()), + cpu: "generic-rv32".into(), + + max_atomic_width: Some(32), + atomic_cas: true, + + llvm_abiname: "ilp32f".into(), + features: "+m,+a,+c,+f".into(), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + eh_frame_header: false, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs index f0515615b195..5b19ed1b5ff1 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs @@ -6,7 +6,8 @@ pub fn target() -> Target { base.plt_by_default = false; base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI; + base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK; + base.supports_xray = true; Target { llvm_target: "x86_64-unknown-fuchsia".into(), diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 533fe32f70d8..ecbb92ca5b99 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -10,7 +10,7 @@ use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor use crate::solve::{deeply_normalize_for_diagnostics, inspect}; use crate::traits::engine::TraitEngineExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs}; +use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::structural_normalize::StructurallyNormalizeExt; use crate::traits::NormalizeExt; use crate::traits::SkipLeakCheck; @@ -31,7 +31,6 @@ use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; -use rustc_session::lint::builtin::COINDUCTIVE_OVERLAP_IN_COHERENCE; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; use std::fmt::Debug; @@ -197,7 +196,7 @@ fn overlap<'tcx>( .intercrate(true) .with_next_trait_solver(tcx.next_trait_solver_in_coherence()) .build(); - let selcx = &mut SelectionContext::new(&infcx); + let selcx = &mut SelectionContext::with_treat_inductive_cycle_as_ambig(&infcx); if track_ambiguity_causes.is_yes() { selcx.enable_tracking_intercrate_ambiguity_causes(); } @@ -224,61 +223,10 @@ fn overlap<'tcx>( ); if overlap_mode.use_implicit_negative() { - for mode in [TreatInductiveCycleAs::Ambig, TreatInductiveCycleAs::Recur] { - if let Some(failing_obligation) = selcx.with_treat_inductive_cycle_as(mode, |selcx| { - impl_intersection_has_impossible_obligation(selcx, &obligations) - }) { - if matches!(mode, TreatInductiveCycleAs::Recur) { - let first_local_impl = impl1_header - .impl_def_id - .as_local() - .or(impl2_header.impl_def_id.as_local()) - .expect("expected one of the impls to be local"); - infcx.tcx.struct_span_lint_hir( - COINDUCTIVE_OVERLAP_IN_COHERENCE, - infcx.tcx.local_def_id_to_hir_id(first_local_impl), - infcx.tcx.def_span(first_local_impl), - format!( - "implementations {} will conflict in the future", - match impl1_header.trait_ref { - Some(trait_ref) => { - let trait_ref = infcx.resolve_vars_if_possible(trait_ref); - format!( - "of `{}` for `{}`", - trait_ref.print_trait_sugared(), - trait_ref.self_ty() - ) - } - None => format!( - "for `{}`", - infcx.resolve_vars_if_possible(impl1_header.self_ty) - ), - }, - ), - |lint| { - lint.note( - "impls that are not considered to overlap may be considered to \ - overlap in the future", - ) - .span_label( - infcx.tcx.def_span(impl1_header.impl_def_id), - "the first impl is here", - ) - .span_label( - infcx.tcx.def_span(impl2_header.impl_def_id), - "the second impl is here", - ); - lint.note(format!( - "`{}` may be considered to hold in future releases, \ - causing the impls to overlap", - infcx.resolve_vars_if_possible(failing_obligation.predicate) - )); - }, - ); - } - - return None; - } + if let Some(_failing_obligation) = + impl_intersection_has_impossible_obligation(selcx, &obligations) + { + return None; } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 451e0823c252..e119ddeb4c6e 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -122,8 +122,8 @@ pub fn is_const_evaluatable<'tcx>( if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def) } else { span }, "failed to evaluate generic const expression", ) - .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`") - .span_suggestion_verbose( + .note_mv("the crate this constant originates from uses `#![feature(generic_const_exprs)]`") + .span_suggestion_verbose_mv( rustc_span::DUMMY_SP, "consider enabling this feature", "#![feature(generic_const_exprs)]\n", diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 52f91d282f0b..c9e8b30c4c48 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -521,7 +521,7 @@ impl<'tcx> OnUnimplementedDirective { pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result, ErrorGuaranteed> { if let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) { return Self::parse_attribute(attr, false, tcx, item_def_id); - } else if tcx.features().diagnostic_namespace { + } else { tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented]) .filter_map(|attr| Self::parse_attribute(attr, true, tcx, item_def_id).transpose()) .try_fold(None, |aggr: Option, directive| { @@ -592,8 +592,6 @@ impl<'tcx> OnUnimplementedDirective { Ok(Some(directive)) } }) - } else { - Ok(None) } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 58700850a60f..4a6ef27e7ba3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2088,7 +2088,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let ty = self.resolve_vars_if_possible(returned_ty); if ty.references_error() { // don't print out the [type error] here - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); } else { err.span_label(expr.span, format!("this returned value is of type `{ty}`")); } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index efc75ee538e8..b05895e4b9a3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -2525,14 +2525,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Replace the more general E0283 with a more specific error err.cancel(); - err = self.dcx().struct_span_err_with_code( + err = self.dcx().struct_span_err( span, format!( "cannot {verb} associated {noun} on trait without specifying the \ corresponding `impl` type", ), - rustc_errors::error_code!(E0790), ); + err.code(rustc_errors::error_code!(E0790)); if let Some(local_def_id) = data.trait_ref.def_id.as_local() && let Some(hir::Node::Item(hir::Item { @@ -2654,26 +2654,24 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .chain(Some(data.term.into_arg())) .find(|g| g.has_non_region_infer()); if let Some(subst) = subst { - let mut err = self.emit_inference_failure_err( + self.emit_inference_failure_err( obligation.cause.body_id, span, subst, ErrorCode::E0284, true, - ); - err.note(format!("cannot satisfy `{predicate}`")); - err + ) + .note_mv(format!("cannot satisfy `{predicate}`")) } else { // If we can't find a substitution, just print a generic error - let mut err = struct_span_err!( + struct_span_err!( self.dcx(), span, E0284, "type annotations needed: cannot satisfy `{}`", predicate, - ); - err.span_label(span, format!("cannot satisfy `{predicate}`")); - err + ) + .span_label_mv(span, format!("cannot satisfy `{predicate}`")) } } @@ -2693,30 +2691,28 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err } else { // If we can't find a substitution, just print a generic error - let mut err = struct_span_err!( + struct_span_err!( self.dcx(), span, E0284, "type annotations needed: cannot satisfy `{}`", predicate, - ); - err.span_label(span, format!("cannot satisfy `{predicate}`")); - err + ) + .span_label_mv(span, format!("cannot satisfy `{predicate}`")) } } _ => { if self.dcx().has_errors().is_some() || self.tainted_by_errors().is_some() { return; } - let mut err = struct_span_err!( + struct_span_err!( self.dcx(), span, E0284, "type annotations needed: cannot satisfy `{}`", predicate, - ); - err.span_label(span, format!("cannot satisfy `{predicate}`")); - err + ) + .span_label_mv(span, format!("cannot satisfy `{predicate}`")) } }; self.note_obligation_cause(&mut err, obligation); @@ -3548,17 +3544,16 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span: Span, ) -> Option> { if !self.tcx.features().generic_const_exprs { - let mut err = self - .dcx() - .struct_span_err(span, "constant expression depends on a generic parameter"); - // FIXME(const_generics): we should suggest to the user how they can resolve this - // issue. However, this is currently not actually possible - // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). - // - // Note that with `feature(generic_const_exprs)` this case should not - // be reachable. - err.note("this may fail depending on what value the parameter takes"); - err.emit(); + self.dcx() + .struct_span_err(span, "constant expression depends on a generic parameter") + // FIXME(const_generics): we should suggest to the user how they can resolve this + // issue. However, this is currently not actually possible + // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). + // + // Note that with `feature(generic_const_exprs)` this case should not + // be reachable. + .note_mv("this may fail depending on what value the parameter takes") + .emit(); return None; } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index c52b8f37ef3b..080ad7bd549c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -279,6 +279,12 @@ pub fn normalize_param_env_or_error<'tcx>( } fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + // FIXME(return_type_notation): track binders in this normalizer, as + // `ty::Const::normalize` can only work with properly preserved binders. + + if c.has_escaping_bound_vars() { + return ty::Const::new_misc_error(self.0, c.ty()); + } // While it is pretty sus to be evaluating things with an empty param env, it // should actually be okay since without `feature(generic_const_exprs)` the only // const arguments that have a non-empty param env are array repeat counts. These diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 9749ff9cbc11..5b349d576b6a 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -65,8 +65,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { assert!(!ty.has_non_region_infer()); let mut canonical_var_values = OriginalQueryValues::default(); - let canonical_ty = - self.canonicalize_query_keep_static(param_env.and(ty), &mut canonical_var_values); + let canonical_ty = self.canonicalize_query(param_env.and(ty), &mut canonical_var_values); let Ok(canonical_result) = self.tcx.implied_outlives_bounds(canonical_ty) else { return vec![]; }; diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index d812d537d8c1..31e34096fb00 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -87,10 +87,8 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { }) } else { assert!(!self.intercrate); - let c_pred = self.canonicalize_query_keep_static( - param_env.and(obligation.predicate), - &mut _orig_values, - ); + let c_pred = + self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values); self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index e8867187a408..d5f98db2c930 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -239,16 +239,13 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> } let generic_ty = self.interner().type_of(data.def_id); - let concrete_ty = generic_ty.instantiate(self.interner(), args); + let mut concrete_ty = generic_ty.instantiate(self.interner(), args); self.anon_depth += 1; if concrete_ty == ty { - bug!( - "infinite recursion generic_ty: {:#?}, args: {:#?}, \ - concrete_ty: {:#?}, ty: {:#?}", - generic_ty, - args, - concrete_ty, - ty + concrete_ty = Ty::new_error_with_message( + self.interner(), + DUMMY_SP, + "recursive opaque type", ); } let folded_ty = ensure_sufficient_stack(|| self.try_fold_ty(concrete_ty)); @@ -275,10 +272,7 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> let data = data.try_fold_with(self)?; let mut orig_values = OriginalQueryValues::default(); - // HACK(matthewjasper) `'static` is special-cased in selection, - // so we cannot canonicalize it. - let c_data = infcx - .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values); + let c_data = infcx.canonicalize_query(self.param_env.and(data), &mut orig_values); debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); let result = match kind { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index cab2a62ed7e6..957de925dd37 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -111,14 +111,9 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable> + 't return Ok((result, None, vec![], Certainty::Proven)); } - // FIXME(#33684) -- We need to use - // `canonicalize_query_keep_static` here because of things - // like the subtype query, which go awry around - // `'static` otherwise. let mut canonical_var_values = OriginalQueryValues::default(); let old_param_env = query_key.param_env; - let canonical_self = - infcx.canonicalize_query_keep_static(query_key, &mut canonical_var_values); + let canonical_self = infcx.canonicalize_query(query_key, &mut canonical_var_values); let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?; let InferOk { value, obligations } = infcx diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 54b91ab1d4d8..c1145bc30c91 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -969,7 +969,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.tcx().def_span(impl_def_id), "multiple drop impls found", ) - .span_note(self.tcx().def_span(old_impl_def_id), "other impl here") + .span_note_mv( + self.tcx().def_span(old_impl_def_id), + "other impl here", + ) .delay_as_bug(); } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index c45925295ee7..61fe2c8efe36 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -239,20 +239,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - // Sets the `TreatInductiveCycleAs` mode temporarily in the selection context - pub fn with_treat_inductive_cycle_as( - &mut self, - treat_inductive_cycle: TreatInductiveCycleAs, - f: impl FnOnce(&mut Self) -> T, - ) -> T { + pub fn with_treat_inductive_cycle_as_ambig( + infcx: &'cx InferCtxt<'tcx>, + ) -> SelectionContext<'cx, 'tcx> { // Should be executed in a context where caching is disabled, // otherwise the cache is poisoned with the temporary result. - assert!(self.is_intercrate()); - let treat_inductive_cycle = - std::mem::replace(&mut self.treat_inductive_cycle, treat_inductive_cycle); - let value = f(self); - self.treat_inductive_cycle = treat_inductive_cycle; - value + assert!(infcx.intercrate); + SelectionContext { + treat_inductive_cycle: TreatInductiveCycleAs::Ambig, + ..SelectionContext::new(infcx) + } } pub fn with_query_mode( diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index d43ab0c8e85a..10329c623b38 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -345,7 +345,7 @@ fn report_negative_positive_conflict<'tcx>( positive_impl_def_id: DefId, sg: &mut specialization_graph::Graph, ) { - let mut err = tcx.dcx().create_err(NegativePositiveConflict { + let err = tcx.dcx().create_err(NegativePositiveConflict { impl_span: tcx.def_span(local_impl_def_id), trait_desc: overlap.trait_ref, self_ty: overlap.self_ty, diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 19eae93df9c8..c40ed10e52ff 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -271,7 +271,7 @@ pub fn closure_trait_ref_and_return_type<'tcx>( TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()), }; - let trait_ref = if tcx.generics_of(fn_trait_def_id).host_effect_index.is_some() { + let trait_ref = if tcx.has_host_param(fn_trait_def_id) { ty::TraitRef::new( tcx, fn_trait_def_id, diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 49f24f66b24a..86a077ee808b 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -199,6 +199,7 @@ pub(crate) mod rustc { match err { LayoutError::Unknown(..) | LayoutError::ReferencesError(..) => Self::UnknownLayout, LayoutError::SizeOverflow(..) => Self::SizeOverflow, + LayoutError::Cycle(err) => Self::TypeError(*err), err => unimplemented!("{:?}", err), } } diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 38f0eb821801..59966423f7fb 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -11,6 +11,7 @@ rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } +rustc_span = { path = "../rustc_span", optional = true } smallvec = { version = "1.8.1" } # tidy-alphabetical-end @@ -21,6 +22,7 @@ nightly = [ "smallvec/union", "rustc_index/nightly", "rustc_serialize", + "rustc_span", "rustc_data_structures", "rustc_macros", ] diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs index 2fbc8f76fa4f..71f9eb0ef8a8 100644 --- a/compiler/rustc_type_ir/src/codec.rs +++ b/compiler/rustc_type_ir/src/codec.rs @@ -1,7 +1,7 @@ use crate::{Interner, PredicateKind}; use rustc_data_structures::fx::FxHashMap; -use rustc_serialize::{Decoder, Encoder}; +use rustc_span::{SpanDecoder, SpanEncoder}; /// The shorthand encoding uses an enum's variant index `usize` /// and is offset by this value so it never matches a real variant. @@ -22,7 +22,7 @@ pub trait RefDecodable<'tcx, D: TyDecoder> { fn decode(d: &mut D) -> &'tcx Self; } -pub trait TyEncoder: Encoder { +pub trait TyEncoder: SpanEncoder { type I: Interner; const CLEAR_CROSS_CRATE: bool; @@ -35,7 +35,7 @@ pub trait TyEncoder: Encoder { fn encode_alloc_id(&mut self, alloc_id: &::AllocId); } -pub trait TyDecoder: Decoder { +pub trait TyDecoder: SpanDecoder { type I: Interner; const CLEAR_CROSS_CRATE: bool; diff --git a/config.example.toml b/config.example.toml index f1ea6bac3ca1..a5ef4022d39d 100644 --- a/config.example.toml +++ b/config.example.toml @@ -339,6 +339,14 @@ # on this runtime, such as `-C profile-generate` or `-C instrument-coverage`). #profiler = false +# Use the optimized LLVM C intrinsics for `compiler_builtins`, rather than Rust intrinsics. +# Requires the LLVM submodule to be managed by bootstrap (i.e. not external) so that `compiler-rt` +# sources are available. +# +# Setting this to `false` generates slower code, but removes the requirement for a C toolchain in +# order to run `x check`. +#optimized-compiler-builtins = if rust.channel == "dev" { false } else { true } + # Indicates whether the native libraries linked into Cargo will be statically # linked or not. #cargo-native-static = false diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 0af3ac38ee53..78629b39d34b 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -120,7 +120,6 @@ #![feature(const_size_of_val)] #![feature(const_waker)] #![feature(core_intrinsics)] -#![feature(core_panic)] #![feature(deprecated_suggestion)] #![feature(dispatch_from_dyn)] #![feature(error_generic_member_access)] @@ -139,6 +138,8 @@ #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_uninit_array_transpose)] +#![feature(non_null_convenience)] +#![feature(panic_internals)] #![feature(pattern)] #![feature(ptr_internals)] #![feature(ptr_metadata)] @@ -180,6 +181,7 @@ #![feature(const_ptr_write)] #![feature(const_trait_impl)] #![feature(const_try)] +#![feature(decl_macro)] #![feature(dropck_eyepatch)] #![feature(exclusive_range_pattern)] #![feature(fundamental)] diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index a6cbed092c0a..0a2280545dac 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -257,7 +257,7 @@ where // then the source pointer will stay in its initial position and we can't use it as reference if src.ptr != src_ptr { debug_assert!( - unsafe { dst_buf.add(len) as *const _ } <= src.ptr, + unsafe { dst_buf.add(len) as *const _ } <= src.ptr.as_ptr(), "InPlaceIterable contract violation, write pointer advanced beyond read pointer" ); } diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index b03e04b7c706..654ce09afcd3 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -18,6 +18,17 @@ use core::ops::Deref; use core::ptr::{self, NonNull}; use core::slice::{self}; +macro non_null { + (mut $place:expr, $t:ident) => {{ + #![allow(unused_unsafe)] // we're sometimes used within an unsafe block + unsafe { &mut *(ptr::addr_of_mut!($place) as *mut NonNull<$t>) } + }}, + ($place:expr, $t:ident) => {{ + #![allow(unused_unsafe)] // we're sometimes used within an unsafe block + unsafe { *(ptr::addr_of!($place) as *const NonNull<$t>) } + }}, +} + /// An iterator that moves out of a vector. /// /// This `struct` is created by the `into_iter` method on [`Vec`](super::Vec) @@ -41,10 +52,12 @@ pub struct IntoIter< // the drop impl reconstructs a RawVec from buf, cap and alloc // to avoid dropping the allocator twice we need to wrap it into ManuallyDrop pub(super) alloc: ManuallyDrop, - pub(super) ptr: *const T, - pub(super) end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that - // ptr == end is a quick test for the Iterator being empty, that works - // for both ZST and non-ZST. + pub(super) ptr: NonNull, + /// If T is a ZST, this is actually ptr+len. This encoding is picked so that + /// ptr == end is a quick test for the Iterator being empty, that works + /// for both ZST and non-ZST. + /// For non-ZSTs the pointer is treated as `NonNull` + pub(super) end: *const T, } #[stable(feature = "vec_intoiter_debug", since = "1.13.0")] @@ -68,7 +81,7 @@ impl IntoIter { /// ``` #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")] pub fn as_slice(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.ptr, self.len()) } + unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len()) } } /// Returns the remaining items of this iterator as a mutable slice. @@ -97,7 +110,7 @@ impl IntoIter { } fn as_raw_mut_slice(&mut self) -> *mut [T] { - ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len()) + ptr::slice_from_raw_parts_mut(self.ptr.as_ptr(), self.len()) } /// Drops remaining elements and relinquishes the backing allocation. @@ -124,7 +137,7 @@ impl IntoIter { // this creates less assembly self.cap = 0; self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) }; - self.ptr = self.buf.as_ptr(); + self.ptr = self.buf; self.end = self.buf.as_ptr(); // Dropping the remaining elements can panic, so this needs to be @@ -136,9 +149,9 @@ impl IntoIter { /// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed. pub(crate) fn forget_remaining_elements(&mut self) { - // For th ZST case, it is crucial that we mutate `end` here, not `ptr`. + // For the ZST case, it is crucial that we mutate `end` here, not `ptr`. // `ptr` must stay aligned, while `end` may be unaligned. - self.end = self.ptr; + self.end = self.ptr.as_ptr(); } #[cfg(not(no_global_oom_handling))] @@ -160,7 +173,7 @@ impl IntoIter { // say that they're all at the beginning of the "allocation". 0..this.len() } else { - this.ptr.sub_ptr(buf)..this.end.sub_ptr(buf) + this.ptr.sub_ptr(this.buf)..this.end.sub_ptr(buf) }; let cap = this.cap; let alloc = ManuallyDrop::take(&mut this.alloc); @@ -187,29 +200,35 @@ impl Iterator for IntoIter { #[inline] fn next(&mut self) -> Option { - if self.ptr == self.end { - None - } else if T::IS_ZST { - // `ptr` has to stay where it is to remain aligned, so we reduce the length by 1 by - // reducing the `end`. - self.end = self.end.wrapping_byte_sub(1); + if T::IS_ZST { + if self.ptr.as_ptr() == self.end as *mut _ { + None + } else { + // `ptr` has to stay where it is to remain aligned, so we reduce the length by 1 by + // reducing the `end`. + self.end = self.end.wrapping_byte_sub(1); - // Make up a value of this ZST. - Some(unsafe { mem::zeroed() }) + // Make up a value of this ZST. + Some(unsafe { mem::zeroed() }) + } } else { - let old = self.ptr; - self.ptr = unsafe { self.ptr.add(1) }; + if self.ptr == non_null!(self.end, T) { + None + } else { + let old = self.ptr; + self.ptr = unsafe { old.add(1) }; - Some(unsafe { ptr::read(old) }) + Some(unsafe { ptr::read(old.as_ptr()) }) + } } } #[inline] fn size_hint(&self) -> (usize, Option) { let exact = if T::IS_ZST { - self.end.addr().wrapping_sub(self.ptr.addr()) + self.end.addr().wrapping_sub(self.ptr.as_ptr().addr()) } else { - unsafe { self.end.sub_ptr(self.ptr) } + unsafe { non_null!(self.end, T).sub_ptr(self.ptr) } }; (exact, Some(exact)) } @@ -217,7 +236,7 @@ impl Iterator for IntoIter { #[inline] fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let step_size = self.len().min(n); - let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size); + let to_drop = ptr::slice_from_raw_parts_mut(self.ptr.as_ptr(), step_size); if T::IS_ZST { // See `next` for why we sub `end` here. self.end = self.end.wrapping_byte_sub(step_size); @@ -259,7 +278,7 @@ impl Iterator for IntoIter { // Safety: `len` indicates that this many elements are available and we just checked that // it fits into the array. unsafe { - ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, len); + ptr::copy_nonoverlapping(self.ptr.as_ptr(), raw_ary.as_mut_ptr() as *mut T, len); self.forget_remaining_elements(); return Err(array::IntoIter::new_unchecked(raw_ary, 0..len)); } @@ -268,7 +287,7 @@ impl Iterator for IntoIter { // Safety: `len` is larger than the array size. Copy a fixed amount here to fully initialize // the array. return unsafe { - ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, N); + ptr::copy_nonoverlapping(self.ptr.as_ptr(), raw_ary.as_mut_ptr() as *mut T, N); self.ptr = self.ptr.add(N); Ok(raw_ary.transpose().assume_init()) }; @@ -286,7 +305,7 @@ impl Iterator for IntoIter { // Also note the implementation of `Self: TrustedRandomAccess` requires // that `T: Copy` so reading elements from the buffer doesn't invalidate // them for `Drop`. - unsafe { if T::IS_ZST { mem::zeroed() } else { ptr::read(self.ptr.add(i)) } } + unsafe { if T::IS_ZST { mem::zeroed() } else { self.ptr.add(i).read() } } } } @@ -294,18 +313,25 @@ impl Iterator for IntoIter { impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { - if self.end == self.ptr { - None - } else if T::IS_ZST { - // See above for why 'ptr.offset' isn't used - self.end = self.end.wrapping_byte_sub(1); + if T::IS_ZST { + if self.end as *mut _ == self.ptr.as_ptr() { + None + } else { + // See above for why 'ptr.offset' isn't used + self.end = self.end.wrapping_byte_sub(1); - // Make up a value of this ZST. - Some(unsafe { mem::zeroed() }) + // Make up a value of this ZST. + Some(unsafe { mem::zeroed() }) + } } else { - self.end = unsafe { self.end.sub(1) }; + if non_null!(self.end, T) == self.ptr { + None + } else { + let new_end = unsafe { non_null!(self.end, T).sub(1) }; + *non_null!(mut self.end, T) = new_end; - Some(unsafe { ptr::read(self.end) }) + Some(unsafe { ptr::read(new_end.as_ptr()) }) + } } } @@ -331,7 +357,11 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter { fn is_empty(&self) -> bool { - self.ptr == self.end + if T::IS_ZST { + self.ptr.as_ptr() == self.end as *mut _ + } else { + self.ptr == non_null!(self.end, T) + } } } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index e8a096cac869..8aa0c6e7ed62 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2825,14 +2825,8 @@ impl IntoIterator for Vec { begin.add(me.len()) as *const T }; let cap = me.buf.capacity(); - IntoIter { - buf: NonNull::new_unchecked(begin), - phantom: PhantomData, - cap, - alloc, - ptr: begin, - end, - } + let buf = NonNull::new_unchecked(begin); + IntoIter { buf, phantom: PhantomData, cap, alloc, ptr: buf, end } } } } diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs index efa6868473e4..e976552cf2b9 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -44,12 +44,12 @@ impl SpecFromIter> for Vec { // than creating it through the generic FromIterator implementation would. That limitation // is not strictly necessary as Vec's allocation behavior is intentionally unspecified. // But it is a conservative choice. - let has_advanced = iterator.buf.as_ptr() as *const _ != iterator.ptr; + let has_advanced = iterator.buf != iterator.ptr; if !has_advanced || iterator.len() >= iterator.cap / 2 { unsafe { let it = ManuallyDrop::new(iterator); if has_advanced { - ptr::copy(it.ptr, it.buf.as_ptr(), it.len()); + ptr::copy(it.ptr.as_ptr(), it.buf.as_ptr(), it.len()); } return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap); } diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index 453de9754be5..177f39b59aed 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -4,6 +4,7 @@ use crate::char::TryFromCharError; use crate::convert::TryFrom; use crate::error::Error; use crate::fmt; +use crate::intrinsics::assert_unsafe_precondition; use crate::mem::transmute; use crate::str::FromStr; @@ -23,7 +24,13 @@ pub(super) const fn from_u32(i: u32) -> Option { #[must_use] pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char { // SAFETY: the caller must guarantee that `i` is a valid char value. - if cfg!(debug_assertions) { char::from_u32(i).unwrap() } else { unsafe { transmute(i) } } + unsafe { + assert_unsafe_precondition!( + "invalid value for `char`", + (i: u32) => char_try_from_u32(i).is_ok() + ); + transmute(i) + } } #[stable(feature = "char_convert", since = "1.13.0")] diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 8c01b0973d65..45f6e375e894 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -753,6 +753,7 @@ where /// That is, this conversion is whatever the implementation of /// [From]<T> for U chooses to do. #[inline] + #[track_caller] fn into(self) -> U { U::from(self) } diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index 71b9464efd28..af2e422e8a00 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -28,7 +28,7 @@ use crate::task::{Context, Poll}; #[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] #[lang = "future_trait"] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( label = "`{Self}` is not a future", message = "`{Self}` is not a future", note = "{Self} must be a future or must implement `IntoFuture` to be awaited" diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 4a73f160b656..5c44ca69451d 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -287,7 +287,7 @@ pub fn spin_loop() { /// /// The compiler could theoretically make optimizations like the following: /// -/// - `needle` and `haystack` are always the same, move the call to `contains` outside the loop and +/// - The `needle` and `haystack` do not change, move the call to `contains` outside the loop and /// delete the loop /// - Inline `contains` /// - `needle` and `haystack` have values known at compile time, `contains` is always true. Remove diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 696bf6f3a946..3df3e8ea05cd 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1783,27 +1783,37 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn truncf64(x: f64) -> f64; - /// Returns the nearest integer to an `f32`. May raise an inexact floating-point exception - /// if the argument is not an integer. + /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// May raise an inexact floating-point exception if the argument is not an integer. + /// However, Rust assumes floating-point exceptions cannot be observed, so this is not something that + /// can actually be used from Rust code. /// /// The stabilized version of this intrinsic is /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) #[rustc_nounwind] pub fn rintf32(x: f32) -> f32; - /// Returns the nearest integer to an `f64`. May raise an inexact floating-point exception - /// if the argument is not an integer. + /// Returns the nearest integer to an `f64`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// May raise an inexact floating-point exception if the argument is not an integer. + /// However, Rust assumes floating-point exceptions cannot be observed, so this is not something that + /// can actually be used from Rust code. /// /// The stabilized version of this intrinsic is /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) #[rustc_nounwind] pub fn rintf64(x: f64) -> f64; - /// Returns the nearest integer to an `f32`. + /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. /// /// This intrinsic does not have a stable counterpart. #[rustc_nounwind] pub fn nearbyintf32(x: f32) -> f32; - /// Returns the nearest integer to an `f64`. + /// Returns the nearest integer to an `f64`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. /// /// This intrinsic does not have a stable counterpart. #[rustc_nounwind] diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index c6401ec1e333..334e32b26b18 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -65,6 +65,7 @@ //! ```rust //! #![feature(core_intrinsics, custom_mir)] //! #![allow(internal_features)] +//! #![allow(unused_assignments)] //! //! use core::intrinsics::mir::*; //! diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 8e2c887a161e..d94a508b5b28 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3094,16 +3094,23 @@ pub trait Iterator { P: FnMut(Self::Item) -> bool, { #[inline] - fn check( - mut predicate: impl FnMut(T) -> bool, - ) -> impl FnMut(usize, T) -> ControlFlow { + fn check<'a, T>( + mut predicate: impl FnMut(T) -> bool + 'a, + acc: &'a mut usize, + ) -> impl FnMut((), T) -> ControlFlow + 'a { #[rustc_inherit_overflow_checks] - move |i, x| { - if predicate(x) { ControlFlow::Break(i) } else { ControlFlow::Continue(i + 1) } + move |_, x| { + if predicate(x) { + ControlFlow::Break(*acc) + } else { + *acc += 1; + ControlFlow::Continue(()) + } } } - self.try_fold(0, check(predicate)).break_value() + let mut acc = 0; + self.try_fold((), check(predicate, &mut acc)).break_value() } /// Searches for an element in an iterator from the right, returning its diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 9316ec93f240..1a8f245c8be3 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -167,7 +167,6 @@ #![feature(const_unicode_case_lookup)] #![feature(const_unsafecell_get_mut)] #![feature(const_waker)] -#![feature(core_panic)] #![feature(coverage_attribute)] #![feature(duration_consts_float)] #![feature(internal_impls_macro)] @@ -179,6 +178,7 @@ #![feature(non_null_convenience)] #![feature(offset_of)] #![feature(offset_of_enum)] +#![feature(panic_internals)] #![feature(ptr_alignment_type)] #![feature(ptr_metadata)] #![feature(set_ptr_value)] @@ -217,6 +217,7 @@ #![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] +#![feature(diagnostic_namespace)] #![feature(doc_cfg)] #![feature(doc_cfg_hide)] #![feature(doc_notable_trait)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 7f5908e477cf..a2437feeeb9c 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -32,7 +32,7 @@ macro_rules! panic { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "assert_eq_macro")] -#[allow_internal_unstable(core_panic)] +#[allow_internal_unstable(panic_internals)] macro_rules! assert_eq { ($left:expr, $right:expr $(,)?) => { match (&$left, &$right) { @@ -82,7 +82,7 @@ macro_rules! assert_eq { #[macro_export] #[stable(feature = "assert_ne", since = "1.13.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "assert_ne_macro")] -#[allow_internal_unstable(core_panic)] +#[allow_internal_unstable(panic_internals)] macro_rules! assert_ne { ($left:expr, $right:expr $(,)?) => { match (&$left, &$right) { @@ -139,7 +139,7 @@ macro_rules! assert_ne { /// assert_matches!(c, Ok(x) | Err(x) if x.len() < 100); /// ``` #[unstable(feature = "assert_matches", issue = "82775")] -#[allow_internal_unstable(core_panic)] +#[allow_internal_unstable(panic_internals)] #[rustc_macro_transparency = "semitransparent"] pub macro assert_matches { ($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { @@ -787,7 +787,7 @@ macro_rules! unreachable { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "unimplemented_macro")] -#[allow_internal_unstable(core_panic)] +#[allow_internal_unstable(panic_internals)] macro_rules! unimplemented { () => { $crate::panicking::panic("not implemented") @@ -867,7 +867,7 @@ macro_rules! unimplemented { #[macro_export] #[stable(feature = "todo_macro", since = "1.40.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "todo_macro")] -#[allow_internal_unstable(core_panic)] +#[allow_internal_unstable(panic_internals)] macro_rules! todo { () => { $crate::panicking::panic("not yet implemented") @@ -1534,7 +1534,7 @@ pub(crate) mod builtin { #[rustc_builtin_macro] #[macro_export] #[rustc_diagnostic_item = "assert_macro"] - #[allow_internal_unstable(core_panic, edition_panic, generic_assert_internals)] + #[allow_internal_unstable(panic_internals, edition_panic, generic_assert_internals)] macro_rules! assert { ($cond:expr $(,)?) => {{ /* compiler built-in */ }}; ($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }}; diff --git a/library/core/src/macros/panic.md b/library/core/src/macros/panic.md index 60100c2655a6..6bd23b3072ed 100644 --- a/library/core/src/macros/panic.md +++ b/library/core/src/macros/panic.md @@ -56,7 +56,7 @@ For more detailed information about error handling check out the [book] or the [`panic_any`]: ../std/panic/fn.panic_any.html [`Box`]: ../std/boxed/struct.Box.html [`Any`]: crate::any::Any -[`format!` syntax]: ../std/fmt/index.html +[formatting syntax]: ../std/fmt/index.html [book]: ../book/ch09-00-error-handling.html [`std::result`]: ../std/result/index.html diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 99762bccd18f..561f8ef36ffd 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -75,7 +75,7 @@ macro marker_impls { /// [ub]: ../../reference/behavior-considered-undefined.html #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "Send")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "`{Self}` cannot be sent between threads safely", label = "`{Self}` cannot be sent between threads safely" )] @@ -134,7 +134,7 @@ unsafe impl Send for &T {} #[doc(alias = "?", alias = "?Sized")] #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "the size for values of type `{Self}` cannot be known at compilation time", label = "doesn't have a size known at compile-time" )] @@ -205,7 +205,7 @@ pub trait Unsize { /// [RFC1445]: https://github.com/rust-lang/rfcs/blob/master/text/1445-restrict-constants-in-patterns.md /// [issue 63438]: https://github.com/rust-lang/rust/issues/63438 #[unstable(feature = "structural_match", issue = "31434")] -#[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] +#[diagnostic::on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] #[lang = "structural_peq"] pub trait StructuralPartialEq { // Empty. @@ -273,7 +273,7 @@ marker_impls! { /// of the two derives (`#[derive(PartialEq)]` and `#[derive(Eq)]`) and check /// that both of them are present as part of structural-match checking. #[unstable(feature = "structural_match", issue = "31434")] -#[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] +#[diagnostic::on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] #[lang = "structural_teq"] pub trait StructuralEq { // Empty. @@ -899,25 +899,37 @@ marker_impls! { {T: ?Sized} &mut T, } -/// Types that can be safely moved after being pinned. +/// Types that do not require any pinning guarantees. /// -/// Rust itself has no notion of immovable types, and considers moves (e.g., -/// through assignment or [`mem::replace`]) to always be safe. +/// For information on what "pinning" is, see the [`pin` module] documentation. /// -/// The [`Pin`][Pin] type is used instead to prevent moves through the type -/// system. Pointers `P` wrapped in the [`Pin>`][Pin] wrapper can't be -/// moved out of. See the [`pin` module] documentation for more information on -/// pinning. +/// Implementing the `Unpin` trait for `T` expresses the fact that `T` is pinning-agnostic: +/// it shall not expose nor rely on any pinning guarantees. This, in turn, means that a +/// `Pin`-wrapped pointer to such a type can feature a *fully unrestricted* API. +/// In other words, if `T: Unpin`, a value of type `T` will *not* be bound by the invariants +/// which pinning otherwise offers, even when "pinned" by a [`Pin`] pointing at it. +/// When a value of type `T` is pointed at by a [`Pin`], [`Pin`] will not restrict access +/// to the pointee value like it normally would, thus allowing the user to do anything that they +/// normally could with a non-[`Pin`]-wrapped `Ptr` to that value. /// -/// Implementing the `Unpin` trait for `T` lifts the restrictions of pinning off -/// the type, which then allows moving `T` out of [`Pin>`][Pin] with -/// functions such as [`mem::replace`]. +/// The idea of this trait is to alleviate the reduced ergonomics of APIs that require the use +/// of [`Pin`] for soundness for some types, but which also want to be used by other types that +/// don't care about pinning. The prime example of such an API is [`Future::poll`]. There are many +/// [`Future`] types that don't care about pinning. These futures can implement `Unpin` and +/// therefore get around the pinning related restrictions in the API, while still allowing the +/// subset of [`Future`]s which *do* require pinning to be implemented soundly. /// -/// `Unpin` has no consequence at all for non-pinned data. In particular, -/// [`mem::replace`] happily moves `!Unpin` data (it works for any `&mut T`, not -/// just when `T: Unpin`). However, you cannot use [`mem::replace`] on data -/// wrapped inside a [`Pin>`][Pin] because you cannot get the `&mut T` you -/// need for that, and *that* is what makes this system work. +/// For more discussion on the consequences of [`Unpin`] within the wider scope of the pinning +/// system, see the [section about `Unpin`] in the [`pin` module]. +/// +/// `Unpin` has no consequence at all for non-pinned data. In particular, [`mem::replace`] happily +/// moves `!Unpin` data, which would be immovable when pinned ([`mem::replace`] works for any +/// `&mut T`, not just when `T: Unpin`). +/// +/// *However*, you cannot use [`mem::replace`] on `!Unpin` data which is *pinned* by being wrapped +/// inside a [`Pin`] pointing at it. This is because you cannot (safely) use a +/// [`Pin`] to get an `&mut T` to its pointee value, which you would need to call +/// [`mem::replace`], and *that* is what makes this system work. /// /// So this, for example, can only be done on types implementing `Unpin`: /// @@ -935,13 +947,24 @@ marker_impls! { /// mem::replace(&mut *pinned_string, "other".to_string()); /// ``` /// -/// This trait is automatically implemented for almost every type. +/// This trait is automatically implemented for almost every type. The compiler is free +/// to take the conservative stance of marking types as [`Unpin`] so long as all of the types that +/// compose its fields are also [`Unpin`]. This is because if a type implements [`Unpin`], then it +/// is unsound for that type's implementation to rely on pinning-related guarantees for soundness, +/// *even* when viewed through a "pinning" pointer! It is the responsibility of the implementor of +/// a type that relies upon pinning for soundness to ensure that type is *not* marked as [`Unpin`] +/// by adding [`PhantomPinned`] field. For more details, see the [`pin` module] docs. /// -/// [`mem::replace`]: crate::mem::replace -/// [Pin]: crate::pin::Pin -/// [`pin` module]: crate::pin +/// [`mem::replace`]: crate::mem::replace "mem replace" +/// [`Future`]: crate::future::Future "Future" +/// [`Future::poll`]: crate::future::Future::poll "Future poll" +/// [`Pin`]: crate::pin::Pin "Pin" +/// [`Pin`]: crate::pin::Pin "Pin" +/// [`pin` module]: crate::pin "pin module" +/// [section about `Unpin`]: crate::pin#unpin "pin module docs about unpin" +/// [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe" #[stable(feature = "pin", since = "1.33.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( note = "consider using the `pin!` macro\nconsider using `Box::pin` if you need to access the pinned value outside of the current scope", message = "`{Self}` cannot be unpinned" )] @@ -989,7 +1012,7 @@ pub trait Destruct {} /// for any user type. #[unstable(feature = "tuple_trait", issue = "none")] #[lang = "tuple_trait"] -#[rustc_on_unimplemented(message = "`{Self}` is not a tuple")] +#[diagnostic::on_unimplemented(message = "`{Self}` is not a tuple")] #[rustc_deny_explicit_impl(implement_via_object = false)] pub trait Tuple {} @@ -999,7 +1022,7 @@ pub trait Tuple {} /// `*const ()` automatically implement this trait. #[unstable(feature = "pointer_like_trait", issue = "none")] #[lang = "pointer_like"] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "`{Self}` needs to have the same ABI as a pointer", label = "`{Self}` needs to be a pointer-like type" )] @@ -1013,7 +1036,7 @@ pub trait PointerLike {} /// are `StructuralPartialEq`. #[lang = "const_param_ty"] #[unstable(feature = "adt_const_params", issue = "95174")] -#[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] +#[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] #[allow(multiple_supertrait_upcastable)] pub trait ConstParamTy: StructuralEq + StructuralPartialEq + Eq {} diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 1773fdbf37cc..bb3cdde66d17 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -307,7 +307,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "mul"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "cannot multiply `{Self}` by `{Rhs}`", label = "no implementation for `{Self} * {Rhs}`" )] @@ -441,7 +441,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "div"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "cannot divide `{Self}` by `{Rhs}`", label = "no implementation for `{Self} / {Rhs}`" )] @@ -543,7 +543,7 @@ div_impl_float! { f32 f64 } /// ``` #[lang = "rem"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "cannot calculate the remainder of `{Self}` divided by `{Rhs}`", label = "no implementation for `{Self} % {Rhs}`" )] @@ -729,7 +729,7 @@ neg_impl! { isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "add_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "cannot add-assign `{Rhs}` to `{Self}`", label = "no implementation for `{Self} += {Rhs}`" )] @@ -796,7 +796,7 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "sub_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "cannot subtract-assign `{Rhs}` from `{Self}`", label = "no implementation for `{Self} -= {Rhs}`" )] @@ -854,7 +854,7 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "mul_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "cannot multiply-assign `{Self}` by `{Rhs}`", label = "no implementation for `{Self} *= {Rhs}`" )] @@ -912,7 +912,7 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "div_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "cannot divide-assign `{Self}` by `{Rhs}`", label = "no implementation for `{Self} /= {Rhs}`" )] @@ -973,7 +973,7 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "rem_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "cannot calculate and assign the remainder of `{Self}` divided by `{Rhs}`", label = "no implementation for `{Self} %= {Rhs}`" )] diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs index c70f4a3da2ed..6984100e498e 100644 --- a/library/core/src/ops/bit.rs +++ b/library/core/src/ops/bit.rs @@ -137,7 +137,7 @@ impl Not for ! { #[lang = "bitand"] #[doc(alias = "&")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "no implementation for `{Self} & {Rhs}`", label = "no implementation for `{Self} & {Rhs}`" )] @@ -237,7 +237,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[lang = "bitor"] #[doc(alias = "|")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "no implementation for `{Self} | {Rhs}`", label = "no implementation for `{Self} | {Rhs}`" )] @@ -337,7 +337,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[lang = "bitxor"] #[doc(alias = "^")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "no implementation for `{Self} ^ {Rhs}`", label = "no implementation for `{Self} ^ {Rhs}`" )] @@ -436,7 +436,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[lang = "shl"] #[doc(alias = "<<")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "no implementation for `{Self} << {Rhs}`", label = "no implementation for `{Self} << {Rhs}`" )] @@ -554,7 +554,7 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } #[lang = "shr"] #[doc(alias = ">>")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "no implementation for `{Self} >> {Rhs}`", label = "no implementation for `{Self} >> {Rhs}`" )] @@ -681,7 +681,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } #[lang = "bitand_assign"] #[doc(alias = "&=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "no implementation for `{Self} &= {Rhs}`", label = "no implementation for `{Self} &= {Rhs}`" )] @@ -752,7 +752,7 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[lang = "bitor_assign"] #[doc(alias = "|=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "no implementation for `{Self} |= {Rhs}`", label = "no implementation for `{Self} |= {Rhs}`" )] @@ -823,7 +823,7 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[lang = "bitxor_assign"] #[doc(alias = "^=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "no implementation for `{Self} ^= {Rhs}`", label = "no implementation for `{Self} ^= {Rhs}`" )] @@ -892,7 +892,7 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[lang = "shl_assign"] #[doc(alias = "<<=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "no implementation for `{Self} <<= {Rhs}`", label = "no implementation for `{Self} <<= {Rhs}`" )] @@ -974,7 +974,7 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } #[lang = "shr_assign"] #[doc(alias = ">>=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "no implementation for `{Self} >>= {Rhs}`", label = "no implementation for `{Self} >>= {Rhs}`" )] diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 99adbb91599a..2c7845d4304f 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -70,7 +70,7 @@ /// implementation is still specific in this sense; for example, [`Vec`][vec] /// dereferences to `[T]`, so methods of `T` are not applicable. /// -/// Consider also that deref coericion means that deref traits are a much larger +/// Consider also that deref coercion means that deref traits are a much larger /// part of a type's public API than any other trait as it is implicitly called /// by the compiler. Therefore, it is advisable to consider whether this is /// something you are comfortable supporting as a public API. diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 6ceee4637298..37d9a28fb99c 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -47,7 +47,7 @@ /// assert_eq!(nucleotide_count[Nucleotide::T], 12); /// ``` #[lang = "index"] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "the type `{Self}` cannot be indexed by `{Idx}`", label = "`{Self}` cannot be indexed by `{Idx}`" )] diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 4ca5af1eaea3..380933ce1960 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -17,7 +17,7 @@ pub use self::unwind_safe::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe}; #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(core_panic, const_format_args)] +#[allow_internal_unstable(panic_internals, const_format_args)] #[rustc_diagnostic_item = "core_panic_2015_macro"] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2015 { @@ -44,7 +44,7 @@ pub macro panic_2015 { #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(core_panic, const_format_args)] +#[allow_internal_unstable(panic_internals, const_format_args)] #[rustc_diagnostic_item = "core_panic_2021_macro"] #[rustc_macro_transparency = "semitransparent"] #[cfg(feature = "panic_immediate_abort")] @@ -66,7 +66,7 @@ pub macro panic_2021 { #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] #[allow_internal_unstable( - core_panic, + panic_internals, core_intrinsics, const_dispatch, const_eval_select, @@ -109,7 +109,7 @@ pub macro panic_2021 { #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")] -#[allow_internal_unstable(core_panic)] +#[allow_internal_unstable(panic_internals)] #[rustc_diagnostic_item = "unreachable_2015_macro"] #[rustc_macro_transparency = "semitransparent"] pub macro unreachable_2015 { @@ -128,7 +128,7 @@ pub macro unreachable_2015 { #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")] -#[allow_internal_unstable(core_panic)] +#[allow_internal_unstable(panic_internals)] #[rustc_macro_transparency = "semitransparent"] pub macro unreachable_2021 { () => ( @@ -145,8 +145,8 @@ pub macro unreachable_2021 { /// unwind. For example, checks in `_unchecked` functions that are intended for debugging but should /// not compromise unwind safety. #[doc(hidden)] -#[unstable(feature = "core_panic", issue = "none")] -#[allow_internal_unstable(core_panic, const_format_args)] +#[unstable(feature = "panic_internals", issue = "none")] +#[allow_internal_unstable(panic_internals, const_format_args)] #[rustc_macro_transparency = "semitransparent"] pub macro debug_assert_nounwind { ($cond:expr $(,)?) => { diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs index 6a53909a8f12..37859212c0ee 100644 --- a/library/core/src/panic/unwind_safe.rs +++ b/library/core/src/panic/unwind_safe.rs @@ -83,7 +83,7 @@ use crate::task::{Context, Poll}; /// implemented for any closed over variables passed to `catch_unwind`. #[stable(feature = "catch_unwind", since = "1.9.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "unwind_safe_trait")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "the type `{Self}` may not be safely transferred across an unwind boundary", label = "`{Self}` may not be safely transferred across an unwind boundary" )] @@ -99,7 +99,7 @@ pub auto trait UnwindSafe {} /// [`UnwindSafe`] trait, for more information see that documentation. #[stable(feature = "catch_unwind", since = "1.9.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "ref_unwind_safe_trait")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "the type `{Self}` may contain interior mutability and a reference may not be safely \ transferrable across a catch_unwind boundary", label = "`{Self}` may contain interior mutability and a reference may not be safely \ diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 1b6e77b96b1d..0819334b600b 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -21,7 +21,7 @@ #![allow(dead_code, missing_docs)] #![unstable( - feature = "core_panic", + feature = "panic_internals", reason = "internal details of the implementation of the `panic!` and related macros", issue = "none" )] @@ -48,7 +48,7 @@ const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C #[track_caller] #[lang = "panic_fmt"] // needed for const-evaluated panics #[rustc_do_not_const_check] // hooked by const-eval -#[rustc_const_unstable(feature = "core_panic", issue = "none")] +#[rustc_const_unstable(feature = "panic_internals", issue = "none")] pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() @@ -82,7 +82,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { // and unwinds anyway, we will hit the "unwinding out of nounwind function" guard, // which causes a "panic in a function that cannot unwind". #[rustc_nounwind] -#[rustc_const_unstable(feature = "core_panic", issue = "none")] +#[rustc_const_unstable(feature = "panic_internals", issue = "none")] pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { #[inline] // this should always be inlined into `panic_nounwind_fmt` #[track_caller] @@ -132,7 +132,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] -#[rustc_const_unstable(feature = "core_panic", issue = "none")] +#[rustc_const_unstable(feature = "panic_internals", issue = "none")] #[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators pub const fn panic(expr: &'static str) -> ! { // Use Arguments::new_v1 instead of format_args!("{expr}") to potentially @@ -150,7 +150,7 @@ pub const fn panic(expr: &'static str) -> ! { #[cfg_attr(feature = "panic_immediate_abort", inline)] #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics #[rustc_nounwind] -#[rustc_const_unstable(feature = "core_panic", issue = "none")] +#[rustc_const_unstable(feature = "panic_internals", issue = "none")] pub const fn panic_nounwind(expr: &'static str) -> ! { panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ false); } @@ -166,7 +166,7 @@ pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! { #[inline] #[track_caller] #[rustc_diagnostic_item = "panic_str"] -#[rustc_const_unstable(feature = "core_panic", issue = "none")] +#[rustc_const_unstable(feature = "panic_internals", issue = "none")] pub const fn panic_str(expr: &str) -> ! { panic_display(&expr); } @@ -174,7 +174,7 @@ pub const fn panic_str(expr: &str) -> ! { #[track_caller] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] -#[rustc_const_unstable(feature = "core_panic", issue = "none")] +#[rustc_const_unstable(feature = "panic_internals", issue = "none")] pub const fn panic_explicit() -> ! { panic_display(&"explicit panic"); } @@ -191,7 +191,7 @@ pub fn unreachable_display(x: &T) -> ! { #[rustc_do_not_const_check] // hooked by const-eval // enforce a &&str argument in const-check and hook this by const-eval #[rustc_const_panic_str] -#[rustc_const_unstable(feature = "core_panic", issue = "none")] +#[rustc_const_unstable(feature = "panic_internals", issue = "none")] pub const fn panic_display(x: &T) -> ! { panic_fmt(format_args!("{}", *x)); } @@ -258,7 +258,7 @@ fn panic_in_cleanup() -> ! { /// This function is used instead of panic_fmt in const eval. #[lang = "const_panic_fmt"] -#[rustc_const_unstable(feature = "core_panic", issue = "none")] +#[rustc_const_unstable(feature = "panic_internals", issue = "none")] pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if let Some(msg) = fmt.as_str() { // The panic_display function is hooked by const eval. diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 7d8c881eab80..bb6c81a486a5 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1,188 +1,616 @@ -//! Types that pin data to its location in memory. +//! Types that pin data to a location in memory. //! -//! It is sometimes useful to have objects that are guaranteed not to move, -//! in the sense that their placement in memory does not change, and can thus be relied upon. -//! A prime example of such a scenario would be building self-referential structs, -//! as moving an object with pointers to itself will invalidate them, which could cause undefined -//! behavior. +//! It is sometimes useful to be able to rely upon a certain value not being able to *move*, +//! in the sense that its address in memory cannot change. This is useful especially when there +//! are one or more [*pointers*][pointer] pointing at that value. The ability to rely on this +//! guarantee that the value a [pointer] is pointing at (its **pointee**) will //! -//! At a high level, a [Pin]\

ensures that the pointee of any pointer type -//! `P` has a stable location in memory, meaning it cannot be moved elsewhere -//! and its memory cannot be deallocated until it gets dropped. We say that the -//! pointee is "pinned". Things get more subtle when discussing types that -//! combine pinned with non-pinned data; [see below](#projections-and-structural-pinning) -//! for more details. +//! 1. Not be *moved* out of its memory location +//! 2. More generally, remain *valid* at that same memory location //! -//! By default, all types in Rust are movable. Rust allows passing all types by-value, -//! and common smart-pointer types such as [Box]\ and [&mut] T allow -//! replacing and moving the values they contain: you can move out of a [Box]\, -//! or you can use [`mem::swap`]. [Pin]\

wraps a pointer type `P`, so -//! [Pin]<[Box]\> functions much like a regular [Box]\: -//! when a [Pin]<[Box]\> gets dropped, so do its contents, and the memory gets -//! deallocated. Similarly, [Pin]<[&mut] T> is a lot like [&mut] T. -//! However, [Pin]\

does not let clients actually obtain a [Box]\ -//! or [&mut] T to pinned data, which implies that you cannot use operations such -//! as [`mem::swap`]: +//! is called "pinning." We would say that a value which satisfies these guarantees has been +//! "pinned," in that it has been permanently (until the end of its lifespan) attached to its +//! location in memory, as though pinned to a pinboard. Pinning a value is an incredibly useful +//! building block for [`unsafe`] code to be able to reason about whether a raw pointer to the +//! pinned value is still valid. [As we'll see later][drop-guarantee], this is necessarily from the +//! time the value is first pinned until the end of its lifespan. This concept of "pinning" is +//! necessary to implement safe interfaces on top of things like self-referential types and +//! intrusive data structures which cannot currently be modeled in fully safe Rust using only +//! borrow-checked [references][reference]. +//! +//! "Pinning" allows us to put a *value* which exists at some location in memory into a state where +//! safe code cannot *move* that value to a different location in memory or otherwise invalidate it +//! at its current location (unless it implements [`Unpin`], which we will +//! [talk about below][self#unpin]). Anything that wants to interact with the pinned value in a way +//! that has the potential to violate these guarantees must promise that it will not actually +//! violate them, using the [`unsafe`] keyword to mark that such a promise is upheld by the user +//! and not the compiler. In this way, we can allow other [`unsafe`] code to rely on any pointers +//! that point to the pinned value to be valid to dereference while it is pinned. +//! +//! Note that as long as you don't use [`unsafe`], it's impossible to create or misuse a pinned +//! value in a way that is unsound. See the documentation of [`Pin`] for more +//! information on the practicalities of how to pin a value and how to use that pinned value from a +//! user's perspective without using [`unsafe`]. +//! +//! The rest of this documentation is intended to be the source of truth for users of [`Pin`] +//! that are implementing the [`unsafe`] pieces of an interface that relies on pinning for validity; +//! users of [`Pin`] in safe code do not need to read it in detail. +//! +//! There are several sections to this documentation: +//! +//! * [What is "*moving*"?][what-is-moving] +//! * [What is "pinning"?][what-is-pinning] +//! * [Address sensitivity, AKA "when do we need pinning?"][address-sensitive-values] +//! * [Examples of types with address-sensitive states][address-sensitive-examples] +//! * [Self-referential struct][self-ref] +//! * [Intrusive, doubly-linked list][linked-list] +//! * [Subtle details and the `Drop` guarantee][subtle-details] +//! +//! # What is "*moving*"? +//! [what-is-moving]: self#what-is-moving +//! +//! When we say a value is *moved*, we mean that the compiler copies, byte-for-byte, the +//! value from one location to another. In a purely mechanical sense, this is identical to +//! [`Copy`]ing a value from one place in memory to another. In Rust, "move" carries with it the +//! semantics of ownership transfer from one variable to another, which is the key difference +//! between a [`Copy`] and a move. For the purposes of this module's documentation, however, when +//! we write *move* in italics, we mean *specifically* that the value has *moved* in the mechanical +//! sense of being located at a new place in memory. +//! +//! All values in Rust are trivially *moveable*. This means that the address at which a value is +//! located is not necessarily stable in between borrows. The compiler is allowed to *move* a value +//! to a new address without running any code to notify that value that its address +//! has changed. Although the compiler will not insert memory *moves* where no semantic move has +//! occurred, there are many places where a value *may* be moved. For example, when doing +//! assignment or passing a value into a function. //! //! ``` -//! use std::pin::Pin; -//! fn swap_pins(x: Pin<&mut T>, y: Pin<&mut T>) { -//! // `mem::swap` needs `&mut T`, but we cannot get it. -//! // We are stuck, we cannot swap the contents of these references. -//! // We could use `Pin::get_unchecked_mut`, but that is unsafe for a reason: -//! // we are not allowed to use it for moving things out of the `Pin`. +//! #[derive(Default)] +//! struct AddrTracker(Option); +//! +//! impl AddrTracker { +//! // If we haven't checked the addr of self yet, store the current +//! // address. If we have, confirm that the current address is the same +//! // as it was last time, or else panic. +//! fn check_for_move(&mut self) { +//! let current_addr = self as *mut Self as usize; +//! match self.0 { +//! None => self.0 = Some(current_addr), +//! Some(prev_addr) => assert_eq!(prev_addr, current_addr), +//! } +//! } //! } +//! +//! // Create a tracker and store the initial address +//! let mut tracker = AddrTracker::default(); +//! tracker.check_for_move(); +//! +//! // Here we shadow the variable. This carries a semantic move, and may therefore also +//! // come with a mechanical memory *move* +//! let mut tracker = tracker; +//! +//! // May panic! +//! // tracker.check_for_move(); //! ``` //! -//! It is worth reiterating that [Pin]\

does *not* change the fact that a Rust -//! compiler considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, -//! [Pin]\

prevents certain *values* (pointed to by pointers wrapped in -//! [Pin]\

) from being moved by making it impossible to call methods that require -//! [&mut] T on them (like [`mem::swap`]). +//! In this sense, Rust does not guarantee that `check_for_move()` will never panic, because the +//! compiler is permitted to *move* `tracker` in many situations. //! -//! [Pin]\

can be used to wrap any pointer type `P`, and as such it interacts with -//! [`Deref`] and [`DerefMut`]. A [Pin]\

where P: [Deref] should be -//! considered as a "`P`-style pointer" to a pinned P::[Target] – so, a -//! [Pin]<[Box]\> is an owned pointer to a pinned `T`, and a -//! [Pin]<[Rc]\> is a reference-counted pointer to a pinned `T`. -//! For correctness, [Pin]\

relies on the implementations of [`Deref`] and -//! [`DerefMut`] not to move out of their `self` parameter, and only ever to -//! return a pointer to pinned data when they are called on a pinned pointer. +//! Common smart-pointer types such as [`Box`] and [`&mut T`] also allow *moving* the underlying +//! *value* they point at: you can move out of a [`Box`], or you can use [`mem::replace`] to +//! move a `T` out of a [`&mut T`]. Therefore, putting a value (such as `tracker` above) behind a +//! pointer isn't enough on its own to ensure that its address does not change. //! -//! # `Unpin` +//! # What is "pinning"? +//! [what-is-pinning]: self#what-is-pinning //! -//! Many types are always freely movable, even when pinned, because they do not -//! rely on having a stable address. This includes all the basic types (like -//! [`bool`], [`i32`], and references) as well as types consisting solely of these -//! types. Types that do not care about pinning implement the [`Unpin`] -//! auto-trait, which cancels the effect of [Pin]\

. For T: [Unpin], -//! [Pin]<[Box]\> and [Box]\ function identically, as do -//! [Pin]<[&mut] T> and [&mut] T. +//! We say that a value has been *pinned* when it has been put into a state where it is guaranteed +//! to remain *located at the same place in memory* from the time it is pinned until its +//! [`drop`] is called. //! -//! Note that pinning and [`Unpin`] only affect the pointed-to type P::[Target], -//! not the pointer type `P` itself that got wrapped in [Pin]\

. For example, -//! whether or not [Box]\ is [`Unpin`] has no effect on the behavior of -//! [Pin]<[Box]\> (here, `T` is the pointed-to type). +//! ## Address-sensitive values, AKA "when we need pinning" +//! [address-sensitive-values]: self#address-sensitive-values-aka-when-we-need-pinning //! -//! # Example: self-referential struct +//! Most values in Rust are entirely okay with being *moved* around at-will. +//! Types for which it is *always* the case that *any* value of that type can be +//! *moved* at-will should implement [`Unpin`], which we will discuss more [below][self#unpin]. //! -//! Before we go into more details to explain the guarantees and choices -//! associated with [Pin]\

, we discuss some examples for how it might be used. -//! Feel free to [skip to where the theoretical discussion continues](#drop-guarantee). +//! [`Pin`] is specifically targeted at allowing the implementation of *safe interfaces* around +//! types which have some state during which they become "address-sensitive." A value in such an +//! "address-sensitive" state is *not* okay with being *moved* around at-will. Such a value must +//! stay *un-moved* and valid during the address-sensitive portion of its lifespan because some +//! interface is relying on those invariants to be true in order for its implementation to be sound. +//! +//! As a motivating example of a type which may become address-sensitive, consider a type which +//! contains a pointer to another piece of its own data, *i.e.* a "self-referential" type. In order +//! for such a type to be implemented soundly, the pointer which points into `self`'s data must be +//! proven valid whenever it is accessed. But if that value is *moved*, the pointer will still +//! point to the old address where the value was located and not into the new location of `self`, +//! thus becoming invalid. A key example of such self-referential types are the state machines +//! generated by the compiler to implement [`Future`] for `async fn`s. +//! +//! Such types that have an *address-sensitive* state usually follow a lifecycle +//! that looks something like so: +//! +//! 1. A value is created which can be freely moved around. +//! * e.g. calling an async function which returns a state machine implementing [`Future`] +//! 2. An operation causes the value to depend on its own address not changing +//! * e.g. calling [`poll`] for the first time on the produced [`Future`] +//! 3. Further pieces of the safe interface of the type use internal [`unsafe`] operations which +//! assume that the address of the value is stable +//! * e.g. subsequent calls to [`poll`] +//! 4. Before the value is invalidated (e.g. deallocated), it is *dropped*, giving it a chance to +//! notify anything with pointers to itself that those pointers will be invalidated +//! * e.g. [`drop`]ping the [`Future`] [^pin-drop-future] +//! +//! There are two possible ways to ensure the invariants required for 2. and 3. above (which +//! apply to any address-sensitive type, not just self-referrential types) do not get broken. +//! +//! 1. Have the value detect when it is moved and update all the pointers that point to itself. +//! 2. Guarantee that the address of the value does not change (and that memory is not re-used +//! for anything else) during the time that the pointers to it are expected to be valid to +//! dereference. +//! +//! Since, as we discussed, Rust can move values without notifying them that they have moved, the +//! first option is ruled out. +//! +//! In order to implement the second option, we must in some way enforce its key invariant, +//! *i.e.* prevent the value from being *moved* or otherwise invalidated (you may notice this +//! sounds an awful lot like the definition of *pinning* a value). There a few ways one might be +//! able to enforce this invariant in Rust: +//! +//! 1. Offer a wholly `unsafe` API to interact with the object, thus requiring every caller to +//! uphold the invariant themselves +//! 2. Store the value that must not be moved behind a carefully managed pointer internal to +//! the object +//! 3. Leverage the type system to encode and enforce this invariant by presenting a restricted +//! API surface to interact with *any* object that requires these invariants +//! +//! The first option is quite obviously undesirable, as the [`unsafe`]ty of the interface will +//! become viral throughout all code that interacts with the object. +//! +//! The second option is a viable solution to the problem for some use cases, in particular +//! for self-referrential types. Under this model, any type that has an address sensitive state +//! would ultimately store its data in something like a [`Box`], carefully manage internal +//! access to that data to ensure no *moves* or other invalidation occurs, and finally +//! provide a safe interface on top. +//! +//! There are a couple of linked disadvantages to using this model. The most significant is that +//! each individual object must assume it is *on its own* to ensure +//! that its data does not become *moved* or otherwise invalidated. Since there is no shared +//! contract between values of different types, an object cannot assume that others interacting +//! with it will properly respect the invariants around interacting with its data and must +//! therefore protect it from everyone. Because of this, *composition* of address-sensitive types +//! requires at least a level of pointer indirection each time a new object is added to the mix +//! (and, practically, a heap allocation). +//! +//! Although there were other reason as well, this issue of expensive composition is the key thing +//! that drove Rust towards adopting a different model. It is particularly a problem +//! when one considers, for exapmle, the implications of composing together the [`Future`]s which +//! will eventaully make up an asynchronous task (including address-sensitive `async fn` state +//! machines). It is plausible that there could be many layers of [`Future`]s composed together, +//! including multiple layers of `async fn`s handling different parts of a task. It was deemed +//! unacceptable to force indirection and allocation for each layer of composition in this case. +//! +//! [`Pin`] is an implementation of the third option. It allows us to solve the issues +//! discussed with the second option by building a *shared contractual language* around the +//! guarantees of "pinning" data. +//! +//! [^pin-drop-future]: Futures themselves do not ever need to notify other bits of code that +//! they are being dropped, however data structures like stack-based intrusive linked lists do. +//! +//! ## Using [`Pin`] to pin values +//! +//! In order to pin a value, we wrap a *pointer to that value* (of some type `Ptr`) in a +//! [`Pin`]. [`Pin`] can wrap any pointer type, forming a promise that the **pointee** +//! will not be *moved* or [otherwise invalidated][subtle-details]. +//! +//! We call such a [`Pin`]-wrapped pointer a **pinning pointer,** (or pinning reference, or pinning +//! `Box`, etc.) because its existence is the thing that is conceptually pinning the underlying +//! pointee in place: it is the metaphorical "pin" securing the data in place on the pinboard +//! (in memory). +//! +//! Notice that the thing wrapped by [`Pin`] is not the value which we want to pin itself, but +//! rather a pointer to that value! A [`Pin`] does not pin the `Ptr`; instead, it pins the +//! pointer's ***pointee** value*. +//! +//! ### Pinning as a library contract +//! +//! Pinning does not require nor make use of any compiler "magic"[^noalias], only a specific +//! contract between the [`unsafe`] parts of a library API and its users. +//! +//! It is important to stress this point as a user of the [`unsafe`] parts of the [`Pin`] API. +//! Practically, this means that performing the mechanics of "pinning" a value by creating a +//! [`Pin`] to it *does not* actually change the way the compiler behaves towards the +//! inner value! It is possible to use incorrect [`unsafe`] code to create a [`Pin`] to a +//! value which does not actually satisfy the invariants that a pinned value must satisfy, and in +//! this way lead to undefined behavior even in (from that point) fully safe code. Similarly, using +//! [`unsafe`], one may get access to a bare [`&mut T`] from a [`Pin`] and +//! use that to invalidly *move* the pinned value out. It is the job of the user of the +//! [`unsafe`] parts of the [`Pin`] API to ensure these invariants are not violated. +//! +//! This differs from e.g. [`UnsafeCell`] which changes the semantics of a program's compiled +//! output. A [`Pin`] is a handle to a value which we have promised we will not move out of, +//! but Rust still considers all values themselves to be fundamentally moveable through, *e.g.* +//! assignment or [`mem::replace`]. +//! +//! [^noalias]: There is a bit of nuance here that is still being decided about what the aliasing +//! semantics of `Pin<&mut T>` should be, but this is true as of today. +//! +//! ### How [`Pin`] prevents misuse in safe code +//! +//! In order to accomplish the goal of pinning the pointee value, [`Pin`] restricts access to +//! the wrapped `Ptr` type in safe code. Specifically, [`Pin`] disallows the ability to access +//! the wrapped pointer in ways that would allow the user to *move* the underlying pointee value or +//! otherwise re-use that memory for something else without using [`unsafe`]. For example, a +//! [`Pin<&mut T>`] makes it impossible to obtain the wrapped [&mut] T safely because +//! through that [&mut] T it would be possible to *move* the underlying value out of +//! the pointer with [`mem::replace`], etc. +//! +//! As discussed above, this promise must be upheld manually by [`unsafe`] code which interacts +//! with the [`Pin`] so that other [`unsafe`] code can rely on the pointee value being +//! *un-moved* and valid. Interfaces that operate on values which are in an address-sensitive state +//! accept an argument like [Pin]<[&mut] T> or [Pin]<[Box]\> to +//! indicate this contract to the caller. +//! +//! [As discussed below][drop-guarantee], opting in to using pinning guarantees in the interface +//! of an address-sensitive type has consequences for the implementation of some safe traits on +//! that type as well. +//! +//! ## Interaction between [`Deref`] and [`Pin`] +//! +//! Since [`Pin`] can wrap any pointer type, it uses [`Deref`] and [`DerefMut`] in +//! order to identify the type of the pinned pointee data and provide (restricted) access to it. +//! +//! A [`Pin`] where [`Ptr: Deref`][Deref] is a "`Ptr`-style pinning pointer" to a pinned +//! [`Ptr::Target`][Target] – so, a [Pin]<[Box]\> is an owned, pinning pointer to a +//! pinned `T`, and a [Pin]<[Rc]\> is a reference-counted, pinning pointer to a +//! pinned `T`. +//! +//! [`Pin`] also uses the [`::Target`][Target] type information to modify the +//! interface it is allowed to provide for interacting with that data (for example, when a +//! pinning pointer points at pinned data which implements [`Unpin`], as +//! [discussed below][self#unpin]). +//! +//! [`Pin`] requires that implementations of [`Deref`] and [`DerefMut`] on `Ptr` return a +//! pointer to the pinned data directly and do not *move* out of the `self` parameter during their +//! implementation of [`DerefMut::deref_mut`]. It is unsound for [`unsafe`] code to wrap pointer +//! types with such "malicious" implementations of [`Deref`]; see [`Pin::new_unchecked`] for +//! details. +//! +//! ## Fixing `AddrTracker` +//! +//! The guarantee of a stable address is necessary to make our `AddrTracker` example work. When +//! `check_for_move` sees a [Pin]<&mut AddrTracker>, it can safely assume that value +//! will exist at that same address until said value goes out of scope, and thus multiple calls +//! to it *cannot* panic. +//! +//! ``` +//! use std::marker::PhantomPinned; +//! use std::pin::Pin; +//! use std::pin::pin; +//! +//! #[derive(Default)] +//! struct AddrTracker { +//! prev_addr: Option, +//! // remove auto-implemented `Unpin` bound to mark this type as having some +//! // address-sensitive state. This is essential for our expected pinning +//! // guarantees to work, and is discussed more below. +//! _pin: PhantomPinned, +//! } +//! +//! impl AddrTracker { +//! fn check_for_move(self: Pin<&mut Self>) { +//! let current_addr = &*self as *const Self as usize; +//! match self.prev_addr { +//! None => { +//! // SAFETY: we do not move out of self +//! let self_data_mut = unsafe { self.get_unchecked_mut() }; +//! self_data_mut.prev_addr = Some(current_addr); +//! }, +//! Some(prev_addr) => assert_eq!(prev_addr, current_addr), +//! } +//! } +//! } +//! +//! // 1. Create the value, not yet in an address-sensitive state +//! let tracker = AddrTracker::default(); +//! +//! // 2. Pin the value by putting it behind a pinning pointer, thus putting +//! // it into an address-sensitive state +//! let mut ptr_to_pinned_tracker: Pin<&mut AddrTracker> = pin!(tracker); +//! ptr_to_pinned_tracker.as_mut().check_for_move(); +//! +//! // Trying to access `tracker` or pass `ptr_to_pinned_tracker` to anything that requires +//! // mutable access to a non-pinned version of it will no longer compile +//! +//! // 3. We can now assume that the tracker value will never be moved, thus +//! // this will never panic! +//! ptr_to_pinned_tracker.as_mut().check_for_move(); +//! ``` +//! +//! Note that this invariant is enforced by simply making it impossible to call code that would +//! perform a move on the pinned value. This is the case since the only way to access that pinned +//! value is through the pinning [Pin]<[&mut] T>>, which in turn restricts our access. +//! +//! ## [`Unpin`] +//! +//! The vast majority of Rust types have no address-sensitive states. These types +//! implement the [`Unpin`] auto-trait, which cancels the restrictive effects of +//! [`Pin`] when the *pointee* type `T` is [`Unpin`]. When [`T: Unpin`][Unpin], +//! [Pin]<[Box]\> functions identically to a non-pinning [`Box`]; similarly, +//! [Pin]<[&mut] T> would impose no additional restrictions above a regular +//! [`&mut T`]. +//! +//! The idea of this trait is to alleviate the reduced ergonomics of APIs that require the use +//! of [`Pin`] for soundness for some types, but which also want to be used by other types that +//! don't care about pinning. The prime example of such an API is [`Future::poll`]. There are many +//! [`Future`] types that don't care about pinning. These futures can implement [`Unpin`] and +//! therefore get around the pinning related restrictions in the API, while still allowing the +//! subset of [`Future`]s which *do* require pinning to be implemented soundly. +//! +//! Note that the interaction between a [`Pin`] and [`Unpin`] is through the type of the +//! **pointee** value, [`::Target`][Target]. Whether the `Ptr` type itself +//! implements [`Unpin`] does not affect the behavior of a [`Pin`]. For example, whether or not +//! [`Box`] is [`Unpin`] has no effect on the behavior of [Pin]<[Box]\>, because +//! `T` is the type of the pointee value, not [`Box`]. So, whether `T` implements [`Unpin`] is +//! the thing that will affect the behavior of the [Pin]<[Box]\>. +//! +//! Builtin types that are [`Unpin`] include all of the primitive types, like [`bool`], [`i32`], +//! and [`f32`], references ([&]T and [&mut] T), etc., as well as many +//! core and standard library types like [`Box`], [`String`], and more. +//! These types are marked [`Unpin`] because they do not have an ddress-sensitive state like the +//! ones we discussed above. If they did have such a state, those parts of their interface would be +//! unsound without being expressed through pinning, and they would then need to not +//! implement [`Unpin`]. +//! +//! The compiler is free to take the conservative stance of marking types as [`Unpin`] so long as +//! all of the types that compose its fields are also [`Unpin`]. This is because if a type +//! implements [`Unpin`], then it is unsound for that type's implementation to rely on +//! pinning-related guarantees for soundness, *even* when viewed through a "pinning" pointer! It is +//! the responsibility of the implementor of a type that relies upon pinning for soundness to +//! ensure that type is *not* marked as [`Unpin`] by adding [`PhantomPinned`] field. This is +//! exactly what we did with our `AddrTracker` example above. Without doing this, you *must not* +//! rely on pinning-related guarantees to apply to your type! +//! +//! If need to truly pin a value of a foreign or built-in type that implements [`Unpin`], you'll +//! need to create your own wrapper type around the [`Unpin`] type you want to pin and then +//! opts-out of [`Unpin`] using [`PhantomPinned`]. +//! +//! Exposing access to the inner field which you want to remain pinned must then be carefully +//! considered as well! Remember, exposing a method that gives access to a +//! [Pin]<[&mut] InnerT>> where `InnerT: [Unpin]` would allow safe code to trivially +//! move the inner value out of that pinning pointer, which is precisely what you're seeking to +//! prevent! Exposing a field of a pinned value through a pinning pointer is called "projecting" +//! a pin, and the more general case of deciding in which cases a pin should be able to be +//! projected or not is called "structural pinning." We will go into more detail about this +//! [below][structural-pinning]. +//! +//! # Examples of address-sensitive types +//! [address-sensitive-examples]: #examples-of-address-sensitive-types +//! +//! ## A self-referential struct +//! [self-ref]: #a-self-referential-struct +//! [`Unmovable`]: #a-self-referential-struct +//! +//! Self-referential structs are the simplest kind of address-sensitive type. +//! +//! It is often useful for a struct to hold a pointer back into itself, which +//! allows the program to efficiently track subsections of the struct. +//! Below, the `slice` field is a pointer into the `data` field, which +//! we could imagine being used to track a sliding window of `data` in parser +//! code. +//! +//! As mentioned before, this pattern is also used extensively by compiler-generated +//! [`Future`]s. //! //! ```rust //! use std::pin::Pin; //! use std::marker::PhantomPinned; //! use std::ptr::NonNull; //! -//! // This is a self-referential struct because the slice field points to the data field. -//! // We cannot inform the compiler about that with a normal reference, -//! // as this pattern cannot be described with the usual borrowing rules. -//! // Instead we use a raw pointer, though one which is known not to be null, -//! // as we know it's pointing at the string. +//! /// This is a self-referential struct because `self.slice` points into `self.data`. //! struct Unmovable { -//! data: String, -//! slice: NonNull, +//! /// Backing buffer. +//! data: [u8; 64], +//! /// Points at `self.data` which we know is itself non-null. Raw pointer because we can't do +//! /// this with a normal reference. +//! slice: NonNull<[u8]>, +//! /// Suppress `Unpin` so that this cannot be moved out of a `Pin` once constructed. //! _pin: PhantomPinned, //! } //! //! impl Unmovable { -//! // To ensure the data doesn't move when the function returns, -//! // we place it in the heap where it will stay for the lifetime of the object, -//! // and the only way to access it would be through a pointer to it. -//! fn new(data: String) -> Pin> { +//! /// Create a new `Unmovable`. +//! /// +//! /// To ensure the data doesn't move we place it on the heap behind a pinning Box. +//! /// Note that the data is pinned, but the `Pin>` which is pinning it can +//! /// itself still be moved. This is important because it means we can return the pinning +//! /// pointer from the function, which is itself a kind of move! +//! fn new() -> Pin> { //! let res = Unmovable { -//! data, -//! // we only create the pointer once the data is in place -//! // otherwise it will have already moved before we even started -//! slice: NonNull::dangling(), +//! data: [0; 64], +//! // We only create the pointer once the data is in place +//! // otherwise it will have already moved before we even started. +//! slice: NonNull::from(&[]), //! _pin: PhantomPinned, //! }; -//! let mut boxed = Box::pin(res); +//! // First we put the data in a box, which will be its final resting place +//! let mut boxed = Box::new(res); //! -//! let slice = NonNull::from(&boxed.data); -//! // we know this is safe because modifying a field doesn't move the whole struct -//! unsafe { -//! let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut boxed); -//! Pin::get_unchecked_mut(mut_ref).slice = slice; -//! } -//! boxed +//! // Then we make the slice field point to the proper part of that boxed data. +//! // From now on we need to make sure we don't move the boxed data. +//! boxed.slice = NonNull::from(&boxed.data); +//! +//! // To do that, we pin the data in place by pointing to it with a pinning +//! // (`Pin`-wrapped) pointer. +//! // +//! // `Box::into_pin` makes existing `Box` pin the data in-place without moving it, +//! // so we can safely do this now *after* inserting the slice pointer above, but we have +//! // to take care that we haven't performed any other semantic moves of `res` in between. +//! let pin = Box::into_pin(boxed); +//! +//! // Now we can return the pinned (through a pinning Box) data +//! pin //! } //! } //! -//! let unmoved = Unmovable::new("hello".to_string()); -//! // The pointer should point to the correct location, -//! // so long as the struct hasn't moved. +//! let unmovable: Pin> = Unmovable::new(); +//! +//! // The inner pointee `Unmovable` struct will now never be allowed to move. //! // Meanwhile, we are free to move the pointer around. //! # #[allow(unused_mut)] -//! let mut still_unmoved = unmoved; +//! let mut still_unmoved = unmovable; //! assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data)); //! -//! // Since our type doesn't implement Unpin, this will fail to compile: -//! // let mut new_unmoved = Unmovable::new("world".to_string()); +//! // We cannot mutably dereference a `Pin` unless the pointee is `Unpin` or we use unsafe. +//! // Since our type doesn't implement `Unpin`, this will fail to compile. +//! // let mut new_unmoved = Unmovable::new(); //! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved); //! ``` //! -//! # Example: intrusive doubly-linked list +//! ## An intrusive, doubly-linked list +//! [linked-list]: #an-intrusive-doubly-linked-list //! -//! In an intrusive doubly-linked list, the collection does not actually allocate -//! the memory for the elements itself. Allocation is controlled by the clients, -//! and elements can live on a stack frame that lives shorter than the collection does. +//! In an intrusive doubly-linked list, the collection itself does not own the memory in which +//! each of its elements is stored. Instead, each client is free to allocate space for elements it +//! adds to the list in whichever manner it likes, including on the stack! Elements can live on a +//! stack frame that lives shorter than the collection does provided the elements that live in a +//! given stack frame are removed from the list before going out of scope. //! -//! To make this work, every element has pointers to its predecessor and successor in -//! the list. Elements can only be added when they are pinned, because moving the elements -//! around would invalidate the pointers. Moreover, the [`Drop`][Drop] implementation of a linked -//! list element will patch the pointers of its predecessor and successor to remove itself -//! from the list. +//! To make such an intrusive data structure work, every element stores pointers to its predecessor +//! and successor within its own data, rather than having the list structure itself managing those +//! pointers. It is in this sense that the structure is "intrusive": the details of how an +//! element is stored within the larger structure "intrudes" on the implementation of the element +//! type itself! //! -//! Crucially, we have to be able to rely on [`drop`] being called. If an element -//! could be deallocated or otherwise invalidated without calling [`drop`], the pointers into it -//! from its neighboring elements would become invalid, which would break the data structure. +//! The full implementation details of such a data structure are outside the scope of this +//! documentation, but we will discuss how [`Pin`] can help to do so. //! -//! Therefore, pinning also comes with a [`drop`]-related guarantee. +//! Using such an intrusive pattern, elements may only be added when they are pinned. If we think +//! about the consequences of adding non-pinned values to such a list, this becomes clear: //! -//! # `Drop` guarantee +//! *Moving* or otherwise invalidating an element's data would invalidate the pointers back to it +//! which are stored in the elements ahead and behind it. Thus, in order to soundly dereference +//! the pointers stored to the next and previous elements, we must satisfy the guarantee that +//! nothing has invalidated those pointers (which point to data that we do not own). //! -//! The purpose of pinning is to be able to rely on the placement of some data in memory. -//! To make this work, not just moving the data is restricted; deallocating, repurposing, or -//! otherwise invalidating the memory used to store the data is restricted, too. -//! Concretely, for pinned data you have to maintain the invariant -//! that *its memory will not get invalidated or repurposed from the moment it gets pinned until -//! when [`drop`] is called*. Only once [`drop`] returns or panics, the memory may be reused. +//! Moreover, the [`Drop`][Drop] implementation of each element must in some way notify its +//! predecessor and successor elements that it should be removed from the list before it is fully +//! destroyed, otherwise the pointers back to it would again become invalidated. //! -//! Memory can be "invalidated" by deallocation, but also by -//! replacing a [Some]\(v) by [`None`], or calling [`Vec::set_len`] to "kill" some -//! elements off of a vector. It can be repurposed by using [`ptr::write`] to overwrite it without -//! calling the destructor first. None of this is allowed for pinned data without calling [`drop`]. +//! Crucially, this means we have to be able to rely on [`drop`] always being called before an +//! element is invalidated. If an element could be deallocated or otherwise invalidated without +//! calling [`drop`], the pointers to it stored in its neighboring elements would +//! become invalid, which would break the data structure. //! -//! This is exactly the kind of guarantee that the intrusive linked list from the previous -//! section needs to function correctly. +//! Therefore, pinning data also comes with [the "`Drop` guarantee"][drop-guarantee]. //! -//! Notice that this guarantee does *not* mean that memory does not leak! It is still -//! completely okay to not ever call [`drop`] on a pinned element (e.g., you can still -//! call [`mem::forget`] on a [Pin]<[Box]\>). In the example of the doubly-linked -//! list, that element would just stay in the list. However you must not free or reuse the storage -//! *without calling [`drop`]*. +//! # Subtle details and the `Drop` guarantee +//! [subtle-details]: self#subtle-details-and-the-drop-guarantee +//! [drop-guarantee]: self#subtle-details-and-the-drop-guarantee //! -//! # `Drop` implementation +//! The purpose of pinning is not *just* to prevent a value from being *moved*, but more +//! generally to be able to rely on the pinned value *remaining valid **at a specific place*** in +//! memory. //! -//! If your type uses pinning (such as the two examples above), you have to be careful -//! when implementing [`Drop`][Drop]. The [`drop`] function takes [&mut] self, but this -//! is called *even if your type was previously pinned*! It is as if the -//! compiler automatically called [`Pin::get_unchecked_mut`]. +//! To do so, pinning a value adds an *additional* invariant that must be upheld in order for use +//! of the pinned data to be valid, on top of the ones that must be upheld for a non-pinned value +//! of the same type to be valid: //! -//! This can never cause a problem in safe code because implementing a type that -//! relies on pinning requires unsafe code, but be aware that deciding to make -//! use of pinning in your type (for example by implementing some operation on -//! [Pin]<[&]Self> or [Pin]<[&mut] Self>) has consequences for your +//! From the moment a value is pinned by constructing a [`Pin`]ning pointer to it, that value +//! must *remain, **valid***, at that same address in memory, *until its [`drop`] handler is +//! called.* +//! +//! There is some subtlety to this which we have not yet talked about in detail. The invariant +//! described above means that, yes, +//! +//! 1. The value must not be moved out of its location in memory +//! +//! but it also implies that, +//! +//! 2. The memory location that stores the value must not get invalidated or otherwise repurposed +//! during the lifespan of the pinned value until its [`drop`] returns or panics +//! +//! This point is subtle but required for intrusive data structures to be implemented soundly. +//! +//! ## `Drop` guarantee +//! +//! There needs to be a way for a pinned value to notify any code that is relying on its pinned +//! status that it is about to be destroyed. In this way, the dependent code can remove the +//! pinned value's address from its data structures or otherwise change its behavior with the +//! knowledge that it can no longer rely on that value existing at the location it was pinned to. +//! +//! Thus, in any situation where we may want to overwrite a pinned value, that value's [`drop`] must +//! be called beforehand (unless the pinned value implements [`Unpin`], in which case we can ignore +//! all of [`Pin`]'s guarantees, as usual). +//! +//! The most common storage-reuse situations occur when a value on the stack is destroyed as part +//! of a function return and when heap storage is freed. In both cases, [`drop`] gets run for us +//! by Rust when using standard safe code. However, for manual heap allocations or otherwise +//! custom-allocated storage, [`unsafe`] code must make sure to call [`ptr::drop_in_place`] before +//! deallocating and re-using said storage. +//! +//! In addition, storage "re-use"/invalidation can happen even if no storage is (de-)allocated. +//! For example, if we had an [`Option`] which contained a `Some(v)` where `v` is pinned, then `v` +//! would be invalidated by setting that option to `None`. +//! +//! Similarly, if a [`Vec`] was used to store pinned values and [`Vec::set_len`] was used to +//! manually "kill" some elements of a vector, all of the items "killed" would become invalidated, +//! which would be *undefined behavior* if those items were pinned. +//! +//! Both of these cases are somewhat contrived, but it is crucial to remember that [`Pin`]ned data +//! *must* be [`drop`]ped before it is invalidated; not just to prevent memory leaks, but as a +//! matter of soundness. As a corollary, the following code can *never* be made safe: +//! +//! ```rust +//! # use std::mem::ManuallyDrop; +//! # use std::pin::Pin; +//! # struct Type; +//! // Pin something inside a `ManuallyDrop`. This is fine on its own. +//! let mut pin: Pin>> = Box::pin(ManuallyDrop::new(Type)); +//! +//! // However, creating a pinning mutable reference to the type *inside* +//! // the `ManuallyDrop` is not! +//! let inner: Pin<&mut Type> = unsafe { +//! Pin::map_unchecked_mut(pin.as_mut(), |x| &mut **x) +//! }; +//! ``` +//! +//! Because [`mem::ManuallyDrop`] inhibits the destructor of `Type`, it won't get run when the +//! [Box]<[ManuallyDrop]\> is dropped, thus violating the drop guarantee of the +//! [Pin]<[&mut] Type>>. +//! +//! Of course, *leaking* memory in such a way that its underlying storage will never get invalidated +//! or re-used is still fine: [`mem::forget`]ing a [`Box`] prevents its storage from ever getting +//! re-used, so the [`drop`] guarantee is still satisfied. +//! +//! # Implementing an address-sensitive type. +//! +//! This section goes into detail on important considerations for implementing your own +//! address-sensitive types, which are different from merely using [`Pin`] in a generic +//! way. +//! +//! ## Implementing [`Drop`] for types with address-sensitive states +//! [drop-impl]: self#implementing-drop-for-types-with-address-sensitive-states +//! +//! The [`drop`] function takes [`&mut self`], but this is called *even if that `self` has been +//! pinned*! Implementing [`Drop`] for a type with address-sensitive states, because if `self` was +//! indeed in an address-sensitive state before [`drop`] was called, it is as if the compiler +//! automatically called [`Pin::get_unchecked_mut`]. +//! +//! This can never cause a problem in purely safe code because creating a pinning pointer to +//! a type which has an address-sensitive (thus does not implement `Unpin`) requires `unsafe`, +//! but it is important to note that choosing to take advantage of pinning-related guarantees +//! to justify validity in the implementation of your type has consequences for that type's //! [`Drop`][Drop] implementation as well: if an element of your type could have been pinned, -//! you must treat [`Drop`][Drop] as implicitly taking [Pin]<[&mut] Self>. +//! you must treat [`Drop`][Drop] as implicitly taking self: [Pin]<[&mut] Self>. //! -//! For example, you could implement [`Drop`][Drop] as follows: +//! You should implement [`Drop`] as follows: //! //! ```rust,no_run //! # use std::pin::Pin; -//! # struct Type { } +//! # struct Type; //! impl Drop for Type { //! fn drop(&mut self) { //! // `new_unchecked` is okay because we know this value is never used @@ -195,72 +623,157 @@ //! } //! ``` //! -//! The function `inner_drop` has the type that [`drop`] *should* have, so this makes sure that -//! you do not accidentally use `self`/`this` in a way that is in conflict with pinning. +//! The function `inner_drop` has the signature that [`drop`] *should* have in this situation. +//! This makes sure that you do not accidentally use `self`/`this` in a way that is in conflict +//! with pinning's invariants. //! -//! Moreover, if your type is `#[repr(packed)]`, the compiler will automatically +//! Moreover, if your type is [`#[repr(packed)]`][packed], the compiler will automatically //! move fields around to be able to drop them. It might even do //! that for fields that happen to be sufficiently aligned. As a consequence, you cannot use -//! pinning with a `#[repr(packed)]` type. +//! pinning with a [`#[repr(packed)]`][packed] type. //! -//! # Projections and Structural Pinning +//! ### Implementing [`Drop`] for pointer types which will be used as [`Pin`]ning pointers //! -//! When working with pinned structs, the question arises how one can access the -//! fields of that struct in a method that takes just [Pin]<[&mut] Struct>. -//! The usual approach is to write helper methods (so called *projections*) -//! that turn [Pin]<[&mut] Struct> into a reference to the field, but what type should -//! that reference have? Is it [Pin]<[&mut] Field> or [&mut] Field? -//! The same question arises with the fields of an `enum`, and also when considering -//! container/wrapper types such as [Vec]\, [Box]\, -//! or [RefCell]\. (This question applies to both mutable and shared references, -//! we just use the more common case of mutable references here for illustration.) +//! It should further be noted that creating a pinning pointer of some type `Ptr` *also* carries +//! with it implications on the way that `Ptr` type must implement [`Drop`] +//! (as well as [`Deref`] and [`DerefMut`])! When implementing a pointer type that may be used as +//! a pinning pointer, you must also take the same care described above not to *move* out of or +//! otherwise invalidate the pointee during [`Drop`], [`Deref`], or [`DerefMut`] +//! implementations. //! -//! It turns out that it is actually up to the author of the data structure to decide whether -//! the pinned projection for a particular field turns [Pin]<[&mut] Struct> -//! into [Pin]<[&mut] Field> or [&mut] Field. There are some -//! constraints though, and the most important constraint is *consistency*: -//! every field can be *either* projected to a pinned reference, *or* have -//! pinning removed as part of the projection. If both are done for the same field, -//! that will likely be unsound! +//! ## "Assigning" pinned data //! -//! As the author of a data structure you get to decide for each field whether pinning +//! Although in general it is not valid to swap data or assign through a [`Pin`] for the same +//! reason that reusing a pinned object's memory is invalid, it is possible to do validly when +//! implemented with special care for the needs of the exact data structure which is being +//! modified. For example, the assigning function must know how to update all uses of the pinned +//! address (and any other invariants necessary to satisfy validity for that type). For +//! [`Unmovable`] (from the example above), we could write an assignment function like so: +//! +//! ``` +//! # use std::pin::Pin; +//! # use std::marker::PhantomPinned; +//! # use std::ptr::NonNull; +//! # struct Unmovable { +//! # data: [u8; 64], +//! # slice: NonNull<[u8]>, +//! # _pin: PhantomPinned, +//! # } +//! # +//! impl Unmovable { +//! // Copies the contents of `src` into `self`, fixing up the self-pointer +//! // in the process. +//! fn assign(self: Pin<&mut Self>, src: Pin<&mut Self>) { +//! unsafe { +//! let unpinned_self = Pin::into_inner_unchecked(self); +//! let unpinned_src = Pin::into_inner_unchecked(src); +//! *unpinned_self = Self { +//! data: unpinned_src.data, +//! slice: NonNull::from(&mut []), +//! _pin: PhantomPinned, +//! }; +//! +//! let data_ptr = unpinned_src.data.as_ptr() as *const u8; +//! let slice_ptr = unpinned_src.slice.as_ptr() as *const u8; +//! let offset = slice_ptr.offset_from(data_ptr) as usize; +//! let len = (*unpinned_src.slice.as_ptr()).len(); +//! +//! unpinned_self.slice = NonNull::from(&mut unpinned_self.data[offset..offset+len]); +//! } +//! } +//! } +//! ``` +//! +//! Even though we can't have the compiler do the assignment for us, it's possible to write +//! such specialized functions for types that might need it. +//! +//! Note that it _is_ possible to assign generically through a [`Pin`] by way of [`Pin::set()`]. +//! This does not violate any guarantees, since it will run [`drop`] on the pointee value before +//! assigning the new value. Thus, the [`drop`] implementation still has a chance to perform the +//! necessary notifications to dependent values before the memory location of the original pinned +//! value is overwritten. +//! +//! ## Projections and Structural Pinning +//! [structural-pinning]: self#projections-and-structural-pinning +//! +//! With ordinary structs, it is natural that we want to add *projection* methods that allow +//! borrowing one or more of the inner fields of a struct when the caller has access to a +//! borrow of the whole struct: +//! +//! ``` +//! # struct Field; +//! struct Struct { +//! field: Field, +//! // ... +//! } +//! +//! impl Struct { +//! fn field(&mut self) -> &mut Field { &mut self.field } +//! } +//! ``` +//! +//! When working with address-sensitive types, it's not obvious what the signature of these +//! functions should be. If `field` takes self: [Pin]<[&mut Struct][&mut]>, should it +//! return [`&mut Field`] or [Pin]<[`&mut Field`]>? This question also arises with +//! `enum`s and wrapper types like [`Vec`], [`Box`], and [`RefCell`]. (This question +//! applies just as well to shared references, but we'll examine the more common case of mutable +//! references for illustration) +//! +//! It turns out that it's up to the author of `Struct` to decide which type the "projection" +//! should produce. The choice must be *consistent* though: if a pin is projected to a field +//! in one place, then it should very likely not be exposed elsewhere without projecting the +//! pin. +//! +//! As the author of a data structure, you get to decide for each field whether pinning //! "propagates" to this field or not. Pinning that propagates is also called "structural", //! because it follows the structure of the type. -//! In the following subsections, we describe the considerations that have to be made -//! for either choice. //! -//! ## Pinning *is not* structural for `field` +//! This choice depends on what guarantees you need from the field for your [`unsafe`] code to work. +//! If the field is itself address-sensitive, or participates in the parent struct's address +//! sensitivity, it will need to be structurally pinned. //! -//! It may seem counter-intuitive that the field of a pinned struct might not be pinned, -//! but that is actually the easiest choice: if a [Pin]<[&mut] Field> is never created, -//! nothing can go wrong! So, if you decide that some field does not have structural pinning, -//! all you have to ensure is that you never create a pinned reference to that field. +//! A useful test is if [`unsafe`] code that consumes [Pin]\<[&mut Struct][&mut]> +//! also needs to take note of the address of the field itself, it may be evidence that that field +//! is structurally pinned. Unfortunately, there are no hard-and-fast rules. +//! +//! ### Choosing pinning *not to be* structural for `field`... +//! +//! While counter-intuitive, it's often the easier choice: if you do not expose a +//! [Pin]<[&mut] Field>, you do not need to be careful about other code +//! moving out of that field, you just have to ensure is that you never create pinning +//! reference to that field. This does of course also mean that if you decide a field does not +//! have structural pinning, you must not write [`unsafe`] code that assumes (invalidly) that the +//! field *is* structurally pinned! //! //! Fields without structural pinning may have a projection method that turns -//! [Pin]<[&mut] Struct> into [&mut] Field: +//! [Pin]<[&mut] Struct> into [`&mut Field`]: //! //! ```rust,no_run //! # use std::pin::Pin; //! # type Field = i32; //! # struct Struct { field: Field } //! impl Struct { -//! fn pin_get_field(self: Pin<&mut Self>) -> &mut Field { -//! // This is okay because `field` is never considered pinned. +//! fn field(self: Pin<&mut Self>) -> &mut Field { +//! // This is okay because `field` is never considered pinned, therefore we do not +//! // need to uphold any pinning guarantees for this field in particular. Of course, +//! // we must not elsewhere assume this field *is* pinned if we choose to expose +//! // such a method! //! unsafe { &mut self.get_unchecked_mut().field } //! } //! } //! ``` //! -//! You may also impl [Unpin] for Struct *even if* the type of `field` -//! is not [`Unpin`]. What that type thinks about pinning is not relevant -//! when no [Pin]<[&mut] Field> is ever created. +//! You may also in this situation impl [Unpin] for Struct {} *even if* the type of +//! `field` is not [`Unpin`]. Since we have explicitly chosen not to care about pinning guarantees +//! for `field`, the way `field`'s type interacts with pinning is no longer relevant in the +//! context of its use in `Struct`. //! -//! ## Pinning *is* structural for `field` +//! ### Choosing pinning *to be* structural for `field`... //! //! The other option is to decide that pinning is "structural" for `field`, //! meaning that if the struct is pinned then so is the field. //! -//! This allows writing a projection that creates a [Pin]<[&mut] Field>, thus +//! This allows writing a projection that creates a [Pin]<[`&mut Field`]>, thus //! witnessing that the field is pinned: //! //! ```rust,no_run @@ -268,108 +781,117 @@ //! # type Field = i32; //! # struct Struct { field: Field } //! impl Struct { -//! fn pin_get_field(self: Pin<&mut Self>) -> Pin<&mut Field> { +//! fn field(self: Pin<&mut Self>) -> Pin<&mut Field> { //! // This is okay because `field` is pinned when `self` is. //! unsafe { self.map_unchecked_mut(|s| &mut s.field) } //! } //! } //! ``` //! -//! However, structural pinning comes with a few extra requirements: +//! Structural pinning comes with a few extra requirements: //! -//! 1. The struct must only be [`Unpin`] if all the structural fields are -//! [`Unpin`]. This is the default, but [`Unpin`] is a safe trait, so as the author of -//! the struct it is your responsibility *not* to add something like -//! impl\ [Unpin] for Struct\. (Notice that adding a projection operation -//! requires unsafe code, so the fact that [`Unpin`] is a safe trait does not break -//! the principle that you only have to worry about any of this if you use [`unsafe`].) -//! 2. The destructor of the struct must not move structural fields out of its argument. This -//! is the exact point that was raised in the [previous section][drop-impl]: [`drop`] takes -//! [&mut] self, but the struct (and hence its fields) might have been pinned -//! before. You have to guarantee that you do not move a field inside your [`Drop`][Drop] -//! implementation. In particular, as explained previously, this means that your struct -//! must *not* be `#[repr(packed)]`. -//! See that section for how to write [`drop`] in a way that the compiler can help you -//! not accidentally break pinning. -//! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: -//! once your struct is pinned, the memory that contains the -//! content is not overwritten or deallocated without calling the content's destructors. -//! This can be tricky, as witnessed by [VecDeque]\: the destructor of -//! [VecDeque]\ can fail to call [`drop`] on all elements if one of the -//! destructors panics. This violates the [`Drop`][Drop] guarantee, because it can lead to -//! elements being deallocated without their destructor being called. -//! ([VecDeque]\ has no pinning projections, so this -//! does not cause unsoundness.) -//! 4. You must not offer any other operations that could lead to data being moved out of +//! 1. *Structural [`Unpin`].* A struct can be [`Unpin`] only if all of its +//! structurally-pinned fields are, too. This is [`Unpin`]'s behavior by default. +//! However, as a libray author, it is your responsibility not to write something like +//! impl\ [Unpin] for Struct\ {} and then offer a method that provides +//! structural pinning to an inner field of `T`, which may not be [`Unpin`]! (Adding *any* +//! projection operation requires unsafe code, so the fact that [`Unpin`] is a safe trait does +//! not break the principle that you only have to worry about any of this if you use +//! [`unsafe`]) +//! +//! 2. *Pinned Destruction.* As discussed [above][drop-impl], [`drop`] takes +//! [`&mut self`], but the struct (and hence its fields) might have been pinned +//! before. The destructor must be written as if its argument was +//! self: [Pin]\<[`&mut Self`]>, instead. +//! +//! As a consequence, the struct *must not* be [`#[repr(packed)]`][packed]. +//! +//! 3. *Structural Notice of Destruction.* You must uphold the the +//! [`Drop` guarantee][drop-guarantee]: once your struct is pinned, the struct's storage cannot +//! be re-used without calling the structurally-pinned fields' destructors, as well. +//! +//! This can be tricky, as witnessed by [`VecDeque`]: the destructor of [`VecDeque`] +//! can fail to call [`drop`] on all elements if one of the destructors panics. This violates +//! the [`Drop` guarantee][drop-guarantee], because it can lead to elements being deallocated +//! without their destructor being called. +//! +//! [`VecDeque`] has no pinning projections, so its destructor is sound. If it wanted +//! to provide such structural pinning, its destructor would need to abort the process if any +//! of the destructors panicked. +//! +//! 4. You must not offer any other operations that could lead to data being *moved* out of //! the structural fields when your type is pinned. For example, if the struct contains an -//! [Option]\ and there is a [`take`][Option::take]-like operation with type -//! fn([Pin]<[&mut] Struct\>) -> [Option]\, -//! that operation can be used to move a `T` out of a pinned `Struct` – which means -//! pinning cannot be structural for the field holding this data. +//! [`Option`] and there is a [`take`][Option::take]-like operation with type +//! fn([Pin]<[&mut Struct\][&mut]>) -> [`Option`], +//! then that operation can be used to move a `T` out of a pinned `Struct` – which +//! means pinning cannot be structural for the field holding this data. //! //! For a more complex example of moving data out of a pinned type, -//! imagine if [RefCell]\ had a method -//! fn get_pin_mut(self: [Pin]<[&mut] Self>) -> [Pin]<[&mut] T>. +//! imagine if [`RefCell`] had a method +//! fn get_pin_mut(self: [Pin]<[`&mut Self`]>) -> [Pin]<[`&mut T`]>. //! Then we could do the following: //! ```compile_fail +//! # use std::cell::RefCell; +//! # use std::pin::Pin; //! fn exploit_ref_cell(rc: Pin<&mut RefCell>) { -//! { let p = rc.as_mut().get_pin_mut(); } // Here we get pinned access to the `T`. -//! let rc_shr: &RefCell = rc.into_ref().get_ref(); -//! let b = rc_shr.borrow_mut(); -//! let content = &mut *b; // And here we have `&mut T` to the same data. +//! // Here we get pinned access to the `T`. +//! let _: Pin<&mut T> = rc.as_mut().get_pin_mut(); +//! +//! // And here we have `&mut T` to the same data. +//! let shared: &RefCell = rc.into_ref().get_ref(); +//! let borrow = shared.borrow_mut(); +//! let content = &mut *borrow; //! } //! ``` -//! This is catastrophic, it means we can first pin the content of the -//! [RefCell]\ (using [RefCell]::get_pin_mut) and then move that +//! This is catastrophic: it means we can first pin the content of the +//! [`RefCell`] (using [RefCell]::get_pin_mut) and then move that //! content using the mutable reference we got later. //! -//! ## Examples +//! ### Structural Pinning examples //! -//! For a type like [Vec]\, both possibilities (structural pinning or not) make -//! sense. A [Vec]\ with structural pinning could have `get_pin`/`get_pin_mut` -//! methods to get pinned references to elements. However, it could *not* allow calling -//! [`pop`][Vec::pop] on a pinned [Vec]\ because that would move the (structurally +//! For a type like [`Vec`], both possibilities (structural pinning or not) make +//! sense. A [`Vec`] with structural pinning could have `get_pin`/`get_pin_mut` +//! methods to get pinning references to elements. However, it could *not* allow calling +//! [`pop`][Vec::pop] on a pinned [`Vec`] because that would move the (structurally //! pinned) contents! Nor could it allow [`push`][Vec::push], which might reallocate and thus also //! move the contents. //! -//! A [Vec]\ without structural pinning could -//! impl\ [Unpin] for [Vec]\, because the contents are never pinned -//! and the [Vec]\ itself is fine with being moved as well. +//! A [`Vec`] without structural pinning could +//! impl\ [Unpin] for [`Vec`], because the contents are never pinned +//! and the [`Vec`] itself is fine with being moved as well. //! At that point pinning just has no effect on the vector at all. //! //! In the standard library, pointer types generally do not have structural pinning, -//! and thus they do not offer pinning projections. This is why [Box]\: [Unpin] +//! and thus they do not offer pinning projections. This is why [`Box`]: [Unpin] //! holds for all `T`. It makes sense to do this for pointer types, because moving the -//! [Box]\ does not actually move the `T`: the [Box]\ can be freely -//! movable (aka [`Unpin`]) even if the `T` is not. In fact, even [Pin]<[Box]\> and -//! [Pin]<[&mut] T> are always [`Unpin`] themselves, for the same reason: +//! [`Box`] does not actually move the `T`: the [`Box`] can be freely +//! movable (aka [`Unpin`]) even if the `T` is not. In fact, even [Pin]<[`Box`]> and +//! [Pin]<[`&mut T`]> are always [`Unpin`] themselves, for the same reason: //! their contents (the `T`) are pinned, but the pointers themselves can be moved without moving -//! the pinned data. For both [Box]\ and [Pin]<[Box]\>, +//! the pinned data. For both [`Box`] and [Pin]<[`Box`]>, //! whether the content is pinned is entirely independent of whether the //! pointer is pinned, meaning pinning is *not* structural. //! //! When implementing a [`Future`] combinator, you will usually need structural pinning -//! for the nested futures, as you need to get pinned references to them to call [`poll`]. -//! But if your combinator contains any other data that does not need to be pinned, +//! for the nested futures, as you need to get pinning ([`Pin`]-wrapped) references to them to +//! call [`poll`]. But if your combinator contains any other data that does not need to be pinned, //! you can make those fields not structural and hence freely access them with a -//! mutable reference even when you just have [Pin]<[&mut] Self> (such as in your own -//! [`poll`] implementation). +//! mutable reference even when you just have [Pin]<[`&mut Self`]> +//! (such as in your own [`poll`] implementation). //! +//! [`&mut T`]: &mut +//! [`&mut self`]: &mut +//! [`&mut Self`]: &mut +//! [`&mut Field`]: &mut //! [Deref]: crate::ops::Deref "ops::Deref" //! [`Deref`]: crate::ops::Deref "ops::Deref" //! [Target]: crate::ops::Deref::Target "ops::Deref::Target" //! [`DerefMut`]: crate::ops::DerefMut "ops::DerefMut" //! [`mem::swap`]: crate::mem::swap "mem::swap" //! [`mem::forget`]: crate::mem::forget "mem::forget" -//! [Vec]: ../../std/vec/struct.Vec.html "Vec" -//! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len "Vec::set_len" -//! [Box]: ../../std/boxed/struct.Box.html "Box" -//! [Vec::pop]: ../../std/vec/struct.Vec.html#method.pop "Vec::pop" -//! [Vec::push]: ../../std/vec/struct.Vec.html#method.push "Vec::push" -//! [Rc]: ../../std/rc/struct.Rc.html "rc::Rc" +//! [ManuallyDrop]: crate::mem::ManuallyDrop "ManuallyDrop" //! [RefCell]: crate::cell::RefCell "cell::RefCell" //! [`drop`]: Drop::drop -//! [VecDeque]: ../../std/collections/struct.VecDeque.html "collections::VecDeque" //! [`ptr::write`]: crate::ptr::write "ptr::write" //! [`Future`]: crate::future::Future "future::Future" //! [drop-impl]: #drop-implementation @@ -378,6 +900,23 @@ //! [&]: reference "shared reference" //! [&mut]: reference "mutable reference" //! [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe" +//! [packed]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprpacked +//! [`std::alloc`]: ../../std/alloc/index.html +//! [`Box`]: ../../std/boxed/struct.Box.html +//! [Box]: ../../std/boxed/struct.Box.html "Box" +//! [`Box`]: ../../std/boxed/struct.Box.html "Box" +//! [`Rc`]: ../../std/rc/struct.Rc.html +//! [Rc]: ../../std/rc/struct.Rc.html "rc::Rc" +//! [`Vec`]: ../../std/vec/struct.Vec.html +//! [Vec]: ../../std/vec/struct.Vec.html "Vec" +//! [`Vec`]: ../../std/vec/struct.Vec.html "Vec" +//! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len "Vec::set_len" +//! [Vec::pop]: ../../std/vec/struct.Vec.html#method.pop "Vec::pop" +//! [Vec::push]: ../../std/vec/struct.Vec.html#method.push "Vec::push" +//! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len +//! [`VecDeque`]: ../../std/collections/struct.VecDeque.html +//! [VecDeque]: ../../std/collections/struct.VecDeque.html "collections::VecDeque" +//! [`String`]: ../../std/string/struct.String.html "String" #![stable(feature = "pin", since = "1.33.0")] @@ -386,17 +925,159 @@ use crate::fmt; use crate::hash::{Hash, Hasher}; use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver}; -/// A pinned pointer. +#[allow(unused_imports)] +use crate::{ + cell::{RefCell, UnsafeCell}, + future::Future, + marker::PhantomPinned, + mem, ptr, +}; + +/// A pointer which pins its pointee in place. /// -/// This is a wrapper around a kind of pointer which makes that pointer "pin" its -/// value in place, preventing the value referenced by that pointer from being moved -/// unless it implements [`Unpin`]. +/// [`Pin`] is a wrapper around some kind of pointer `Ptr` which makes that pointer "pin" its +/// pointee value in place, thus preventing the value referenced by that pointer from being moved +/// or otherwise invalidated at that place in memory unless it implements [`Unpin`]. /// -/// `Pin

` is guaranteed to have the same memory layout and ABI as `P`. +/// *See the [`pin` module] documentation for a more thorough exploration of pinning.* /// -/// *See the [`pin` module] documentation for an explanation of pinning.* +/// ## Pinning values with [`Pin`] /// -/// [`pin` module]: self +/// In order to pin a value, we wrap a *pointer to that value* (of some type `Ptr`) in a +/// [`Pin`]. [`Pin`] can wrap any pointer type, forming a promise that the **pointee** +/// will not be *moved* or [otherwise invalidated][subtle-details]. If the pointee value's type +/// implements [`Unpin`], we are free to disregard these requirements entirely and can wrap any +/// pointer to that value in [`Pin`] directly via [`Pin::new`]. If the pointee value's type does +/// not implement [`Unpin`], then Rust will not let us use the [`Pin::new`] function directly and +/// we'll need to construct a [`Pin`]-wrapped pointer in one of the more specialized manners +/// discussed below. +/// +/// We call such a [`Pin`]-wrapped pointer a **pinning pointer** (or pinning ref, or pinning +/// [`Box`], etc.) because its existince is the thing that is pinning the underlying pointee in +/// place: it is the metaphorical "pin" securing the data in place on the pinboard (in memory). +/// +/// It is important to stress that the thing in the [`Pin`] is not the value which we want to pin +/// itself, but rather a pointer to that value! A [`Pin`] does not pin the `Ptr` but rather +/// the pointer's ***pointee** value*. +/// +/// The most common set of types which require pinning related guarantees for soundness are the +/// compiler-generated state machines that implement [`Future`] for the return value of +/// `async fn`s. These compiler-generated [`Future`]s may contain self-referrential pointers, one +/// of the most common use cases for [`Pin`]. More details on this point are provided in the +/// [`pin` module] docs, but suffice it to say they require the guarantees provided by pinning to +/// be implemented soundly. +/// +/// This requirement for the implementation of `async fn`s means that the [`Future`] trait +/// requires all calls to [`poll`] to use a self: [Pin]\<&mut Self> parameter instead +/// of the usual `&mut self`. Therefore, when manually polling a future, you will need to pin it +/// first. +/// +/// You may notice that `async fn`-sourced [`Future`]s are only a small percentage of all +/// [`Future`]s that exist, yet we had to modify the signature of [`poll`] for all [`Future`]s +/// to accommodate them. This is unfortunate, but there is a way that the language attempts to +/// alleviate the extra friction that this API choice incurs: the [`Unpin`] trait. +/// +/// The vast majority of Rust types have no reason to ever care about being pinned. These +/// types implement the [`Unpin`] trait, which entirely opts all values of that type out of +/// pinning-related guarantees. For values of these types, pinning a value by pointing to it with a +/// [`Pin`] will have no actual effect. +/// +/// The reason this distinction exists is exactly to allow APIs like [`Future::poll`] to take a +/// [`Pin`] as an argument for all types while only forcing [`Future`] types that actually +/// care about pinning guarantees pay the ergonomics cost. For the majority of [`Future`] types +/// that don't have a reason to care about being pinned and therefore implement [`Unpin`], the +/// [Pin]\<&mut Self> will act exactly like a regular `&mut Self`, allowing direct +/// access to the underlying value. Only types that *don't* implement [`Unpin`] will be restricted. +/// +/// ### Pinning a value of a type that implements [`Unpin`] +/// +/// If the type of the value you need to "pin" implements [`Unpin`], you can trivially wrap any +/// pointer to that value in a [`Pin`] by calling [`Pin::new`]. +/// +/// ``` +/// use std::pin::Pin; +/// +/// // Create a value of a type that implements `Unpin` +/// let mut unpin_future = std::future::ready(5); +/// +/// // Pin it by creating a pinning mutable reference to it (ready to be `poll`ed!) +/// let my_pinned_unpin_future: Pin<&mut _> = Pin::new(&mut unpin_future); +/// ``` +/// +/// ### Pinning a value inside a [`Box`] +/// +/// The simplest and most flexible way to pin a value that does not implement [`Unpin`] is to put +/// that value inside a [`Box`] and then turn that [`Box`] into a "pinning [`Box`]" by wrapping it +/// in a [`Pin`]. You can do both of these in a single step using [`Box::pin`]. Let's see an +/// example of using this flow to pin a [`Future`] returned from calling an `async fn`, a common +/// use case as described above. +/// +/// ``` +/// use std::pin::Pin; +/// +/// async fn add_one(x: u32) -> u32 { +/// x + 1 +/// } +/// +/// // Call the async function to get a future back +/// let fut = add_one(42); +/// +/// // Pin the future inside a pinning box +/// let pinned_fut: Pin> = Box::pin(fut); +/// ``` +/// +/// If you have a value which is already boxed, for example a [`Box`][Box], you can pin +/// that value in-place at its current memory address using [`Box::into_pin`]. +/// +/// ``` +/// use std::pin::Pin; +/// use std::future::Future; +/// +/// async fn add_one(x: u32) -> u32 { +/// x + 1 +/// } +/// +/// fn boxed_add_one(x: u32) -> Box> { +/// Box::new(add_one(x)) +/// } +/// +/// let boxed_fut = boxed_add_one(42); +/// +/// // Pin the future inside the existing box +/// let pinned_fut: Pin> = Box::into_pin(boxed_fut); +/// ``` +/// +/// There are similar pinning methods offered on the other standard library smart pointer types +/// as well, like [`Rc`] and [`Arc`]. +/// +/// ### Pinning a value on the stack using [`pin!`] +/// +/// There are some situations where it is desirable or even required (for example, in a `#[no_std]` +/// context where you don't have access to the standard library or allocation in general) to +/// pin a value which does not implement [`Unpin`] to its location on the stack. Doing so is +/// possible using the [`pin!`] macro. See its documentation for more. +/// +/// ## Layout and ABI +/// +/// [`Pin`] is guaranteed to have the same memory layout and ABI[^noalias] as `Ptr`. +/// +/// [^noalias]: There is a bit of nuance here that is still being decided about whether the +/// aliasing semantics of `Pin<&mut T>` should be different than `&mut T`, but this is true as of +/// today. +/// +/// [`pin!`]: crate::pin::pin "pin!" +/// [`Future`]: crate::future::Future "Future" +/// [`poll`]: crate::future::Future::poll "Future::poll" +/// [`Future::poll`]: crate::future::Future::poll "Future::poll" +/// [`pin` module]: self "pin module" +/// [`Rc`]: ../../std/rc/struct.Rc.html "Rc" +/// [`Arc`]: ../../std/sync/struct.Arc.html "Arc" +/// [Box]: ../../std/boxed/struct.Box.html "Box" +/// [`Box`]: ../../std/boxed/struct.Box.html "Box" +/// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin "Box::pin" +/// [`Box::into_pin`]: ../../std/boxed/struct.Box.html#method.into_pin "Box::into_pin" +/// [subtle-details]: self#subtle-details-and-the-drop-guarantee "pin subtle details" +/// [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe" // // Note: the `Clone` derive below causes unsoundness as it's possible to implement // `Clone` for mutable references. @@ -406,7 +1087,7 @@ use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver}; #[fundamental] #[repr(transparent)] #[derive(Copy, Clone)] -pub struct Pin

{ +pub struct Pin { // FIXME(#93176): this field is made `#[unstable] #[doc(hidden)] pub` to: // - deter downstream users from accessing it (which would be unsound!), // - let the `pin!` macro access it (such a macro requires using struct @@ -414,7 +1095,7 @@ pub struct Pin

{ // Long-term, `unsafe` fields or macro hygiene are expected to offer more robust alternatives. #[unstable(feature = "unsafe_pin_internals", issue = "none")] #[doc(hidden)] - pub pointer: P, + pub pointer: Ptr, } // The following implementations aren't derived in order to avoid soundness @@ -424,68 +1105,68 @@ pub struct Pin

{ // See for more details. #[stable(feature = "pin_trait_impls", since = "1.41.0")] -impl PartialEq> for Pin

+impl PartialEq> for Pin where - P::Target: PartialEq, + Ptr::Target: PartialEq, { fn eq(&self, other: &Pin) -> bool { - P::Target::eq(self, other) + Ptr::Target::eq(self, other) } fn ne(&self, other: &Pin) -> bool { - P::Target::ne(self, other) + Ptr::Target::ne(self, other) } } #[stable(feature = "pin_trait_impls", since = "1.41.0")] -impl> Eq for Pin

{} +impl> Eq for Pin {} #[stable(feature = "pin_trait_impls", since = "1.41.0")] -impl PartialOrd> for Pin

+impl PartialOrd> for Pin where - P::Target: PartialOrd, + Ptr::Target: PartialOrd, { fn partial_cmp(&self, other: &Pin) -> Option { - P::Target::partial_cmp(self, other) + Ptr::Target::partial_cmp(self, other) } fn lt(&self, other: &Pin) -> bool { - P::Target::lt(self, other) + Ptr::Target::lt(self, other) } fn le(&self, other: &Pin) -> bool { - P::Target::le(self, other) + Ptr::Target::le(self, other) } fn gt(&self, other: &Pin) -> bool { - P::Target::gt(self, other) + Ptr::Target::gt(self, other) } fn ge(&self, other: &Pin) -> bool { - P::Target::ge(self, other) + Ptr::Target::ge(self, other) } } #[stable(feature = "pin_trait_impls", since = "1.41.0")] -impl> Ord for Pin

{ +impl> Ord for Pin { fn cmp(&self, other: &Self) -> cmp::Ordering { - P::Target::cmp(self, other) + Ptr::Target::cmp(self, other) } } #[stable(feature = "pin_trait_impls", since = "1.41.0")] -impl> Hash for Pin

{ +impl> Hash for Pin { fn hash(&self, state: &mut H) { - P::Target::hash(self, state); + Ptr::Target::hash(self, state); } } -impl> Pin

{ - /// Construct a new `Pin

` around a pointer to some data of a type that +impl> Pin { + /// Construct a new `Pin` around a pointer to some data of a type that /// implements [`Unpin`]. /// /// Unlike `Pin::new_unchecked`, this method is safe because the pointer - /// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees. + /// `Ptr` dereferences to an [`Unpin`] type, which cancels the pinning guarantees. /// /// # Examples /// @@ -493,22 +1174,25 @@ impl> Pin

{ /// use std::pin::Pin; /// /// let mut val: u8 = 5; - /// // We can pin the value, since it doesn't care about being moved + /// + /// // Since `val` doesn't care about being moved, we can safely create a "facade" `Pin` + /// // which will allow `val` to participate in `Pin`-bound apis without checking that + /// // pinning guarantees are actually upheld. /// let mut pinned: Pin<&mut u8> = Pin::new(&mut val); /// ``` #[inline(always)] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] - pub const fn new(pointer: P) -> Pin

{ + pub const fn new(pointer: Ptr) -> Pin { // SAFETY: the value pointed to is `Unpin`, and so has no requirements // around pinning. unsafe { Pin::new_unchecked(pointer) } } - /// Unwraps this `Pin

` returning the underlying pointer. + /// Unwraps this `Pin`, returning the underlying pointer. /// - /// This requires that the data inside this `Pin` implements [`Unpin`] so that we - /// can ignore the pinning invariants when unwrapping it. + /// Doing this operation safely requires that the data pointed at by this pinning pointer + /// implemts [`Unpin`] so that we can ignore the pinning invariants when unwrapping it. /// /// # Examples /// @@ -517,46 +1201,54 @@ impl> Pin

{ /// /// let mut val: u8 = 5; /// let pinned: Pin<&mut u8> = Pin::new(&mut val); - /// // Unwrap the pin to get a reference to the value + /// + /// // Unwrap the pin to get the underlying mutable reference to the value. We can do + /// // this because `val` doesn't care about being moved, so the `Pin` was just + /// // a "facade" anyway. /// let r = Pin::into_inner(pinned); /// assert_eq!(*r, 5); /// ``` #[inline(always)] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin_into_inner", since = "1.39.0")] - pub const fn into_inner(pin: Pin

) -> P { + pub const fn into_inner(pin: Pin) -> Ptr { pin.pointer } } -impl Pin

{ - /// Construct a new `Pin

` around a reference to some data of a type that - /// may or may not implement `Unpin`. +impl Pin { + /// Construct a new `Pin` around a reference to some data of a type that + /// may or may not implement [`Unpin`]. /// - /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used + /// If `pointer` dereferences to an [`Unpin`] type, [`Pin::new`] should be used /// instead. /// /// # Safety /// /// This constructor is unsafe because we cannot guarantee that the data - /// pointed to by `pointer` is pinned, meaning that the data will not be moved or - /// its storage invalidated until it gets dropped. If the constructed `Pin

` does - /// not guarantee that the data `P` points to is pinned, that is a violation of - /// the API contract and may lead to undefined behavior in later (safe) operations. + /// pointed to by `pointer` is pinned. At its core, pinning a value means making the + /// guarantee that the value's data will not be moved nor have its storage invalidated until + /// it gets dropped. For a more thorough explanation of pinning, see the [`pin` module docs]. /// - /// By using this method, you are making a promise about the `P::Deref` and - /// `P::DerefMut` implementations, if they exist. Most importantly, they + /// If the caller that is constructing this `Pin` does not ensure that the data `Ptr` + /// points to is pinned, that is a violation of the API contract and may lead to undefined + /// behavior in later (even safe) operations. + /// + /// By using this method, you are also making a promise about the [`Deref`] and + /// [`DerefMut`] implementations of `Ptr`, if they exist. Most importantly, they /// must not move out of their `self` arguments: `Pin::as_mut` and `Pin::as_ref` - /// will call `DerefMut::deref_mut` and `Deref::deref` *on the pinned pointer* + /// will call `DerefMut::deref_mut` and `Deref::deref` *on the pointer type `Ptr`* /// and expect these methods to uphold the pinning invariants. - /// Moreover, by calling this method you promise that the reference `P` + /// Moreover, by calling this method you promise that the reference `Ptr` /// dereferences to will not be moved out of again; in particular, it - /// must not be possible to obtain a `&mut P::Target` and then + /// must not be possible to obtain a `&mut Ptr::Target` and then /// move out of that reference (using, for example [`mem::swap`]). /// /// For example, calling `Pin::new_unchecked` on an `&'a mut T` is unsafe because /// while you are able to pin it for the given lifetime `'a`, you have no control - /// over whether it is kept pinned once `'a` ends: + /// over whether it is kept pinned once `'a` ends, and therefore cannot uphold the + /// guarantee that a value, once pinned, remains pinned until it is dropped: + /// /// ``` /// use std::mem; /// use std::pin::Pin; @@ -583,12 +1275,14 @@ impl Pin

{ /// use std::pin::Pin; /// /// fn move_pinned_rc(mut x: Rc) { - /// let pinned = unsafe { Pin::new_unchecked(Rc::clone(&x)) }; + /// // This should mean the pointee can never move again. + /// let pin = unsafe { Pin::new_unchecked(Rc::clone(&x)) }; /// { - /// let p: Pin<&T> = pinned.as_ref(); - /// // This should mean the pointee can never move again. + /// let p: Pin<&T> = pin.as_ref(); + /// // ... /// } - /// drop(pinned); + /// drop(pin); + /// /// let content = Rc::get_mut(&mut x).unwrap(); // Potential UB down the road ⚠️ /// // Now, if `x` was the only reference, we have a mutable reference to /// // data that we pinned above, which we could use to move it as we have @@ -649,15 +1343,16 @@ impl Pin

{ /// ``` /// /// [`mem::swap`]: crate::mem::swap + /// [`pin` module docs]: self #[lang = "new_unchecked"] #[inline(always)] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] - pub const unsafe fn new_unchecked(pointer: P) -> Pin

{ + pub const unsafe fn new_unchecked(pointer: Ptr) -> Pin { Pin { pointer } } - /// Gets a pinned shared reference from this pinned pointer. + /// Gets a shared reference to the pinned value this [`Pin`] points to. /// /// This is a generic method to go from `&Pin>` to `Pin<&T>`. /// It is safe because, as part of the contract of `Pin::new_unchecked`, @@ -666,34 +1361,39 @@ impl Pin

{ /// ruled out by the contract of `Pin::new_unchecked`. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn as_ref(&self) -> Pin<&P::Target> { + pub fn as_ref(&self) -> Pin<&Ptr::Target> { // SAFETY: see documentation on this function unsafe { Pin::new_unchecked(&*self.pointer) } } - /// Unwraps this `Pin

` returning the underlying pointer. + /// Unwraps this `Pin`, returning the underlying `Ptr`. /// /// # Safety /// /// This function is unsafe. You must guarantee that you will continue to - /// treat the pointer `P` as pinned after you call this function, so that + /// treat the pointer `Ptr` as pinned after you call this function, so that /// the invariants on the `Pin` type can be upheld. If the code using the - /// resulting `P` does not continue to maintain the pinning invariants that + /// resulting `Ptr` does not continue to maintain the pinning invariants that /// is a violation of the API contract and may lead to undefined behavior in /// later (safe) operations. /// + /// Note that you must be able to guarantee that the data pointed to by `Ptr` + /// will be treated as pinned all the way until its `drop` handler is complete! + /// + /// *For more information, see the [`pin` module docs][self]* + /// /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used /// instead. #[inline(always)] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin_into_inner", since = "1.39.0")] - pub const unsafe fn into_inner_unchecked(pin: Pin

) -> P { + pub const unsafe fn into_inner_unchecked(pin: Pin) -> Ptr { pin.pointer } } -impl Pin

{ - /// Gets a pinned mutable reference from this pinned pointer. +impl Pin { + /// Gets a mutable reference to the pinned value this `Pin` points to. /// /// This is a generic method to go from `&mut Pin>` to `Pin<&mut T>`. /// It is safe because, as part of the contract of `Pin::new_unchecked`, @@ -701,7 +1401,8 @@ impl Pin

{ /// "Malicious" implementations of `Pointer::DerefMut` are likewise /// ruled out by the contract of `Pin::new_unchecked`. /// - /// This method is useful when doing multiple calls to functions that consume the pinned type. + /// This method is useful when doing multiple calls to functions that consume the + /// pinning pointer. /// /// # Example /// @@ -723,15 +1424,17 @@ impl Pin

{ /// ``` #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn as_mut(&mut self) -> Pin<&mut P::Target> { + pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> { // SAFETY: see documentation on this function unsafe { Pin::new_unchecked(&mut *self.pointer) } } - /// Assigns a new value to the memory behind the pinned reference. + /// Assigns a new value to the memory location pointed to by the `Pin`. /// - /// This overwrites pinned data, but that is okay: its destructor gets - /// run before being overwritten, so no pinning guarantee is violated. + /// This overwrites pinned data, but that is okay: the original pinned value's destructor gets + /// run before being overwritten and the new value is also a valid value of the same type, so + /// no pinning invariant is violated. See [the `pin` module documentation][subtle-details] + /// for more information on how this upholds the pinning invariants. /// /// # Example /// @@ -741,14 +1444,16 @@ impl Pin

{ /// let mut val: u8 = 5; /// let mut pinned: Pin<&mut u8> = Pin::new(&mut val); /// println!("{}", pinned); // 5 - /// pinned.as_mut().set(10); + /// pinned.set(10); /// println!("{}", pinned); // 10 /// ``` + /// + /// [subtle-details]: self#subtle-details-and-the-drop-guarantee #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn set(&mut self, value: P::Target) + pub fn set(&mut self, value: Ptr::Target) where - P::Target: Sized, + Ptr::Target: Sized, { *(self.pointer) = value; } @@ -790,15 +1495,15 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// It may seem like there is an issue here with interior mutability: in fact, /// it *is* possible to move a `T` out of a `&RefCell`. However, this is /// not a problem as long as there does not also exist a `Pin<&T>` pointing - /// to the same data, and `RefCell` does not let you create a pinned reference - /// to its contents. See the discussion on ["pinning projections"] for further - /// details. + /// to the inner `T` inside the `RefCell`, and `RefCell` does not let you get a + /// `Pin<&T>` pointer to its contents. See the discussion on ["pinning projections"] + /// for further details. /// /// Note: `Pin` also implements `Deref` to the target, which can be used /// to access the inner value. However, `Deref` only provides a reference /// that lives for as long as the borrow of the `Pin`, not the lifetime of - /// the `Pin` itself. This method allows turning the `Pin` into a reference - /// with the same lifetime as the original `Pin`. + /// the reference contained in the `Pin`. This method allows turning the `Pin` into a reference + /// with the same lifetime as the reference it wraps. /// /// ["pinning projections"]: self#projections-and-structural-pinning #[inline(always)] @@ -891,9 +1596,9 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { } impl Pin<&'static T> { - /// Get a pinned reference from a static reference. + /// Get a pinning reference from a `&'static` reference. /// - /// This is safe, because `T` is borrowed for the `'static` lifetime, which + /// This is safe because `T` is borrowed immutably for the `'static` lifetime, which /// never ends. #[stable(feature = "pin_static_ref", since = "1.61.0")] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] @@ -904,49 +1609,50 @@ impl Pin<&'static T> { } } -impl<'a, P: DerefMut> Pin<&'a mut Pin

> { - /// Gets a pinned mutable reference from this nested pinned pointer. +impl<'a, Ptr: DerefMut> Pin<&'a mut Pin> { + /// Gets `Pin<&mut T>` to the underlying pinned value from this nested `Pin`-pointer. /// /// This is a generic method to go from `Pin<&mut Pin>>` to `Pin<&mut T>`. It is /// safe because the existence of a `Pin>` ensures that the pointee, `T`, cannot /// move in the future, and this method does not enable the pointee to move. "Malicious" - /// implementations of `P::DerefMut` are likewise ruled out by the contract of + /// implementations of `Ptr::DerefMut` are likewise ruled out by the contract of /// `Pin::new_unchecked`. #[unstable(feature = "pin_deref_mut", issue = "86918")] #[must_use = "`self` will be dropped if the result is not used"] #[inline(always)] - pub fn as_deref_mut(self) -> Pin<&'a mut P::Target> { + pub fn as_deref_mut(self) -> Pin<&'a mut Ptr::Target> { // SAFETY: What we're asserting here is that going from // - // Pin<&mut Pin

> + // Pin<&mut Pin> // // to // - // Pin<&mut P::Target> + // Pin<&mut Ptr::Target> // // is safe. // // We need to ensure that two things hold for that to be the case: // - // 1) Once we give out a `Pin<&mut P::Target>`, an `&mut P::Target` will not be given out. - // 2) By giving out a `Pin<&mut P::Target>`, we do not risk of violating `Pin<&mut Pin

>` + // 1) Once we give out a `Pin<&mut Ptr::Target>`, an `&mut Ptr::Target` will not be given out. + // 2) By giving out a `Pin<&mut Ptr::Target>`, we do not risk of violating + // `Pin<&mut Pin>` // - // The existence of `Pin

` is sufficient to guarantee #1: since we already have a - // `Pin

`, it must already uphold the pinning guarantees, which must mean that - // `Pin<&mut P::Target>` does as well, since `Pin::as_mut` is safe. We do not have to rely - // on the fact that P is _also_ pinned. + // The existence of `Pin` is sufficient to guarantee #1: since we already have a + // `Pin`, it must already uphold the pinning guarantees, which must mean that + // `Pin<&mut Ptr::Target>` does as well, since `Pin::as_mut` is safe. We do not have to rely + // on the fact that `Ptr` is _also_ pinned. // - // For #2, we need to ensure that code given a `Pin<&mut P::Target>` cannot cause the - // `Pin

` to move? That is not possible, since `Pin<&mut P::Target>` no longer retains - // any access to the `P` itself, much less the `Pin

`. + // For #2, we need to ensure that code given a `Pin<&mut Ptr::Target>` cannot cause the + // `Pin` to move? That is not possible, since `Pin<&mut Ptr::Target>` no longer retains + // any access to the `Ptr` itself, much less the `Pin`. unsafe { self.get_unchecked_mut() }.as_mut() } } impl Pin<&'static mut T> { - /// Get a pinned mutable reference from a static mutable reference. + /// Get a pinning mutable reference from a static mutable reference. /// - /// This is safe, because `T` is borrowed for the `'static` lifetime, which + /// This is safe because `T` is borrowed for the `'static` lifetime, which /// never ends. #[stable(feature = "pin_static_ref", since = "1.61.0")] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] @@ -958,39 +1664,39 @@ impl Pin<&'static mut T> { } #[stable(feature = "pin", since = "1.33.0")] -impl Deref for Pin

{ - type Target = P::Target; - fn deref(&self) -> &P::Target { +impl Deref for Pin { + type Target = Ptr::Target; + fn deref(&self) -> &Ptr::Target { Pin::get_ref(Pin::as_ref(self)) } } #[stable(feature = "pin", since = "1.33.0")] -impl> DerefMut for Pin

{ - fn deref_mut(&mut self) -> &mut P::Target { +impl> DerefMut for Pin { + fn deref_mut(&mut self) -> &mut Ptr::Target { Pin::get_mut(Pin::as_mut(self)) } } #[unstable(feature = "receiver_trait", issue = "none")] -impl Receiver for Pin

{} +impl Receiver for Pin {} #[stable(feature = "pin", since = "1.33.0")] -impl fmt::Debug for Pin

{ +impl fmt::Debug for Pin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.pointer, f) } } #[stable(feature = "pin", since = "1.33.0")] -impl fmt::Display for Pin

{ +impl fmt::Display for Pin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.pointer, f) } } #[stable(feature = "pin", since = "1.33.0")] -impl fmt::Pointer for Pin

{ +impl fmt::Pointer for Pin { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Pointer::fmt(&self.pointer, f) } @@ -1002,10 +1708,10 @@ impl fmt::Pointer for Pin

{ // for other reasons, though, so we just need to take care not to allow such // impls to land in std. #[stable(feature = "pin", since = "1.33.0")] -impl CoerceUnsized> for Pin

where P: CoerceUnsized {} +impl CoerceUnsized> for Pin where Ptr: CoerceUnsized {} #[stable(feature = "pin", since = "1.33.0")] -impl DispatchFromDyn> for Pin

where P: DispatchFromDyn {} +impl DispatchFromDyn> for Pin where Ptr: DispatchFromDyn {} /// Constructs a [Pin]<[&mut] T>, by pinning a `value: T` locally. /// diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 075347b80d03..8a8d634c0072 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -60,7 +60,17 @@ where return false; } - self.iter().zip(other.iter()).all(|(x, y)| x == y) + // Implemented as explicit indexing rather + // than zipped iterators for performance reasons. + // See PR https://github.com/rust-lang/rust/pull/116846 + for idx in 0..self.len() { + // bound checks are optimized away + if self[idx] != other[idx] { + return false; + } + } + + true } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index b14d9712794b..5edc89e4cb53 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2483,7 +2483,7 @@ impl [T] { /// Splits the slice on the first element that matches the specified /// predicate. /// - /// If any matching elements are resent in the slice, returns the prefix + /// If any matching elements are present in the slice, returns the prefix /// before the match and suffix after. The matching element itself is not /// included. If no elements match, returns `None`. /// @@ -2511,7 +2511,7 @@ impl [T] { /// Splits the slice on the last element that matches the specified /// predicate. /// - /// If any matching elements are resent in the slice, returns the prefix + /// If any matching elements are present in the slice, returns the prefix /// before the match and suffix after. The matching element itself is not /// included. If no elements match, returns `None`. /// diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 99db00e54906..ccae406cc286 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -261,6 +261,8 @@ cfg_if::cfg_if! { } } +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[cfg_attr(not(bootstrap), allow(static_mut_ref))] pub unsafe fn panic(data: Box) -> u32 { use core::intrinsics::atomic_store_seqcst; @@ -322,6 +324,8 @@ pub unsafe fn panic(data: Box) -> u32 { _CxxThrowException(throw_ptr, &mut THROW_INFO as *mut _ as *mut _); } +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[cfg_attr(not(bootstrap), allow(static_mut_ref))] pub unsafe fn cleanup(payload: *mut u8) -> Box { // A null payload here means that we got here from the catch (...) of // __rust_try. This happens when a non-Rust foreign exception is caught. diff --git a/library/rtstartup/rsbegin.rs b/library/rtstartup/rsbegin.rs index 1df0c8970538..14bce2bbeee2 100644 --- a/library/rtstartup/rsbegin.rs +++ b/library/rtstartup/rsbegin.rs @@ -18,6 +18,7 @@ #![crate_type = "rlib"] #![no_core] #![allow(non_camel_case_types)] +#![allow(internal_features)] #[lang = "sized"] trait Sized {} diff --git a/library/rtstartup/rsend.rs b/library/rtstartup/rsend.rs index d5aca80edf9e..714643c83866 100644 --- a/library/rtstartup/rsend.rs +++ b/library/rtstartup/rsend.rs @@ -5,6 +5,7 @@ #![feature(auto_traits)] #![crate_type = "rlib"] #![no_core] +#![allow(internal_features)] #[lang = "sized"] trait Sized {} diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index fe66788b564d..5dbfe4aa2ac1 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,7 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } libc = { version = "0.2.150", default-features = false, features = ['rustc-dep-of-std'], public = true } -compiler_builtins = { version = "0.1.103" } +compiler_builtins = { version = "0.1.104" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] } @@ -54,8 +54,8 @@ hermit-abi = { version = "0.3.2", features = ['rustc-dep-of-std'], public = true wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false } [target.'cfg(target_os = "uefi")'.dependencies] -r-efi = { version = "4.2.0", features = ['rustc-dep-of-std']} -r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std']} +r-efi = { version = "4.2.0", features = ['rustc-dep-of-std'] } +r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std'] } [features] backtrace = [ diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 12afdef2669a..5917bf8df029 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -936,8 +936,10 @@ fn read_link() { } // Check that readlink works with non-drive paths on Windows. let link = tmpdir.join("link_unc"); - check!(symlink_dir(r"\\localhost\c$\", &link)); - assert_eq!(check!(fs::read_link(&link)), Path::new(r"\\localhost\c$\")); + if got_symlink_permission(&tmpdir) { + check!(symlink_dir(r"\\localhost\c$\", &link)); + assert_eq!(check!(fs::read_link(&link)), Path::new(r"\\localhost\c$\")); + }; } let link = tmpdir.join("link"); if !got_symlink_permission(&tmpdir) { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 95ee6a9b29c9..7a8d9d0ceeca 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -374,7 +374,6 @@ #![feature(cfg_eval)] #![feature(concat_bytes)] #![feature(const_format_args)] -#![feature(core_panic)] #![feature(custom_test_frameworks)] #![feature(edition_panic)] #![feature(format_args_nl)] diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 1b70b669c779..f6835472e2ca 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -73,7 +73,7 @@ impl UnixListener { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; - #[cfg(any(target_os = "windows", target_os = "redox"))] + #[cfg(any(target_os = "windows", target_os = "redox", target_os = "espidf"))] const backlog: libc::c_int = 128; #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] const backlog: libc::c_int = -1; @@ -82,7 +82,8 @@ impl UnixListener { target_os = "redox", target_os = "linux", target_os = "freebsd", - target_os = "openbsd" + target_os = "openbsd", + target_os = "espidf" )))] const backlog: libc::c_int = libc::SOMAXCONN; diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 69a6f3e6d5ac..7f6b563d7295 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -11,7 +11,7 @@ use crate::thread::Result; #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(libstd_sys_internals, const_format_args, core_panic, rt)] +#[allow_internal_unstable(libstd_sys_internals, const_format_args, panic_internals, rt)] #[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2015 { diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 66b4ec37c8ec..c80f15d8a611 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -337,6 +337,8 @@ pub mod panic_count { #[doc(hidden)] #[cfg(not(feature = "panic_immediate_abort"))] #[unstable(feature = "update_panic_count", issue = "none")] +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[cfg_attr(not(bootstrap), allow(static_mut_ref))] pub mod panic_count { use crate::cell::Cell; use crate::sync::atomic::{AtomicUsize, Ordering}; diff --git a/library/std/src/sys/common/thread_local/fast_local.rs b/library/std/src/sys/common/thread_local/fast_local.rs index c0a9619bf7bf..9206588be064 100644 --- a/library/std/src/sys/common/thread_local/fast_local.rs +++ b/library/std/src/sys/common/thread_local/fast_local.rs @@ -13,6 +13,8 @@ pub macro thread_local_inner { (@key $t:ty, const $init:expr) => {{ #[inline] #[deny(unsafe_op_in_unsafe_fn)] + // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint + #[cfg_attr(not(bootstrap), allow(static_mut_ref))] unsafe fn __getit( _init: $crate::option::Option<&mut $crate::option::Option<$t>>, ) -> $crate::option::Option<&'static $t> { diff --git a/library/std/src/sys/common/thread_local/static_local.rs b/library/std/src/sys/common/thread_local/static_local.rs index 5cb6c541a0ec..51cba66fad76 100644 --- a/library/std/src/sys/common/thread_local/static_local.rs +++ b/library/std/src/sys/common/thread_local/static_local.rs @@ -11,6 +11,8 @@ pub macro thread_local_inner { (@key $t:ty, const $init:expr) => {{ #[inline] // see comments below #[deny(unsafe_op_in_unsafe_fn)] + // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint + #[cfg_attr(not(bootstrap), allow(static_mut_ref))] unsafe fn __getit( _init: $crate::option::Option<&mut $crate::option::Option<$t>>, ) -> $crate::option::Option<&'static $t> { diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index 817c33b66037..f99cea360f1f 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -185,6 +185,12 @@ pub struct UserRef(UnsafeCell); #[unstable(feature = "sgx_platform", issue = "56975")] pub struct User(NonNull>); +#[unstable(feature = "sgx_platform", issue = "56975")] +unsafe impl Send for User {} + +#[unstable(feature = "sgx_platform", issue = "56975")] +unsafe impl Send for User<[T]> {} + trait NewUserRef { unsafe fn new_userref(v: T) -> Self; } diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index 2825d1677427..cf0fe0f47c53 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -64,17 +64,7 @@ mod imp { #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "freebsd"))] fn getrandom(buf: &mut [u8]) -> libc::ssize_t { - #[cfg(not(target_os = "freebsd"))] - use libc::getrandom; - #[cfg(target_os = "freebsd")] - extern "C" { - fn getrandom( - buf: *mut libc::c_void, - buflen: libc::size_t, - flags: libc::c_uint, - ) -> libc::ssize_t; - } - unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) } + unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) } } #[cfg(not(any( diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 9cf37b0e6347..338567777f75 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -180,6 +180,8 @@ impl fmt::Debug for LocalKey { #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")] #[allow_internal_unstable(thread_local_internals)] +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[cfg_attr(not(bootstrap), allow(static_mut_ref))] macro_rules! thread_local { // empty (base case for the recursion) () => {}; diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index f1f2f28909de..5f0afdb1b36c 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -28,7 +28,9 @@ fn args(builder: &Builder<'_>) -> Vec { arr.iter().copied().map(String::from) } - if let Subcommand::Clippy { fix, allow, deny, warn, forbid, .. } = &builder.config.cmd { + if let Subcommand::Clippy { fix, allow_dirty, allow_staged, allow, deny, warn, forbid } = + &builder.config.cmd + { // disable the most spammy clippy lints let ignored_lints = vec![ "many_single_char_names", // there are a lot in stdarch @@ -49,7 +51,16 @@ fn args(builder: &Builder<'_>) -> Vec { // As a workaround, avoid checking tests and benches when passed --fix. "--lib", "--bins", "--examples", ])); + + if *allow_dirty { + args.push("--allow-dirty".to_owned()); + } + + if *allow_staged { + args.push("--allow-staged".to_owned()); + } } + args.extend(strings(&["--", "--cap-lints", "warn"])); args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint))); let mut clippy_lint_levels: Vec = Vec::new(); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index d699c4fe536c..190f0fe3cddc 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -46,6 +46,7 @@ pub struct Std { /// but we need to use the downloaded copy of std for linking to rustdoc. Allow this to be overriden by `builder.ensure` from other steps. force_recompile: bool, extra_rust_args: &'static [&'static str], + is_for_mir_opt_tests: bool, } impl Std { @@ -56,6 +57,7 @@ impl Std { crates: Default::default(), force_recompile: false, extra_rust_args: &[], + is_for_mir_opt_tests: false, } } @@ -66,6 +68,18 @@ impl Std { crates: Default::default(), force_recompile: true, extra_rust_args: &[], + is_for_mir_opt_tests: false, + } + } + + pub fn new_for_mir_opt_tests(compiler: Compiler, target: TargetSelection) -> Self { + Self { + target, + compiler, + crates: Default::default(), + force_recompile: false, + extra_rust_args: &[], + is_for_mir_opt_tests: true, } } @@ -80,6 +94,7 @@ impl Std { crates: Default::default(), force_recompile: false, extra_rust_args, + is_for_mir_opt_tests: false, } } } @@ -109,6 +124,7 @@ impl Step for Std { crates, force_recompile: false, extra_rust_args: &[], + is_for_mir_opt_tests: false, }); } @@ -206,11 +222,19 @@ impl Step for Std { } } - let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "build"); - std_cargo(builder, target, compiler.stage, &mut cargo); - for krate in &*self.crates { - cargo.arg("-p").arg(krate); - } + let mut cargo = if self.is_for_mir_opt_tests { + let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustc"); + cargo.arg("-p").arg("std").arg("--crate-type=lib"); + std_cargo(builder, target, compiler.stage, &mut cargo); + cargo + } else { + let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "build"); + std_cargo(builder, target, compiler.stage, &mut cargo); + for krate in &*self.crates { + cargo.arg("-p").arg(krate); + } + cargo + }; // See src/bootstrap/synthetic_targets.rs if target.is_synthetic() { @@ -382,9 +406,7 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car // Determine if we're going to compile in optimized C intrinsics to // the `compiler-builtins` crate. These intrinsics live in LLVM's - // `compiler-rt` repository, but our `src/llvm-project` submodule isn't - // always checked out, so we need to conditionally look for this. (e.g. if - // an external LLVM is used we skip the LLVM submodule checkout). + // `compiler-rt` repository. // // Note that this shouldn't affect the correctness of `compiler-builtins`, // but only its speed. Some intrinsics in C haven't been translated to Rust @@ -395,8 +417,21 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car // If `compiler-rt` is available ensure that the `c` feature of the // `compiler-builtins` crate is enabled and it's configured to learn where // `compiler-rt` is located. - let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt"); - let compiler_builtins_c_feature = if compiler_builtins_root.exists() { + let compiler_builtins_c_feature = if builder.config.optimized_compiler_builtins { + // NOTE: this interacts strangely with `llvm-has-rust-patches`. In that case, we enforce `submodules = false`, so this is a no-op. + // But, the user could still decide to manually use an in-tree submodule. + // + // NOTE: if we're using system llvm, we'll end up building a version of `compiler-rt` that doesn't match the LLVM we're linking to. + // That's probably ok? At least, the difference wasn't enforced before. There's a comment in + // the compiler_builtins build script that makes me nervous, though: + // https://github.com/rust-lang/compiler-builtins/blob/31ee4544dbe47903ce771270d6e3bea8654e9e50/build.rs#L575-L579 + builder.update_submodule(&Path::new("src").join("llvm-project")); + let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt"); + if !compiler_builtins_root.exists() { + panic!( + "need LLVM sources available to build `compiler-rt`, but they weren't present; consider enabling `build.submodules = true` or disabling `optimized-compiler-builtins`" + ); + } // Note that `libprofiler_builtins/build.rs` also computes this so if // you're changing something here please also change that. cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root); @@ -905,34 +940,6 @@ impl Step for Rustc { )); } - // We currently don't support cross-crate LTO in stage0. This also isn't hugely necessary - // and may just be a time sink. - if compiler.stage != 0 { - match builder.config.rust_lto { - RustcLto::Thin | RustcLto::Fat => { - // Since using LTO for optimizing dylibs is currently experimental, - // we need to pass -Zdylib-lto. - cargo.rustflag("-Zdylib-lto"); - // Cargo by default passes `-Cembed-bitcode=no` and doesn't pass `-Clto` when - // compiling dylibs (and their dependencies), even when LTO is enabled for the - // crate. Therefore, we need to override `-Clto` and `-Cembed-bitcode` here. - let lto_type = match builder.config.rust_lto { - RustcLto::Thin => "thin", - RustcLto::Fat => "fat", - _ => unreachable!(), - }; - cargo.rustflag(&format!("-Clto={lto_type}")); - cargo.rustflag("-Cembed-bitcode=yes"); - } - RustcLto::ThinLocal => { /* Do nothing, this is the default */ } - RustcLto::Off => { - cargo.rustflag("-Clto=off"); - } - } - } else if builder.config.rust_lto == RustcLto::Off { - cargo.rustflag("-Clto=off"); - } - for krate in &*self.crates { cargo.arg("-p").arg(krate); } @@ -989,6 +996,34 @@ pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelec cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)"); + // We currently don't support cross-crate LTO in stage0. This also isn't hugely necessary + // and may just be a time sink. + if stage != 0 { + match builder.config.rust_lto { + RustcLto::Thin | RustcLto::Fat => { + // Since using LTO for optimizing dylibs is currently experimental, + // we need to pass -Zdylib-lto. + cargo.rustflag("-Zdylib-lto"); + // Cargo by default passes `-Cembed-bitcode=no` and doesn't pass `-Clto` when + // compiling dylibs (and their dependencies), even when LTO is enabled for the + // crate. Therefore, we need to override `-Clto` and `-Cembed-bitcode` here. + let lto_type = match builder.config.rust_lto { + RustcLto::Thin => "thin", + RustcLto::Fat => "fat", + _ => unreachable!(), + }; + cargo.rustflag(&format!("-Clto={lto_type}")); + cargo.rustflag("-Cembed-bitcode=yes"); + } + RustcLto::ThinLocal => { /* Do nothing, this is the default */ } + RustcLto::Off => { + cargo.rustflag("-Clto=off"); + } + } + } else if builder.config.rust_lto == RustcLto::Off { + cargo.rustflag("-Clto=off"); + } + rustc_cargo_env(builder, cargo, target, stage); } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index d87651cb367e..f50026368dab 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2032,23 +2032,24 @@ fn install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path) { /// /// Returns whether the files were actually copied. fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool { - if let Some(config) = builder.config.target_config.get(&target) { - if config.llvm_config.is_some() && !builder.config.llvm_from_ci { - // If the LLVM was externally provided, then we don't currently copy - // artifacts into the sysroot. This is not necessarily the right - // choice (in particular, it will require the LLVM dylib to be in - // the linker's load path at runtime), but the common use case for - // external LLVMs is distribution provided LLVMs, and in that case - // they're usually in the standard search path (e.g., /usr/lib) and - // copying them here is going to cause problems as we may end up - // with the wrong files and isn't what distributions want. - // - // This behavior may be revisited in the future though. - // - // If the LLVM is coming from ourselves (just from CI) though, we - // still want to install it, as it otherwise won't be available. - return false; - } + // If the LLVM was externally provided, then we don't currently copy + // artifacts into the sysroot. This is not necessarily the right + // choice (in particular, it will require the LLVM dylib to be in + // the linker's load path at runtime), but the common use case for + // external LLVMs is distribution provided LLVMs, and in that case + // they're usually in the standard search path (e.g., /usr/lib) and + // copying them here is going to cause problems as we may end up + // with the wrong files and isn't what distributions want. + // + // This behavior may be revisited in the future though. + // + // NOTE: this intentionally doesn't use `is_rust_llvm`; whether this is patched or not doesn't matter, + // we only care if the shared object itself is managed by bootstrap. + // + // If the LLVM is coming from ourselves (just from CI) though, we + // still want to install it, as it otherwise won't be available. + if builder.is_system_llvm(target) { + return false; } // On macOS, rustc (and LLVM tools) link to an unversioned libLLVM.dylib diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 6b4a8f597eab..1c565e7f7cc0 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -204,15 +204,13 @@ install!((self, builder, _config), install_sh(builder, "docs", self.compiler.stage, Some(self.target), &tarball); }; Std, path = "library/std", true, only_hosts: false, { - for target in &builder.targets { - // `expect` should be safe, only None when host != build, but this - // only runs when host == build - let tarball = builder.ensure(dist::Std { - compiler: self.compiler, - target: *target - }).expect("missing std"); - install_sh(builder, "std", self.compiler.stage, Some(*target), &tarball); - } + // `expect` should be safe, only None when host != build, but this + // only runs when host == build + let tarball = builder.ensure(dist::Std { + compiler: self.compiler, + target: self.target + }).expect("missing std"); + install_sh(builder, "std", self.compiler.stage, Some(self.target), &tarball); }; Cargo, alias = "cargo", Self::should_build(_config), only_hosts: true, { let tarball = builder diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs index d2c65b740dad..9acdcaeb517b 100644 --- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs +++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs @@ -59,6 +59,11 @@ fn create_synthetic_target( let mut cmd = Command::new(builder.rustc(compiler)); cmd.arg("--target").arg(base.rustc_target_arg()); cmd.args(["-Zunstable-options", "--print", "target-spec-json"]); + + // If `rust.channel` is set to either beta or stable, rustc will complain that + // we cannot use nightly features. So `RUSTC_BOOTSTRAP` is needed here. + cmd.env("RUSTC_BOOTSTRAP", "1"); + cmd.stdout(Stdio::piped()); let output = cmd.spawn().unwrap().wait_with_output().unwrap(); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 7f46726b9565..04728e2e00dc 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1596,8 +1596,13 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // NOTE: Only stage 1 is special cased because we need the rustc_private artifacts to match the // running compiler in stage 2 when plugins run. let stage_id = if suite == "ui-fulldeps" && compiler.stage == 1 { - compiler = builder.compiler(compiler.stage - 1, target); - format!("stage{}-{}", compiler.stage + 1, target) + // At stage 0 (stage - 1) we are using the beta compiler. Using `self.target` can lead finding + // an incorrect compiler path on cross-targets, as the stage 0 beta compiler is always equal + // to `build.build` in the configuration. + let build = builder.build.build; + + compiler = builder.compiler(compiler.stage - 1, build); + format!("stage{}-{}", compiler.stage + 1, build) } else { format!("stage{}-{}", compiler.stage, target) }; @@ -1611,7 +1616,12 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the .ensure(dist::DebuggerScripts { sysroot: builder.sysroot(compiler), host: target }); } - builder.ensure(compile::Std::new(compiler, target)); + if suite == "mir-opt" { + builder.ensure(compile::Std::new_for_mir_opt_tests(compiler, target)); + } else { + builder.ensure(compile::Std::new(compiler, target)); + } + // ensure that `libproc_macro` is available on the host. builder.ensure(compile::Std::new(compiler, compiler.host)); @@ -1619,7 +1629,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the builder.ensure(TestHelpers { target: compiler.host }); // As well as the target, except for plain wasm32, which can't build it - if !target.contains("wasm") || target.contains("emscripten") { + if suite != "mir-opt" && !target.contains("wasm") && !target.contains("emscripten") { builder.ensure(TestHelpers { target }); } @@ -1845,6 +1855,8 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the llvm_components_passed = true; } if !builder.is_rust_llvm(target) { + // FIXME: missing Rust patches is not the same as being system llvm; we should rename the flag at some point. + // Inspecting the tests with `// no-system-llvm` in src/test *looks* like this is doing the right thing, though. cmd.arg("--system-llvm"); } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 3ac3e5456314..85132e405b47 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -178,6 +178,8 @@ pub struct Config { pub patch_binaries_for_nix: Option, pub stage0_metadata: Stage0Metadata, pub android_ndk: Option, + /// Whether to use the `c` feature of the `compiler_builtins` crate. + pub optimized_compiler_builtins: bool, pub stdout_is_tty: bool, pub stderr_is_tty: bool, @@ -848,6 +850,7 @@ define_config! { // NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally metrics: Option = "metrics", android_ndk: Option = "android-ndk", + optimized_compiler_builtins: Option = "optimized-compiler-builtins", } } @@ -1396,6 +1399,7 @@ impl Config { // This field is only used by bootstrap.py metrics: _, android_ndk, + optimized_compiler_builtins, } = toml.build.unwrap_or_default(); if let Some(file_build) = build { @@ -1810,7 +1814,14 @@ impl Config { } target.llvm_config = Some(config.src.join(s)); } - target.llvm_has_rust_patches = cfg.llvm_has_rust_patches; + if let Some(patches) = cfg.llvm_has_rust_patches { + assert_eq!( + config.submodules, + Some(false), + "cannot set `llvm-has-rust-patches` for a managed submodule (set `build.submodules = false` if you want to apply patches)" + ); + target.llvm_has_rust_patches = Some(patches); + } if let Some(ref s) = cfg.llvm_filecheck { target.llvm_filecheck = Some(config.src.join(s)); } @@ -1909,6 +1920,8 @@ impl Config { config.rust_debuginfo_level_std = with_defaults(debuginfo_level_std); config.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools); config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None); + config.optimized_compiler_builtins = + optimized_compiler_builtins.unwrap_or(config.channel != "dev"); let download_rustc = config.download_rustc_commit.is_some(); // See https://github.com/rust-lang/compiler-team/issues/326 diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 0b13726081b1..8af454001a64 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -255,6 +255,10 @@ pub enum Subcommand { Clippy { #[arg(long)] fix: bool, + #[arg(long, requires = "fix")] + allow_dirty: bool, + #[arg(long, requires = "fix")] + allow_staged: bool, /// clippy lints to allow #[arg(global(true), short = 'A', action = clap::ArgAction::Append, value_name = "LINT")] allow: Vec, diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 82755f418000..5f1ca5de74af 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -62,9 +62,15 @@ impl Finder { } pub fn check(build: &mut Build) { - let skip_target_sanity = + let mut skip_target_sanity = env::var_os("BOOTSTRAP_SKIP_TARGET_SANITY").is_some_and(|s| s == "1" || s == "true"); + // Skip target sanity checks when we are doing anything with mir-opt tests or Miri + let skipped_paths = [OsStr::new("mir-opt"), OsStr::new("miri")]; + skip_target_sanity |= build.config.paths.iter().any(|path| { + path.components().any(|component| skipped_paths.contains(&component.as_os_str())) + }); + let path = env::var_os("PATH").unwrap_or_default(); // On Windows, quotes are invalid characters for filename paths, and if // one is present as part of the PATH then that can lead to the system diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 871318de5955..30824f585228 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -823,18 +823,34 @@ impl Build { INTERNER.intern_path(self.out.join(&*target.triple).join("md-doc")) } - /// Returns `true` if no custom `llvm-config` is set for the specified target. + /// Returns `true` if this is an external version of LLVM not managed by bootstrap. + /// In particular, we expect llvm sources to be available when this is false. /// - /// If no custom `llvm-config` was specified then Rust's llvm will be used. + /// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set. + fn is_system_llvm(&self, target: TargetSelection) -> bool { + match self.config.target_config.get(&target) { + Some(Target { llvm_config: Some(_), .. }) => { + let ci_llvm = self.config.llvm_from_ci && target == self.config.build; + !ci_llvm + } + // We're building from the in-tree src/llvm-project sources. + Some(Target { llvm_config: None, .. }) => false, + None => false, + } + } + + /// Returns `true` if this is our custom, patched, version of LLVM. + /// + /// This does not necessarily imply that we're managing the `llvm-project` submodule. fn is_rust_llvm(&self, target: TargetSelection) -> bool { match self.config.target_config.get(&target) { + // We're using a user-controlled version of LLVM. The user has explicitly told us whether the version has our patches. + // (They might be wrong, but that's not a supported use-case.) + // In particular, this tries to support `submodules = false` and `patches = false`, for using a newer version of LLVM that's not through `rust-lang/llvm-project`. Some(Target { llvm_has_rust_patches: Some(patched), .. }) => *patched, - Some(Target { llvm_config, .. }) => { - // If the user set llvm-config we assume Rust is not patched, - // but first check to see if it was configured by llvm-from-ci. - (self.config.llvm_from_ci && target == self.config.build) || llvm_config.is_none() - } - None => true, + // The user hasn't promised the patches match. + // This only has our patches if it's downloaded from CI or built from source. + _ => !self.is_system_llvm(target), } } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 25efa5079c87..327b4674acfd 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -106,4 +106,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "The dist.missing-tools config option was deprecated, as it was unused. If you are using it, remove it from your config, it will be removed soon.", }, + ChangeInfo { + change_id: 102579, + severity: ChangeSeverity::Warning, + summary: "A new `optimized-compiler-builtins` option has been introduced. Whether to build llvm's `compiler-rt` from source is no longer implicitly controlled by git state. See the PR for more details.", + }, ]; diff --git a/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile b/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile index 5ddd3f180396..637b5fa22f97 100644 --- a/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile @@ -47,4 +47,6 @@ ENV RUST_CONFIGURE_ARGS --disable-jemalloc \ --set=$TARGET.cc=x86_64-unknown-haiku-gcc \ --set=$TARGET.cxx=x86_64-unknown-haiku-g++ \ --set=$TARGET.llvm-config=/bin/llvm-config-haiku +ENV EXTERNAL_LLVM 1 + ENV SCRIPT python3 ../x.py dist --host=$HOST --target=$HOST diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile index f1d6b9a4ef26..fe30a9534410 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile @@ -40,6 +40,7 @@ RUN sh /scripts/sccache.sh # We are disabling CI LLVM since this builder is intentionally using a host # LLVM, rather than the typical src/llvm-project LLVM. ENV NO_DOWNLOAD_CI_LLVM 1 +ENV EXTERNAL_LLVM 1 # Using llvm-link-shared due to libffi issues -- see #34486 ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 205ee263217a..cc0c658aabd2 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -37,7 +37,6 @@ else fi # We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc. # Also cover some other targets via cross-testing, in particular all tier 1 targets. -export BOOTSTRAP_SKIP_TARGET_SANITY=1 # we don't need `cc` for these targets case $HOST_TARGET in x86_64-unknown-linux-gnu) # Only this branch runs in PR CI. @@ -62,4 +61,3 @@ case $HOST_TARGET in exit 1 ;; esac -unset BOOTSTRAP_SKIP_TARGET_SANITY diff --git a/src/ci/run.sh b/src/ci/run.sh index dc0d5e02cb1b..420545172e6d 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -85,6 +85,15 @@ fi # space required for CI artifacts. RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --dist-compression-formats=xz" +# Enable the `c` feature for compiler_builtins, but only when the `compiler-rt` source is available +# (to avoid spending a lot of time cloning llvm) +if [ "$EXTERNAL_LLVM" = "" ]; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.optimized-compiler-builtins" +elif [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then + echo "error: dist builds should always use optimized compiler-rt!" >&2 + exit 1 +fi + if [ "$DIST_SRC" = "" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-dist-src" fi diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 33a678a31d6a..2ddf5737fbd9 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -323,6 +323,7 @@ target | std | host | notes [`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? | | RISC-V Xous (RV32IMAC ISA) [`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF +[`riscv32imafc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ | | RISC-V Hermit `riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD `riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia diff --git a/src/doc/rustc/src/platform-support/esp-idf.md b/src/doc/rustc/src/platform-support/esp-idf.md index 8f630fa152c4..1f8d98598099 100644 --- a/src/doc/rustc/src/platform-support/esp-idf.md +++ b/src/doc/rustc/src/platform-support/esp-idf.md @@ -19,6 +19,7 @@ The target names follow this format: `$ARCH-esp-espidf`, where `$ARCH` specifies | `riscv32imc-esp-espidf` | [ESP32-C3](https://www.espressif.com/en/products/socs/esp32-c3) | `v4.3` | | `riscv32imac-esp-espidf` | [ESP32-C6](https://www.espressif.com/en/products/socs/esp32-c6) | `v5.1` | | `riscv32imac-esp-espidf` | [ESP32-H2](https://www.espressif.com/en/products/socs/esp32-h2) | `v5.1` | +| `riscv32imafc-esp-espidf`| [ESP32-P4](https://www.espressif.com/en/news/ESP32-P4) | `v5.2` | It is recommended to use the latest ESP-IDF stable release if possible. diff --git a/src/doc/rustdoc/src/read-documentation/search.md b/src/doc/rustdoc/src/read-documentation/search.md index 1f45bd6c6b82..b5f4060f0590 100644 --- a/src/doc/rustdoc/src/read-documentation/search.md +++ b/src/doc/rustdoc/src/read-documentation/search.md @@ -147,15 +147,38 @@ will match these queries: * `Read -> Result, Error>` * `Read -> Result` * `Read -> Result>` +* `Read -> u8` But it *does not* match `Result` or `Result>`. -Function signature searches also support arrays and slices. The explicit name -`primitive:slice` and `primitive:array` can be used to match a slice -or array of bytes, while square brackets `[u8]` will match either one. Empty -square brackets, `[]`, will match any slice or array regardless of what -it contains, while a slice with a type parameter, like `[T]`, will only match -functions that actually operate on generic slices. +### Primitives with Special Syntax + +| Shorthand | Explicit names | +| --------- | ------------------------------------------------ | +| `[]` | `primitive:slice` and/or `primitive:array` | +| `[T]` | `primitive:slice` and/or `primitive:array` | +| `()` | `primitive:unit` and/or `primitive:tuple` | +| `(T)` | `T` | +| `(T,)` | `primitive:tuple` | +| `!` | `primitive:never` | + +When searching for `[]`, Rustdoc will return search results with either slices +or arrays. If you know which one you want, you can force it to return results +for `primitive:slice` or `primitive:array` using the explicit name syntax. +Empty square brackets, `[]`, will match any slice or array regardless of what +it contains, or an item type can be provided, such as `[u8]` or `[T]`, to +explicitly find functions that operate on byte slices or generic slices, +respectively. + +A single type expression wrapped in parens is the same as that type expression, +since parens act as the grouping operator. If they're empty, though, they will +match both `unit` and `tuple`, and if there's more than one type (or a trailing +or leading comma) it is the same as `primitive:tuple<...>`. + +However, since items can be left out of the query, `(T)` will still return +results for types that match tuples, even though it also matches the type on +its own. That is, `(u32)` matches `(u32,)` for the exact same reason that it +also matches `Result`. ### Limitations and quirks of type-based search @@ -188,11 +211,10 @@ Most of these limitations should be addressed in future version of Rustdoc. that you don't want a type parameter, you can force it to match something else by giving it a different prefix like `struct:T`. - * It's impossible to search for references, pointers, or tuples. The + * It's impossible to search for references or pointers. The wrapped types can be searched for, so a function that takes `&File` can be found with `File`, but you'll get a parse error when typing an `&` - into the search field. Similarly, `Option<(T, U)>` can be matched with - `Option`, but `(` will give a parse error. + into the search field. * Searching for lifetimes is not supported. @@ -216,8 +238,9 @@ Item filters can be used in both name-based and type signature-based searches. ```text ident = *(ALPHA / DIGIT / "_") path = ident *(DOUBLE-COLON ident) [!] -slice = OPEN-SQUARE-BRACKET [ nonempty-arg-list ] CLOSE-SQUARE-BRACKET -arg = [type-filter *WS COLON *WS] (path [generics] / slice / [!]) +slice-like = OPEN-SQUARE-BRACKET [ nonempty-arg-list ] CLOSE-SQUARE-BRACKET +tuple-like = OPEN-PAREN [ nonempty-arg-list ] CLOSE-PAREN +arg = [type-filter *WS COLON *WS] (path [generics] / slice-like / tuple-like / [!]) type-sep = COMMA/WS *(COMMA/WS) nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep) generic-arg-list = *(type-sep) arg [ EQUAL arg ] *(type-sep arg [ EQUAL arg ]) *(type-sep) @@ -263,6 +286,8 @@ OPEN-ANGLE-BRACKET = "<" CLOSE-ANGLE-BRACKET = ">" OPEN-SQUARE-BRACKET = "[" CLOSE-SQUARE-BRACKET = "]" +OPEN-PAREN = "(" +CLOSE-PAREN = ")" COLON = ":" DOUBLE-COLON = "::" QUOTE = %x22 diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md index 8ab6e83d99e7..e8fc2fe986e2 100644 --- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -4,18 +4,16 @@ The tracking issue for this feature is: [#82450](https://github.com/rust-lang/ru ------------------------ -This feature allows you to enable complete or partial checking of configuration. +This feature enables checking of conditional configuration. `rustc` accepts the `--check-cfg` option, which specifies whether to check conditions and how to -check them. The `--check-cfg` option takes a value, called the _check cfg specification_. The -check cfg specification is parsed using the Rust metadata syntax, just as the `--cfg` option is. +check them. The `--check-cfg` option takes a value, called the _check cfg specification_. +This specification has one form: -`--check-cfg` option take one form: +1. `--check-cfg cfg(...)` mark a configuration and it's expected values as expected. -1. `--check-cfg cfg(...)` enables checking the values within list-valued conditions. - -NOTE: No implicit expectation is added when using `--cfg` for both forms. Users are expected to -pass all expected names and values using `cfg(...)`. +*No implicit expectation is added when using `--cfg`. Users are expected to +pass all expected names and values using the _check cfg specification_.* ## The `cfg(...)` form @@ -23,7 +21,7 @@ The `cfg(...)` form enables checking the values within list-valued conditions. I basic form: ```bash -rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))' +rustc --check-cfg 'cfg(name, values("value1", "value2", ... "valueN"))' ``` where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal @@ -31,162 +29,186 @@ string. `name` specifies the name of the condition, such as `feature` or `my_cfg When the `cfg(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]` attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]` -and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the -list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs` -lint diagnostic. The default diagnostic level for this lint is `Warn`. +attribute and `cfg!(name = "value")` macro call. It will check that the `"value"` specified is +present in the list of expected values. If `"value"` is not in it, then `rustc` will report an +`unexpected_cfgs` lint diagnostic. The default diagnostic level for this lint is `Warn`. -The command line `--cfg` arguments are currently *NOT* checked but may very well be checked in -the future. +*The command line `--cfg` arguments are currently *NOT* checked but may very well be checked in +the future.* -To enable checking of values, but to provide an empty set of expected values, use these forms: +To enable checking of values, but to provide an *none*/empty set of expected values +(ie. expect `#[cfg(name)]`), use these forms: ```bash -rustc --check-cfg 'cfg(name1, ..., nameN)' -rustc --check-cfg 'cfg(name1, ..., nameN, values())' +rustc --check-cfg 'cfg(name)' +rustc --check-cfg 'cfg(name, values())' ``` To enable checking of name but not values (i.e. unknown expected values), use this form: ```bash -rustc --check-cfg 'cfg(name1, ..., nameN, values(any()))' +rustc --check-cfg 'cfg(name, values(any()))' +``` + +To avoid repeating the same set of values, use this form: + +```bash +rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))' ``` The `--check-cfg cfg(...)` option can be repeated, both for the same condition name and for different names. If it is repeated for the same condition name, then the sets of values for that -condition are merged together (presedence is given to `any()`). +condition are merged together (precedence is given to `values(any())`). ## Well known names and values `rustc` has a internal list of well known names and their corresponding values. Those well known names and values follows the same stability as what they refer to. -Well known values checking is always enabled as long as a `--check-cfg` argument is present. +Well known names and values checking is always enabled as long as at least one +`--check-cfg` argument is present. -Well known names checking is always enable as long as a `--check-cfg` argument is present -**unless** any `cfg(any())` argument is passed. +As of `2024-01-09T`, the list of known names is as follows: -To disable checking of well known names, use this form: + -```bash -rustc --check-cfg 'cfg(any())' -``` + - `debug_assertions` + - `doc` + - `doctest` + - `miri` + - `overflow_checks` + - `panic` + - `proc_macro` + - `relocation_model` + - `sanitize` + - `sanitizer_cfi_generalize_pointers` + - `sanitizer_cfi_normalize_integers` + - `target_abi` + - `target_arch` + - `target_endian` + - `target_env` + - `target_family` + - `target_feature` + - `target_has_atomic` + - `target_has_atomic_equal_alignment` + - `target_has_atomic_load_store` + - `target_os` + - `target_pointer_width` + - `target_thread_local` + - `target_vendor` + - `test` + - `unix` + - `windows` -NOTE: If one want to enable values and names checking without having any cfg to declare, one -can use an empty `cfg()` argument. +Like with `values(any())`, well known names checking can be disabled by passing `cfg(any())` +as argument to `--check-cfg`. ## Examples +### Equivalence table + +This table describe the equivalence of a `--cfg` argument to a `--check-cfg` argument. + +| `--cfg` | `--check-cfg` | +|-----------------------------|----------------------------------------------------------| +| *nothing* | *nothing* or `--check-cfg=cfg()` (to enable the checking) | +| `--cfg foo` | `--check-cfg=cfg(foo) or --check-cfg=cfg(foo, values())` | +| `--cfg foo=""` | `--check-cfg=cfg(foo, values(""))` | +| `--cfg foo="bar"` | `--check-cfg=cfg(foo, values("bar"))` | +| `--cfg foo="1" --cfg foo="2"` | `--check-cfg=cfg(foo, values("1", "2"))` | +| `--cfg foo="1" --cfg bar="2"` | `--check-cfg=cfg(foo, values("1")) --check-cfg=cfg(bar, values("2"))` | +| `--cfg foo --cfg foo="bar"` | `--check-cfg=cfg(foo) --check-cfg=cfg(foo, values("bar"))` | + +NOTE: There is (currently) no way to express that a condition name is expected but no (!= none) +values are expected. Passing an empty `values()` means *(none)* in the sense of `#[cfg(foo)]` +with no value. Users are expected to NOT pass a `--check-cfg` with that condition name. + +### Example: Cargo-like `feature` example + Consider this command line: ```bash rustc --check-cfg 'cfg(feature, values("lion", "zebra"))' \ - --cfg 'feature="lion"' -Z unstable-options \ - example.rs + --cfg 'feature="lion"' -Z unstable-options example.rs ``` This command line indicates that this crate has two features: `lion` and `zebra`. The `lion` -feature is enabled, while the `zebra` feature is disabled. Exhaustive checking of names and -values are enabled by default. Consider compiling this code: +feature is enabled, while the `zebra` feature is disabled. +Given the `--check-cfg` arguments, exhaustive checking of names and +values are enabled. +`example.rs`: ```rust -// This is expected, and tame_lion() will be compiled -#[cfg(feature = "lion")] +#[cfg(feature = "lion")] // This condition is expected, as "lion" is an expected value of `feature` fn tame_lion(lion: Lion) {} -// This is expected, and ride_zebra() will NOT be compiled. -#[cfg(feature = "zebra")] -fn ride_zebra(zebra: Zebra) {} +#[cfg(feature = "zebra")] // This condition is expected, as "zebra" is an expected value of `feature` + // but the condition will still evaluate to false + // since only --cfg feature="lion" was passed +fn ride_zebra(z: Zebra) {} -// This is UNEXPECTED, and will cause a compiler warning (by default). -#[cfg(feature = "platypus")] +#[cfg(feature = "platypus")] // This condition is UNEXPECTED, as "platypus" is NOT an expected value of + // `feature` and will cause a compiler warning (by default). fn poke_platypus() {} -// This is UNEXPECTED, because 'feechure' is not a known condition name, -// and will cause a compiler warning (by default). -#[cfg(feechure = "lion")] +#[cfg(feechure = "lion")] // This condition is UNEXPECTED, as 'feechure' is NOT a expected condition + // name, no `cfg(feechure, ...)` was passed in `--check-cfg` fn tame_lion() {} -// This is UNEXPECTED, because 'windows' is a well known condition name, -// and because 'windows' doesn't take any values, -// and will cause a compiler warning (by default). -#[cfg(windows = "unix")] +#[cfg(windows = "unix")] // This condition is UNEXPECTED, as while 'windows' is a well known + // condition name, it doens't expect any values fn tame_windows() {} ``` -### Example: Checking condition names, but not values +### Example: Multiple names and values ```bash -# This turns on checking for condition names, but not values, such as 'feature' values. -rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \ - --cfg has_feathers -Z unstable-options -``` - -```rust -#[cfg(is_embedded)] // This is expected as "is_embedded" was provided in cfg() -fn do_embedded() {} // and because names exhaustiveness was not disabled - -#[cfg(has_feathers)] // This is expected as "has_feathers" was provided in cfg() -fn do_features() {} // and because names exhaustiveness was not disabled - -#[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in cfg() - // and because no value checking was enable for "has_feathers" - // no warning is emitted for the value "zapping" -fn do_zapping() {} - -#[cfg(has_mumble_frotz)] // This is UNEXPECTED because names checking is enable and - // "has_mumble_frotz" was not provided in cfg() -fn do_mumble_frotz() {} -``` - -### Example: Checking feature values, but not condition names - -```bash -# This turns on checking for feature values, but not for condition names. -rustc --check-cfg 'cfg(feature, values("zapping", "lasers"))' \ - --check-cfg 'cfg(any())' \ - --cfg 'feature="zapping"' -Z unstable-options -``` - -```rust -#[cfg(is_embedded)] // This is doesn't raise a warning, because names checking was - // disabled by 'cfg(any())' -fn do_embedded() {} - -#[cfg(has_feathers)] // Same as above, 'cfg(any())' was provided so no name - // checking is performed -fn do_features() {} - -#[cfg(feature = "lasers")] // This is expected, "lasers" is in the cfg(feature) list -fn shoot_lasers() {} - -#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in the - // cfg(feature) list -fn write_shakespeare() {} -``` - -### Example: Checking both condition names and feature values - -```bash -# This turns on checking for feature values and for condition names. rustc --check-cfg 'cfg(is_embedded, has_feathers)' \ --check-cfg 'cfg(feature, values("zapping", "lasers"))' \ --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options ``` ```rust -#[cfg(is_embedded)] // This is expected because "is_embedded" was provided in cfg() +#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was provided in --check-cfg fn do_embedded() {} // and doesn't take any value -#[cfg(has_feathers)] // This is expected because "has_feathers" was provided in cfg() -fn do_features() {} // and deosn't take any value +#[cfg(has_feathers)] // This condition is expected, as 'has_feathers' was provided in --check-cfg +fn do_features() {} // and doesn't take any value -#[cfg(has_mumble_frotz)] // This is UNEXPECTED, because "has_mumble_frotz" was never provided +#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was NEVER provided + // in any --check-cfg arguments fn do_mumble_frotz() {} -#[cfg(feature = "lasers")] // This is expected, "lasers" is in the cfg(feature) list +#[cfg(feature = "lasers")] // This condition is expected, as "lasers" is an expected value of `feature` fn shoot_lasers() {} -#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in - // the cfg(feature) list +#[cfg(feature = "monkeys")] // This condition is UNEXPECTED, as "monkeys" is NOT an expected value of + // `feature` fn write_shakespeare() {} ``` + +### Example: Condition names without values + +```bash +rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \ + --cfg has_feathers -Z unstable-options +``` + +```rust +#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was provided in --check-cfg + // as condition name +fn do_embedded() {} + +#[cfg(has_feathers)] // This condition is expected, as "has_feathers" was provided in --check-cfg + // as condition name +fn do_features() {} + +#[cfg(has_feathers = "zapping")] // This condition is expected, as "has_feathers" was provided in + // and because *any* values is expected for 'has_feathers' no + // warning is emitted for the value "zapping" +fn do_zapping() {} + +#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was not provided + // in any --check-cfg arguments +fn do_mumble_frotz() {} +``` diff --git a/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md b/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md new file mode 100644 index 000000000000..4f3c780972de --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md @@ -0,0 +1,11 @@ +# `shell-argfiles` + +-------------------- + +The `-Zshell-argfiles` compiler flag allows argfiles to be parsed using POSIX +"shell-style" quoting. When enabled, the compiler will use `shlex` to parse the +arguments from argfiles specified with `@shell:`. + +Because this feature controls the parsing of input arguments, the +`-Zshell-argfiles` flag must be present before the argument specifying the +shell-style arguemnt file. diff --git a/src/doc/unstable-book/src/library-features/core-panic.md b/src/doc/unstable-book/src/library-features/core-panic.md deleted file mode 100644 index c197588404c9..000000000000 --- a/src/doc/unstable-book/src/library-features/core-panic.md +++ /dev/null @@ -1,5 +0,0 @@ -# `core_panic` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 95bce9e31a4d..9fc95fd09ba9 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -143,6 +143,8 @@ complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-profile-use -d complete -c x.py -n "__fish_seen_subcommand_from clippy" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r complete -c x.py -n "__fish_seen_subcommand_from clippy" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from clippy" -l fix +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l allow-dirty +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l allow-staged complete -c x.py -n "__fish_seen_subcommand_from clippy" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from clippy" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_seen_subcommand_from clippy" -l include-default-paths -d 'include default paths in addition to the provided ones' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index dabc3b16e4d7..6359b7ff086a 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -188,6 +188,8 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive') [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('--fix', 'fix', [CompletionResultType]::ParameterName, 'fix') + [CompletionResult]::new('--allow-dirty', 'allow-dirty', [CompletionResultType]::ParameterName, 'allow-dirty') + [CompletionResult]::new('--allow-staged', 'allow-staged', [CompletionResultType]::ParameterName, 'allow-staged') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index f739f46b88bb..8ffd8f67df25 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -615,7 +615,7 @@ _x.py() { return 0 ;; x.py__clippy) - opts="-A -D -W -F -v -i -j -h --fix --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-A -D -W -F -v -i -j -h --fix --allow-dirty --allow-staged --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 639f0487f8b0..ea7e4ba6758f 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -182,6 +182,8 @@ _arguments "${_arguments_options[@]}" \ '*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ '*--set=[override options in config.toml]:section.option=value:( )' \ '--fix[]' \ +'--allow-dirty[]' \ +'--allow-staged[]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1a25d3f79936..4441060de98a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -207,8 +207,13 @@ pub(crate) fn clean_trait_ref_with_bindings<'tcx>( span_bug!(cx.tcx.def_span(trait_ref.def_id()), "`TraitRef` had unexpected kind {kind:?}"); } inline::record_extern_fqn(cx, trait_ref.def_id(), kind); - let path = - external_path(cx, trait_ref.def_id(), true, bindings, trait_ref.map_bound(|tr| tr.args)); + let path = clean_middle_path( + cx, + trait_ref.def_id(), + true, + bindings, + trait_ref.map_bound(|tr| tr.args), + ); debug!(?trait_ref); @@ -467,7 +472,7 @@ fn projection_to_path_segment<'tcx>( PathSegment { name: item.name, args: GenericArgs::AngleBracketed { - args: ty_args_to_args( + args: clean_middle_generic_args( cx, ty.map_bound(|ty| &ty.args[generics.parent_count..]), false, @@ -1903,7 +1908,7 @@ fn normalize<'tcx>( fn clean_trait_object_lifetime_bound<'tcx>( region: ty::Region<'tcx>, - container: Option>, + container: Option>, preds: &'tcx ty::List>, tcx: TyCtxt<'tcx>, ) -> Option { @@ -1932,7 +1937,7 @@ fn clean_trait_object_lifetime_bound<'tcx>( fn can_elide_trait_object_lifetime_bound<'tcx>( region: ty::Region<'tcx>, - container: Option>, + container: Option>, preds: &'tcx ty::List>, tcx: TyCtxt<'tcx>, ) -> bool { @@ -1979,21 +1984,22 @@ fn can_elide_trait_object_lifetime_bound<'tcx>( } #[derive(Debug)] -pub(crate) enum ContainerTy<'tcx> { +pub(crate) enum ContainerTy<'a, 'tcx> { Ref(ty::Region<'tcx>), Regular { ty: DefId, - args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, - has_self: bool, + /// The arguments *have* to contain an arg for the self type if the corresponding generics + /// contain a self type. + args: ty::Binder<'tcx, &'a [ty::GenericArg<'tcx>]>, arg: usize, }, } -impl<'tcx> ContainerTy<'tcx> { +impl<'tcx> ContainerTy<'_, 'tcx> { fn object_lifetime_default(self, tcx: TyCtxt<'tcx>) -> ObjectLifetimeDefault<'tcx> { match self { Self::Ref(region) => ObjectLifetimeDefault::Arg(region), - Self::Regular { ty: container, args, has_self, arg: index } => { + Self::Regular { ty: container, args, arg: index } => { let (DefKind::Struct | DefKind::Union | DefKind::Enum @@ -2006,14 +2012,7 @@ impl<'tcx> ContainerTy<'tcx> { let generics = tcx.generics_of(container); debug_assert_eq!(generics.parent_count, 0); - // If the container is a trait object type, the arguments won't contain the self type but the - // generics of the corresponding trait will. In such a case, offset the index by one. - // For comparison, if the container is a trait inside a bound, the arguments do contain the - // self type. - let offset = - if !has_self && generics.parent.is_none() && generics.has_self { 1 } else { 0 }; - let param = generics.params[index + offset].def_id; - + let param = generics.params[index].def_id; let default = tcx.object_lifetime_default(param); match default { rbv::ObjectLifetimeDefault::Param(lifetime) => { @@ -2045,7 +2044,7 @@ pub(crate) fn clean_middle_ty<'tcx>( bound_ty: ty::Binder<'tcx, Ty<'tcx>>, cx: &mut DocContext<'tcx>, parent_def_id: Option, - container: Option>, + container: Option>, ) -> Type { let bound_ty = normalize(cx, bound_ty).unwrap_or(bound_ty); match *bound_ty.skip_binder().kind() { @@ -2096,12 +2095,12 @@ pub(crate) fn clean_middle_ty<'tcx>( AdtKind::Enum => ItemType::Enum, }; inline::record_extern_fqn(cx, did, kind); - let path = external_path(cx, did, false, ThinVec::new(), bound_ty.rebind(args)); + let path = clean_middle_path(cx, did, false, ThinVec::new(), bound_ty.rebind(args)); Type::Path { path } } ty::Foreign(did) => { inline::record_extern_fqn(cx, did, ItemType::ForeignType); - let path = external_path( + let path = clean_middle_path( cx, did, false, @@ -2132,7 +2131,7 @@ pub(crate) fn clean_middle_ty<'tcx>( let mut bounds = dids .map(|did| { let empty = ty::Binder::dummy(ty::GenericArgs::empty()); - let path = external_path(cx, did, false, ThinVec::new(), empty); + let path = clean_middle_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); PolyTrait { trait_: path, generic_params: Vec::new() } }) @@ -2171,7 +2170,7 @@ pub(crate) fn clean_middle_ty<'tcx>( .collect(); let late_bound_regions = late_bound_regions.into_iter().collect(); - let path = external_path(cx, did, false, bindings, args); + let path = clean_middle_path(cx, did, false, bindings, args); bounds.insert(0, PolyTrait { trait_: path, generic_params: late_bound_regions }); DynTrait(bounds, lifetime) @@ -2193,7 +2192,7 @@ pub(crate) fn clean_middle_ty<'tcx>( assoc: PathSegment { name: cx.tcx.associated_item(def_id).name, args: GenericArgs::AngleBracketed { - args: ty_args_to_args( + args: clean_middle_generic_args( cx, alias_ty.map_bound(|ty| ty.args.as_slice()), true, @@ -2213,7 +2212,7 @@ pub(crate) fn clean_middle_ty<'tcx>( if cx.tcx.features().lazy_type_alias { // Weak type alias `data` represents the `type X` in `type X = Y`. If we need `Y`, // we need to use `type_of`. - let path = external_path( + let path = clean_middle_path( cx, data.def_id, false, @@ -2243,7 +2242,8 @@ pub(crate) fn clean_middle_ty<'tcx>( ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { // If it's already in the same alias, don't get an infinite loop. if cx.current_type_aliases.contains_key(&def_id) { - let path = external_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(args)); + let path = + clean_middle_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(args)); Type::Path { path } } else { *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; @@ -3001,7 +3001,7 @@ fn clean_use_statement_inner<'tcx>( E0780, "anonymous imports cannot be inlined" ) - .span_label(import.span, "anonymous import") + .span_label_mv(import.span, "anonymous import") .emit(); } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 179f37e6d96a..90eb783c7cae 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -36,7 +36,7 @@ use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use crate::clean::cfg::Cfg; -use crate::clean::external_path; +use crate::clean::clean_middle_path; use crate::clean::inline::{self, print_inlined_const}; use crate::clean::utils::{is_literal_expr, print_evaluated_const}; use crate::core::DocContext; @@ -1258,7 +1258,7 @@ impl GenericBound { fn sized_with(cx: &mut DocContext<'_>, modifier: hir::TraitBoundModifier) -> GenericBound { let did = cx.tcx.require_lang_item(LangItem::Sized, None); let empty = ty::Binder::dummy(ty::GenericArgs::empty()); - let path = external_path(cx, did, false, ThinVec::new(), empty); + let path = clean_middle_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifier) } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index bdfda07be096..437517598ac4 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -16,9 +16,10 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_metadata::rendered_const; use rustc_middle::mir; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, TyCtxt}; -use rustc_middle::ty::{TypeVisitable, TypeVisitableExt}; use rustc_span::symbol::{kw, sym, Symbol}; +use std::assert_matches::debug_assert_matches; use std::fmt::Write as _; use std::mem; use std::sync::LazyLock as Lazy; @@ -75,80 +76,83 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { Crate { module, external_traits: cx.external_traits.clone() } } -pub(crate) fn ty_args_to_args<'tcx>( +pub(crate) fn clean_middle_generic_args<'tcx>( cx: &mut DocContext<'tcx>, - ty_args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, - has_self: bool, + args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, + mut has_self: bool, owner: DefId, ) -> Vec { - if ty_args.skip_binder().is_empty() { + let (args, bound_vars) = (args.skip_binder(), args.bound_vars()); + if args.is_empty() { // Fast path which avoids executing the query `generics_of`. return Vec::new(); } - let params = &cx.tcx.generics_of(owner).params; + // If the container is a trait object type, the arguments won't contain the self type but the + // generics of the corresponding trait will. In such a case, prepend a dummy self type in order + // to align the arguments and parameters for the iteration below and to enable us to correctly + // instantiate the generic parameter default later. + let generics = cx.tcx.generics_of(owner); + let args = if !has_self && generics.parent.is_none() && generics.has_self { + has_self = true; + [cx.tcx.types.trait_object_dummy_self.into()] + .into_iter() + .chain(args.iter().copied()) + .collect::>() + .into() + } else { + std::borrow::Cow::from(args) + }; + let mut elision_has_failed_once_before = false; - - let offset = if has_self { 1 } else { 0 }; - let mut args = Vec::with_capacity(ty_args.skip_binder().len().saturating_sub(offset)); - - let ty_arg_to_arg = |(index, arg): (usize, &ty::GenericArg<'tcx>)| match arg.unpack() { - GenericArgKind::Lifetime(lt) => { - Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided()))) + let clean_arg = |(index, &arg): (usize, &ty::GenericArg<'tcx>)| { + // Elide the self type. + if has_self && index == 0 { + return None; } - GenericArgKind::Type(_) if has_self && index == 0 => None, - GenericArgKind::Type(ty) => { - if !elision_has_failed_once_before - && let Some(default) = params[index].default_value(cx.tcx) - { - let default = - ty_args.map_bound(|args| default.instantiate(cx.tcx, args).expect_ty()); - if can_elide_generic_arg(ty_args.rebind(ty), default) { - return None; - } + // Elide internal host effect args. + let param = generics.param_at(index, cx.tcx); + if param.is_host_effect() { + return None; + } - elision_has_failed_once_before = true; + let arg = ty::Binder::bind_with_vars(arg, bound_vars); + + // Elide arguments that coincide with their default. + if !elision_has_failed_once_before && let Some(default) = param.default_value(cx.tcx) { + let default = default.instantiate(cx.tcx, args.as_ref()); + if can_elide_generic_arg(arg, arg.rebind(default)) { + return None; } + elision_has_failed_once_before = true; + } - Some(GenericArg::Type(clean_middle_ty( - ty_args.rebind(ty), + match arg.skip_binder().unpack() { + GenericArgKind::Lifetime(lt) => { + Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided()))) + } + GenericArgKind::Type(ty) => Some(GenericArg::Type(clean_middle_ty( + arg.rebind(ty), cx, None, Some(crate::clean::ContainerTy::Regular { ty: owner, - args: ty_args, - has_self, + args: arg.rebind(args.as_ref()), arg: index, }), - ))) - } - GenericArgKind::Const(ct) => { - if let ty::GenericParamDefKind::Const { is_host_effect: true, .. } = params[index].kind - { - return None; + ))), + GenericArgKind::Const(ct) => { + Some(GenericArg::Const(Box::new(clean_middle_const(arg.rebind(ct), cx)))) } - - if !elision_has_failed_once_before - && let Some(default) = params[index].default_value(cx.tcx) - { - let default = - ty_args.map_bound(|args| default.instantiate(cx.tcx, args).expect_const()); - - if can_elide_generic_arg(ty_args.rebind(ct), default) { - return None; - } - - elision_has_failed_once_before = true; - } - - Some(GenericArg::Const(Box::new(clean_middle_const(ty_args.rebind(ct), cx)))) } }; - args.extend(ty_args.skip_binder().iter().enumerate().rev().filter_map(ty_arg_to_arg)); - args.reverse(); - args + let offset = if has_self { 1 } else { 0 }; + let mut clean_args = Vec::with_capacity(args.len().saturating_sub(offset)); + clean_args.extend(args.iter().enumerate().rev().filter_map(clean_arg)); + clean_args.reverse(); + clean_args } /// Check if the generic argument `actual` coincides with the `default` and can therefore be elided. @@ -156,13 +160,17 @@ pub(crate) fn ty_args_to_args<'tcx>( /// This uses a very conservative approach for performance and correctness reasons, meaning for /// several classes of terms it claims that they cannot be elided even if they theoretically could. /// This is absolutely fine since it mostly concerns edge cases. -fn can_elide_generic_arg<'tcx, Term>( - actual: ty::Binder<'tcx, Term>, - default: ty::Binder<'tcx, Term>, -) -> bool -where - Term: Eq + TypeVisitable>, -{ +fn can_elide_generic_arg<'tcx>( + actual: ty::Binder<'tcx, ty::GenericArg<'tcx>>, + default: ty::Binder<'tcx, ty::GenericArg<'tcx>>, +) -> bool { + debug_assert_matches!( + (actual.skip_binder().unpack(), default.skip_binder().unpack()), + (ty::GenericArgKind::Lifetime(_), ty::GenericArgKind::Lifetime(_)) + | (ty::GenericArgKind::Type(_), ty::GenericArgKind::Type(_)) + | (ty::GenericArgKind::Const(_), ty::GenericArgKind::Const(_)) + ); + // In practice, we shouldn't have any inference variables at this point. // However to be safe, we bail out if we do happen to stumble upon them. if actual.has_infer() || default.has_infer() { @@ -192,14 +200,14 @@ where actual.skip_binder() == default.skip_binder() } -fn external_generic_args<'tcx>( +fn clean_middle_generic_args_with_bindings<'tcx>( cx: &mut DocContext<'tcx>, did: DefId, has_self: bool, bindings: ThinVec, ty_args: ty::Binder<'tcx, GenericArgsRef<'tcx>>, ) -> GenericArgs { - let args = ty_args_to_args(cx, ty_args.map_bound(|args| &args[..]), has_self, did); + let args = clean_middle_generic_args(cx, ty_args.map_bound(|args| &args[..]), has_self, did); if cx.tcx.fn_trait_kind_from_def_id(did).is_some() { let ty = ty_args @@ -225,7 +233,7 @@ fn external_generic_args<'tcx>( } } -pub(super) fn external_path<'tcx>( +pub(super) fn clean_middle_path<'tcx>( cx: &mut DocContext<'tcx>, did: DefId, has_self: bool, @@ -238,7 +246,7 @@ pub(super) fn external_path<'tcx>( res: Res::Def(def_kind, did), segments: thin_vec![PathSegment { name, - args: external_generic_args(cx, did, has_self, bindings, args), + args: clean_middle_generic_args_with_bindings(cx, did, has_self, bindings, args), }], } } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index f3d63fad7115..614a64d40201 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -577,13 +577,13 @@ impl Options { { if !theme_file.is_file() { dcx.struct_err(format!("invalid argument: \"{theme_s}\"")) - .help("arguments to --theme must be files") + .help_mv("arguments to --theme must be files") .emit(); return Err(1); } if theme_file.extension() != Some(OsStr::new("css")) { dcx.struct_err(format!("invalid argument: \"{theme_s}\"")) - .help("arguments to --theme must have a .css extension") + .help_mv("arguments to --theme must have a .css extension") .emit(); return Err(1); } @@ -595,8 +595,8 @@ impl Options { dcx.struct_warn(format!( "theme file \"{theme_s}\" is missing CSS rules from the default theme", )) - .warn("the theme may appear incorrect when loaded") - .help(format!( + .warn_mv("the theme may appear incorrect when loaded") + .help_mv(format!( "to see what rules are missing, call `rustdoc --check-theme \"{theme_s}\"`", )) .emit(); @@ -809,7 +809,7 @@ fn check_deprecated_options(matches: &getopts::Matches, dcx: &rustc_errors::Diag for &flag in deprecated_flags.iter() { if matches.opt_present(flag) { dcx.struct_warn(format!("the `{flag}` flag is deprecated")) - .note( + .note_mv( "see issue #44136 \ for more information", ) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 359d5ec485e3..40ea4346f933 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -495,16 +495,16 @@ impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> { .intersperse("::") .collect::() ); - let mut err = rustc_errors::struct_span_err!( + rustc_errors::struct_span_err!( self.tcx.dcx(), path.span, E0433, "failed to resolve: {label}", - ); - err.span_label(path.span, label); - err.note("this error was originally ignored because you are running `rustdoc`"); - err.note("try running again with `rustc` or `cargo check` and you may get a more detailed error"); - err.emit(); + ) + .span_label_mv(path.span, label) + .note_mv("this error was originally ignored because you are running `rustdoc`") + .note_mv("try running again with `rustc` or `cargo check` and you may get a more detailed error") + .emit(); } // We could have an outer resolution that succeeded, // but with generic parameters that failed. diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 118c6eeb289b..bea5ccd7c860 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -58,7 +58,7 @@ use rustc_span::{ symbol::{sym, Symbol}, BytePos, FileName, RealFileName, }; -use serde::ser::{SerializeMap, SerializeSeq}; +use serde::ser::SerializeMap; use serde::{Serialize, Serializer}; use crate::clean::{self, ItemId, RenderedLink, SelfTy}; @@ -123,44 +123,58 @@ pub(crate) struct IndexItem { } /// A type used for the search index. -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq)] pub(crate) struct RenderType { id: Option, generics: Option>, bindings: Option)>>, } -impl Serialize for RenderType { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let id = match &self.id { +impl RenderType { + // Types are rendered as lists of lists, because that's pretty compact. + // The contents of the lists are always integers in self-terminating hex + // form, handled by `RenderTypeId::write_to_string`, so no commas are + // needed to separate the items. + pub fn write_to_string(&self, string: &mut String) { + fn write_optional_id(id: Option, string: &mut String) { // 0 is a sentinel, everything else is one-indexed - None => 0, - // concrete type - Some(RenderTypeId::Index(idx)) if *idx >= 0 => idx + 1, - // generic type parameter - Some(RenderTypeId::Index(idx)) => *idx, - _ => panic!("must convert render types to indexes before serializing"), - }; - if self.generics.is_some() || self.bindings.is_some() { - let mut seq = serializer.serialize_seq(None)?; - seq.serialize_element(&id)?; - seq.serialize_element(self.generics.as_ref().map(Vec::as_slice).unwrap_or_default())?; - if self.bindings.is_some() { - seq.serialize_element( - self.bindings.as_ref().map(Vec::as_slice).unwrap_or_default(), - )?; + match id { + Some(id) => id.write_to_string(string), + None => string.push('`'), } - seq.end() + } + // Either just the type id, or `{type, generics, bindings?}` + // where generics is a list of types, + // and bindings is a list of `{id, typelist}` pairs. + if self.generics.is_some() || self.bindings.is_some() { + string.push('{'); + write_optional_id(self.id, string); + string.push('{'); + for generic in &self.generics.as_ref().map(Vec::as_slice).unwrap_or_default()[..] { + generic.write_to_string(string); + } + string.push('}'); + if self.bindings.is_some() { + string.push('{'); + for binding in &self.bindings.as_ref().map(Vec::as_slice).unwrap_or_default()[..] { + string.push('{'); + binding.0.write_to_string(string); + string.push('{'); + for constraint in &binding.1[..] { + constraint.write_to_string(string); + } + string.push_str("}}"); + } + string.push('}'); + } + string.push('}'); } else { - id.serialize(serializer) + write_optional_id(self.id, string); } } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum RenderTypeId { DefId(DefId), Primitive(clean::PrimitiveType), @@ -168,70 +182,122 @@ pub(crate) enum RenderTypeId { Index(isize), } -impl Serialize for RenderTypeId { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let id = match &self { +impl RenderTypeId { + pub fn write_to_string(&self, string: &mut String) { + // (sign, value) + let (sign, id): (bool, u32) = match &self { // 0 is a sentinel, everything else is one-indexed // concrete type - RenderTypeId::Index(idx) if *idx >= 0 => idx + 1, + RenderTypeId::Index(idx) if *idx >= 0 => (false, (idx + 1isize).try_into().unwrap()), // generic type parameter - RenderTypeId::Index(idx) => *idx, + RenderTypeId::Index(idx) => (true, (-*idx).try_into().unwrap()), _ => panic!("must convert render types to indexes before serializing"), }; - id.serialize(serializer) + // zig-zag encoding + let value: u32 = (id << 1) | (if sign { 1 } else { 0 }); + // Self-terminating hex use capital letters for everything but the + // least significant digit, which is lowercase. For example, decimal 17 + // would be `` Aa `` if zig-zag encoding weren't used. + // + // Zig-zag encoding, however, stores the sign bit as the last bit. + // This means, in the last hexit, 1 is actually `c`, -1 is `b` + // (`a` is the imaginary -0), and, because all the bits are shifted + // by one, `` A` `` is actually 8 and `` Aa `` is -8. + // + // https://rust-lang.github.io/rustc-dev-guide/rustdoc-internals/search.html + // describes the encoding in more detail. + let mut shift: u32 = 28; + let mut mask: u32 = 0xF0_00_00_00; + while shift < 32 { + let hexit = (value & mask) >> shift; + if hexit != 0 || shift == 0 { + let hex = + char::try_from(if shift == 0 { '`' } else { '@' } as u32 + hexit).unwrap(); + string.push(hex); + } + shift = shift.wrapping_sub(4); + mask = mask >> 4; + } } } /// Full type of functions/methods in the search index. -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq)] pub(crate) struct IndexItemFunctionType { inputs: Vec, output: Vec, where_clause: Vec>, } -impl Serialize for IndexItemFunctionType { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - // If we couldn't figure out a type, just write `0`. +impl IndexItemFunctionType { + pub fn write_to_string<'a>( + &'a self, + string: &mut String, + backref_queue: &mut VecDeque<&'a IndexItemFunctionType>, + ) { + assert!(backref_queue.len() <= 16); + // If we couldn't figure out a type, just write 0, + // which is encoded as `` ` `` (see RenderTypeId::write_to_string). let has_missing = self .inputs .iter() .chain(self.output.iter()) .any(|i| i.id.is_none() && i.generics.is_none()); if has_missing { - 0.serialize(serializer) + string.push('`'); + } else if let Some(idx) = backref_queue.iter().position(|other| *other == self) { + // The backref queue has 16 items, so backrefs use + // a single hexit, disjoint from the ones used for numbers. + string.push( + char::try_from('0' as u32 + u32::try_from(idx).unwrap()) + .expect("last possible value is '?'"), + ); } else { - let mut seq = serializer.serialize_seq(None)?; + backref_queue.push_front(self); + if backref_queue.len() > 16 { + backref_queue.pop_back(); + } + string.push('{'); match &self.inputs[..] { [one] if one.generics.is_none() && one.bindings.is_none() => { - seq.serialize_element(one)? + one.write_to_string(string); + } + _ => { + string.push('{'); + for item in &self.inputs[..] { + item.write_to_string(string); + } + string.push('}'); } - _ => seq.serialize_element(&self.inputs)?, } match &self.output[..] { [] if self.where_clause.is_empty() => {} [one] if one.generics.is_none() && one.bindings.is_none() => { - seq.serialize_element(one)? + one.write_to_string(string); + } + _ => { + string.push('{'); + for item in &self.output[..] { + item.write_to_string(string); + } + string.push('}'); } - _ => seq.serialize_element(&self.output)?, } for constraint in &self.where_clause { if let [one] = &constraint[..] && one.generics.is_none() && one.bindings.is_none() { - seq.serialize_element(one)?; + one.write_to_string(string); } else { - seq.serialize_element(constraint)?; + string.push('{'); + for item in &constraint[..] { + item.write_to_string(string); + } + string.push('}'); } } - seq.end() + string.push('}'); } } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 5ca623f01f1f..3b91fbdcb29d 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -4,7 +4,6 @@ use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_index::IndexVec; -use rustc_middle::query::Key; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; @@ -1259,7 +1258,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity(); - let enum_def_id = ty.ty_adt_id().unwrap(); + let enum_def_id = ty.ty_adt_def().unwrap().did(); wrap_item(w, |w| { let variants_len = variants.len(); diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index a1029320d2d2..cb059082f85b 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -1,5 +1,5 @@ use std::collections::hash_map::Entry; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, VecDeque}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_middle::ty::TyCtxt; @@ -409,9 +409,11 @@ pub(crate) fn build_index<'tcx>( let mut full_paths = Vec::with_capacity(self.items.len()); let mut descriptions = Vec::with_capacity(self.items.len()); let mut parents = Vec::with_capacity(self.items.len()); - let mut functions = Vec::with_capacity(self.items.len()); + let mut functions = String::with_capacity(self.items.len()); let mut deprecated = Vec::with_capacity(self.items.len()); + let mut backref_queue = VecDeque::new(); + for (index, item) in self.items.iter().enumerate() { let n = item.ty as u8; let c = char::try_from(n + b'A').expect("item types must fit in ASCII"); @@ -434,27 +436,10 @@ pub(crate) fn build_index<'tcx>( full_paths.push((index, &item.path)); } - // Fake option to get `0` out as a sentinel instead of `null`. - // We want to use `0` because it's three less bytes. - enum FunctionOption<'a> { - Function(&'a IndexItemFunctionType), - None, + match &item.search_type { + Some(ty) => ty.write_to_string(&mut functions, &mut backref_queue), + None => functions.push('`'), } - impl<'a> Serialize for FunctionOption<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - FunctionOption::None => 0.serialize(serializer), - FunctionOption::Function(ty) => ty.serialize(serializer), - } - } - } - functions.push(match &item.search_type { - Some(ty) => FunctionOption::Function(ty), - None => FunctionOption::None, - }); if item.deprecation.is_some() { deprecated.push(index); @@ -581,6 +566,9 @@ fn get_index_type_id( // The type parameters are converted to generics in `simplify_fn_type` clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)), clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)), + clean::Tuple(ref n) if n.is_empty() => { + Some(RenderTypeId::Primitive(clean::PrimitiveType::Unit)) + } clean::Tuple(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Tuple)), clean::QPath(ref data) => { if data.self_type.is_self_type() diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js index 93709e4e830a..d24148b9556b 100644 --- a/src/librustdoc/html/static/js/externs.js +++ b/src/librustdoc/html/static/js/externs.js @@ -200,3 +200,59 @@ let FunctionSearchType; * }} */ let FunctionType; + +/** + * The raw search data for a given crate. `n`, `t`, `d`, `i`, and `f` + * are arrays with the same length. `q`, `a`, and `c` use a sparse + * representation for compactness. + * + * `n[i]` contains the name of an item. + * + * `t[i]` contains the type of that item + * (as a string of characters that represent an offset in `itemTypes`). + * + * `d[i]` contains the description of that item. + * + * `q` contains the full paths of the items. For compactness, it is a set of + * (index, path) pairs used to create a map. If a given index `i` is + * not present, this indicates "same as the last index present". + * + * `i[i]` contains an item's parent, usually a module. For compactness, + * it is a set of indexes into the `p` array. + * + * `f` contains function signatures, or `0` if the item isn't a function. + * More information on how they're encoded can be found in rustc-dev-guide + * + * Functions are themselves encoded as arrays. The first item is a list of + * types representing the function's inputs, and the second list item is a list + * of types representing the function's output. Tuples are flattened. + * Types are also represented as arrays; the first item is an index into the `p` + * array, while the second is a list of types representing any generic parameters. + * + * b[i] contains an item's impl disambiguator. This is only present if an item + * is defined in an impl block and, the impl block's type has more than one associated + * item with the same name. + * + * `a` defines aliases with an Array of pairs: [name, offset], where `offset` + * points into the n/t/d/q/i/f arrays. + * + * `doc` contains the description of the crate. + * + * `p` is a list of path/type pairs. It is used for parents and function parameters. + * + * `c` is an array of item indices that are deprecated. + * @typedef {{ + * doc: string, + * a: Object, + * n: Array, + * t: String, + * d: Array, + * q: Array<[Number, string]>, + * i: Array, + * f: string, + * p: Array, + * b: Array<[Number, String]>, + * c: Array + * }} + */ +let RawSearchIndexCrate; diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index e6263db32835..7995a33f09f9 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -260,6 +260,18 @@ function initSearch(rawSearchIndex) { * Special type name IDs for searching by both array and slice (`[]` syntax). */ let typeNameIdOfArrayOrSlice; + /** + * Special type name IDs for searching by tuple. + */ + let typeNameIdOfTuple; + /** + * Special type name IDs for searching by unit. + */ + let typeNameIdOfUnit; + /** + * Special type name IDs for searching by both tuple and unit (`()` syntax). + */ + let typeNameIdOfTupleOrUnit; /** * Add an item to the type Name->ID map, or, if one already exists, use it. @@ -295,11 +307,7 @@ function initSearch(rawSearchIndex) { } function isEndCharacter(c) { - return "=,>-]".indexOf(c) !== -1; - } - - function isErrorCharacter(c) { - return "()".indexOf(c) !== -1; + return "=,>-])".indexOf(c) !== -1; } function itemTypeFromName(typename) { @@ -585,8 +593,6 @@ function initSearch(rawSearchIndex) { throw ["Unexpected ", "!", ": it can only be at the end of an ident"]; } foundExclamation = parserState.pos; - } else if (isErrorCharacter(c)) { - throw ["Unexpected ", c]; } else if (isPathSeparator(c)) { if (c === ":") { if (!isPathStart(parserState)) { @@ -616,11 +622,14 @@ function initSearch(rawSearchIndex) { } } else if ( c === "[" || + c === "(" || isEndCharacter(c) || isSpecialStartCharacter(c) || isSeparatorCharacter(c) ) { break; + } else if (parserState.pos > 0) { + throw ["Unexpected ", c, " after ", parserState.userQuery[parserState.pos - 1]]; } else { throw ["Unexpected ", c]; } @@ -661,15 +670,24 @@ function initSearch(rawSearchIndex) { skipWhitespace(parserState); let start = parserState.pos; let end; - if (parserState.userQuery[parserState.pos] === "[") { + if ("[(".indexOf(parserState.userQuery[parserState.pos]) !== -1) { +let endChar = ")"; +let name = "()"; +let friendlyName = "tuple"; + +if (parserState.userQuery[parserState.pos] === "[") { + endChar = "]"; + name = "[]"; + friendlyName = "slice"; +} parserState.pos += 1; - getItemsBefore(query, parserState, generics, "]"); + const { foundSeparator } = getItemsBefore(query, parserState, generics, endChar); const typeFilter = parserState.typeFilter; const isInBinding = parserState.isInBinding; if (typeFilter !== null && typeFilter !== "primitive") { throw [ "Invalid search type: primitive ", - "[]", + name, " and ", typeFilter, " both specified", @@ -677,27 +695,31 @@ function initSearch(rawSearchIndex) { } parserState.typeFilter = null; parserState.isInBinding = null; - parserState.totalElems += 1; - if (isInGenerics) { - parserState.genericsElems += 1; - } for (const gen of generics) { if (gen.bindingName !== null) { - throw ["Type parameter ", "=", " cannot be within slice ", "[]"]; + throw ["Type parameter ", "=", ` cannot be within ${friendlyName} `, name]; } } - elems.push({ - name: "[]", - id: null, - fullPath: ["[]"], - pathWithoutLast: [], - pathLast: "[]", - normalizedPathLast: "[]", - generics, - typeFilter: "primitive", - bindingName: isInBinding, - bindings: new Map(), - }); + if (name === "()" && !foundSeparator && generics.length === 1 && typeFilter === null) { + elems.push(generics[0]); + } else { + parserState.totalElems += 1; + if (isInGenerics) { + parserState.genericsElems += 1; + } + elems.push({ + name: name, + id: null, + fullPath: [name], + pathWithoutLast: [], + pathLast: name, + normalizedPathLast: name, + generics, + bindings: new Map(), + typeFilter: "primitive", + bindingName: isInBinding, + }); + } } else { const isStringElem = parserState.userQuery[start] === "\""; // We handle the strings on their own mostly to make code easier to follow. @@ -770,9 +792,11 @@ function initSearch(rawSearchIndex) { * @param {Array} elems - This is where the new {QueryElement} will be added. * @param {string} endChar - This function will stop when it'll encounter this * character. + * @returns {{foundSeparator: bool}} */ function getItemsBefore(query, parserState, elems, endChar) { let foundStopChar = true; + let foundSeparator = false; let start = parserState.pos; // If this is a generic, keep the outer item's type filter around. @@ -786,6 +810,8 @@ function initSearch(rawSearchIndex) { extra = "<"; } else if (endChar === "]") { extra = "["; + } else if (endChar === ")") { + extra = "("; } else if (endChar === "") { extra = "->"; } else { @@ -802,6 +828,7 @@ function initSearch(rawSearchIndex) { } else if (isSeparatorCharacter(c)) { parserState.pos += 1; foundStopChar = true; + foundSeparator = true; continue; } else if (c === ":" && isPathStart(parserState)) { throw ["Unexpected ", "::", ": paths cannot start with ", "::"]; @@ -879,6 +906,8 @@ function initSearch(rawSearchIndex) { parserState.typeFilter = oldTypeFilter; parserState.isInBinding = oldIsInBinding; + + return { foundSeparator }; } /** @@ -926,6 +955,8 @@ function initSearch(rawSearchIndex) { break; } throw ["Unexpected ", c, " (did you mean ", "->", "?)"]; + } else if (parserState.pos > 0) { + throw ["Unexpected ", c, " after ", parserState.userQuery[parserState.pos - 1]]; } throw ["Unexpected ", c]; } else if (c === ":" && !isPathStart(parserState)) { @@ -1599,6 +1630,11 @@ function initSearch(rawSearchIndex) { ) { // [] matches primitive:array or primitive:slice // if it matches, then we're fine, and this is an appropriate match candidate + } else if (queryElem.id === typeNameIdOfTupleOrUnit && + (fnType.id === typeNameIdOfTuple || fnType.id === typeNameIdOfUnit) + ) { + // () matches primitive:tuple or primitive:unit + // if it matches, then we're fine, and this is an appropriate match candidate } else if (fnType.id !== queryElem.id || queryElem.id === null) { return false; } @@ -1792,7 +1828,7 @@ function initSearch(rawSearchIndex) { if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 && typePassesFilter(elem.typeFilter, row.ty) && elem.generics.length === 0 && // special case - elem.id !== typeNameIdOfArrayOrSlice + elem.id !== typeNameIdOfArrayOrSlice && elem.id !== typeNameIdOfTupleOrUnit ) { return row.id === elem.id || checkIfInList( row.generics, @@ -2681,9 +2717,33 @@ ${item.displayPath}${name}\ * @return {Array} */ function buildItemSearchTypeAll(types, lowercasePaths) { - return types.map(type => buildItemSearchType(type, lowercasePaths)); + return types.length > 0 ? + types.map(type => buildItemSearchType(type, lowercasePaths)) : + EMPTY_GENERICS_ARRAY; } + /** + * Empty, immutable map used in item search types with no bindings. + * + * @type {Map>} + */ + const EMPTY_BINDINGS_MAP = new Map(); + + /** + * Empty, immutable map used in item search types with no bindings. + * + * @type {Array} + */ + const EMPTY_GENERICS_ARRAY = []; + + /** + * Object pool for function types with no bindings or generics. + * This is reset after loading the index. + * + * @type {Map} + */ + let TYPES_POOL = new Map(); + /** * Converts a single type. * @@ -2696,15 +2756,15 @@ ${item.displayPath}${name}\ let pathIndex, generics, bindings; if (typeof type === "number") { pathIndex = type; - generics = []; - bindings = new Map(); + generics = EMPTY_GENERICS_ARRAY; + bindings = EMPTY_BINDINGS_MAP; } else { pathIndex = type[PATH_INDEX_DATA]; generics = buildItemSearchTypeAll( type[GENERICS_DATA], lowercasePaths ); - if (type.length > BINDINGS_DATA) { + if (type.length > BINDINGS_DATA && type[BINDINGS_DATA].length > 0) { bindings = new Map(type[BINDINGS_DATA].map(binding => { const [assocType, constraints] = binding; // Associated type constructors are represented sloppily in rustdoc's @@ -2723,38 +2783,83 @@ ${item.displayPath}${name}\ ]; })); } else { - bindings = new Map(); + bindings = EMPTY_BINDINGS_MAP; } } + /** + * @type {FunctionType} + */ + let result; if (pathIndex < 0) { // types less than 0 are generic parameters // the actual names of generic parameters aren't stored, since they aren't API - return { + result = { id: pathIndex, ty: TY_GENERIC, path: null, generics, bindings, }; - } - if (pathIndex === 0) { + } else if (pathIndex === 0) { // `0` is used as a sentinel because it's fewer bytes than `null` - return { + result = { id: null, ty: null, path: null, generics, bindings, }; + } else { + const item = lowercasePaths[pathIndex - 1]; + result = { + id: buildTypeMapIndex(item.name, isAssocType), + ty: item.ty, + path: item.path, + generics, + bindings, + }; } - const item = lowercasePaths[pathIndex - 1]; - return { - id: buildTypeMapIndex(item.name, isAssocType), - ty: item.ty, - path: item.path, - generics, - bindings, - }; + const cr = TYPES_POOL.get(result.id); + if (cr) { + // Shallow equality check. Since this function is used + // to construct every type object, this should be mostly + // equivalent to a deep equality check, except if there's + // a conflict, we don't keep the old one around, so it's + // not a fully precise implementation of hashcons. + if (cr.generics.length === result.generics.length && + cr.generics !== result.generics && + cr.generics.every((x, i) => result.generics[i] === x) + ) { + result.generics = cr.generics; + } + if (cr.bindings.size === result.bindings.size && cr.bindings !== result.bindings) { + let ok = true; + for (const [k, v] of cr.bindings.entries()) { + const v2 = result.bindings.get(v); + if (!v2) { + ok = false; + break; + } + if (v !== v2 && v.length === v2.length && v.every((x, i) => v2[i] === x)) { + result.bindings.set(k, v); + } else if (v !== v2) { + ok = false; + break; + } + } + if (ok) { + result.bindings = cr.bindings; + } + } + if (cr.ty === result.ty && cr.path === result.path + && cr.bindings === result.bindings && cr.generics === result.generics + && cr.ty === result.ty + ) { + return cr; + } + } + TYPES_POOL.set(result.id, result); + return result; } /** @@ -2765,21 +2870,67 @@ ${item.displayPath}${name}\ * object-based encoding so that the actual search code is more readable and easier to debug. * * The raw function search type format is generated using serde in - * librustdoc/html/render/mod.rs: impl Serialize for IndexItemFunctionType + * librustdoc/html/render/mod.rs: IndexItemFunctionType::write_to_string * - * @param {RawFunctionSearchType} functionSearchType + * @param {{ + * string: string, + * offset: number, + * backrefQueue: FunctionSearchType[] + * }} itemFunctionDecoder * @param {Array<{name: string, ty: number}>} lowercasePaths * @param {Map} * * @return {null|FunctionSearchType} */ - function buildFunctionSearchType(functionSearchType, lowercasePaths) { - const INPUTS_DATA = 0; - const OUTPUT_DATA = 1; - // `0` is used as a sentinel because it's fewer bytes than `null` - if (functionSearchType === 0) { + function buildFunctionSearchType(itemFunctionDecoder, lowercasePaths) { + const c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset); + itemFunctionDecoder.offset += 1; + const [zero, ua, la, ob, cb] = ["0", "@", "`", "{", "}"].map(c => c.charCodeAt(0)); + // `` ` `` is used as a sentinel because it's fewer bytes than `null`, and decodes to zero + // `0` is a backref + if (c === la) { return null; } + // sixteen characters after "0" are backref + if (c >= zero && c < ua) { + return itemFunctionDecoder.backrefQueue[c - zero]; + } + if (c !== ob) { + throw ["Unexpected ", c, " in function: expected ", "{", "; this is a bug"]; + } + // call after consuming `{` + function decodeList() { + let c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset); + const ret = []; + while (c !== cb) { + ret.push(decode()); + c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset); + } + itemFunctionDecoder.offset += 1; // eat cb + return ret; + } + // consumes and returns a list or integer + function decode() { + let n = 0; + let c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset); + if (c === ob) { + itemFunctionDecoder.offset += 1; + return decodeList(); + } + while (c < la) { + n = (n << 4) | (c & 0xF); + itemFunctionDecoder.offset += 1; + c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset); + } + // last character >= la + n = (n << 4) | (c & 0xF); + const [sign, value] = [n & 1, n >> 1]; + itemFunctionDecoder.offset += 1; + return sign ? -value : value; + } + const functionSearchType = decodeList(); + const INPUTS_DATA = 0; + const OUTPUT_DATA = 1; let inputs, output; if (typeof functionSearchType[INPUTS_DATA] === "number") { inputs = [buildItemSearchType(functionSearchType[INPUTS_DATA], lowercasePaths)]; @@ -2808,9 +2959,14 @@ ${item.displayPath}${name}\ ? [buildItemSearchType(functionSearchType[i], lowercasePaths)] : buildItemSearchTypeAll(functionSearchType[i], lowercasePaths)); } - return { + const ret = { inputs, output, where_clause, }; + itemFunctionDecoder.backrefQueue.unshift(ret); + if (itemFunctionDecoder.backrefQueue.length > 16) { + itemFunctionDecoder.backrefQueue.pop(); + } + return ret; } /** @@ -2835,12 +2991,15 @@ ${item.displayPath}${name}\ */ function buildFunctionTypeFingerprint(type, output, fps) { let input = type.id; - // All forms of `[]` get collapsed down to one thing in the bloom filter. + // All forms of `[]`/`()` get collapsed down to one thing in the bloom filter. // Differentiating between arrays and slices, if the user asks for it, is // still done in the matching algorithm. if (input === typeNameIdOfArray || input === typeNameIdOfSlice) { input = typeNameIdOfArrayOrSlice; } + if (input === typeNameIdOfTuple || input === typeNameIdOfUnit) { + input = typeNameIdOfTupleOrUnit; + } // http://burtleburtle.net/bob/hash/integer.html // ~~ is toInt32. It's used before adding, so // the number stays in safe integer range. @@ -2880,8 +3039,8 @@ ${item.displayPath}${name}\ const fb = { id: null, ty: 0, - generics: [], - bindings: new Map(), + generics: EMPTY_GENERICS_ARRAY, + bindings: EMPTY_BINDINGS_MAP, }; for (const [k, v] of type.bindings.entries()) { fb.id = k; @@ -2924,6 +3083,11 @@ ${item.displayPath}${name}\ return functionTypeFingerprint[(fullId * 4) + 3]; } + /** + * Convert raw search index into in-memory search index. + * + * @param {[string, RawSearchIndexCrate][]} rawSearchIndex + */ function buildIndex(rawSearchIndex) { searchIndex = []; typeNameIdMap = new Map(); @@ -2935,7 +3099,10 @@ ${item.displayPath}${name}\ // that can be searched using `[]` syntax. typeNameIdOfArray = buildTypeMapIndex("array"); typeNameIdOfSlice = buildTypeMapIndex("slice"); + typeNameIdOfTuple = buildTypeMapIndex("tuple"); + typeNameIdOfUnit = buildTypeMapIndex("unit"); typeNameIdOfArrayOrSlice = buildTypeMapIndex("[]"); + typeNameIdOfTupleOrUnit = buildTypeMapIndex("()"); // Function type fingerprints are 128-bit bloom filters that are used to // estimate the distance between function and query. @@ -2950,59 +3117,7 @@ ${item.displayPath}${name}\ // This loop actually generates the search item indexes, including // normalized names, type signature objects and fingerprints, and aliases. id = 0; - /** - * The raw search data for a given crate. `n`, `t`, `d`, `i`, and `f` - * are arrays with the same length. `q`, `a`, and `c` use a sparse - * representation for compactness. - * - * `n[i]` contains the name of an item. - * - * `t[i]` contains the type of that item - * (as a string of characters that represent an offset in `itemTypes`). - * - * `d[i]` contains the description of that item. - * - * `q` contains the full paths of the items. For compactness, it is a set of - * (index, path) pairs used to create a map. If a given index `i` is - * not present, this indicates "same as the last index present". - * - * `i[i]` contains an item's parent, usually a module. For compactness, - * it is a set of indexes into the `p` array. - * - * `f[i]` contains function signatures, or `0` if the item isn't a function. - * Functions are themselves encoded as arrays. The first item is a list of - * types representing the function's inputs, and the second list item is a list - * of types representing the function's output. Tuples are flattened. - * Types are also represented as arrays; the first item is an index into the `p` - * array, while the second is a list of types representing any generic parameters. - * - * b[i] contains an item's impl disambiguator. This is only present if an item - * is defined in an impl block and, the impl block's type has more than one associated - * item with the same name. - * - * `a` defines aliases with an Array of pairs: [name, offset], where `offset` - * points into the n/t/d/q/i/f arrays. - * - * `doc` contains the description of the crate. - * - * `p` is a list of path/type pairs. It is used for parents and function parameters. - * - * `c` is an array of item indices that are deprecated. - * - * @type {{ - * doc: string, - * a: Object, - * n: Array, - * t: String, - * d: Array, - * q: Array<[Number, string]>, - * i: Array, - * f: Array, - * p: Array, - * b: Array<[Number, String]>, - * c: Array - * }} - */ + for (const [crate, crateCorpus] of rawSearchIndex) { // This object should have exactly the same set of fields as the "row" // object defined below. Your JavaScript runtime will thank you. @@ -3039,8 +3154,12 @@ ${item.displayPath}${name}\ const itemDescs = crateCorpus.d; // an array of (Number) the parent path index + 1 to `paths`, or 0 if none const itemParentIdxs = crateCorpus.i; - // an array of (Object | null) the type of the function, if any - const itemFunctionSearchTypes = crateCorpus.f; + // a string representing the list of function types + const itemFunctionDecoder = { + string: crateCorpus.f, + offset: 0, + backrefQueue: [], + }; // an array of (Number) indices for the deprecated items const deprecatedItems = new Set(crateCorpus.c); // an array of (Number) indices for the deprecated items @@ -3088,12 +3207,8 @@ ${item.displayPath}${name}\ word = itemNames[i].toLowerCase(); } const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath; - let type = null; - if (itemFunctionSearchTypes[i] !== 0) { - type = buildFunctionSearchType( - itemFunctionSearchTypes[i], - lowercasePaths - ); + const type = buildFunctionSearchType(itemFunctionDecoder, lowercasePaths); + if (type !== null) { if (type) { const fp = functionTypeFingerprint.subarray(id * 4, (id + 1) * 4); const fps = new Set(); @@ -3153,6 +3268,8 @@ ${item.displayPath}${name}\ } currentIndex += itemTypes.length; } + // Drop the (rather large) hash table used for reusing function items + TYPES_POOL = new Map(); } /** diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 506eb56fdc8f..176494a38634 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1228,7 +1228,7 @@ impl LinkCollector<'_, '_> { span, "linking to associated items of raw pointers is experimental", ) - .note("rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does") + .note_mv("rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does") .emit(); } diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 53c7f0f6e15d..782938f10943 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -8,7 +8,7 @@ use rustc_errors::{ use rustc_parse::parse_stream_from_source_str; use rustc_resolve::rustdoc::source_span_for_markdown_range; use rustc_session::parse::ParseSess; -use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId}; +use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, Transparency}; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{FileName, InnerSpan, DUMMY_SP}; @@ -50,7 +50,7 @@ fn check_rust_syntax( let expn_data = ExpnData::default(ExpnKind::AstPass(AstPass::TestHarness), DUMMY_SP, edition, None, None); let expn_id = cx.tcx.with_stable_hashing_context(|hcx| LocalExpnId::fresh(expn_data, hcx)); - let span = DUMMY_SP.fresh_expansion(expn_id); + let span = DUMMY_SP.apply_mark(expn_id.to_expn_id(), Transparency::Transparent); let is_empty = rustc_driver::catch_fatal_errors(|| { parse_stream_from_source_str( diff --git a/src/tools/cargo b/src/tools/cargo index add15366eaf3..3e428a38a34e 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit add15366eaf3f3eb84717d3b8b71902ca36a7c84 +Subproject commit 3e428a38a34e820a461d2cc082e726d3bda71bcb diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs index 471ad73e2074..76f3663f04f2 100644 --- a/src/tools/clippy/clippy_config/src/msrvs.rs +++ b/src/tools/clippy/clippy_config/src/msrvs.rs @@ -109,7 +109,7 @@ impl Msrv { if let Some(duplicate) = msrv_attrs.last() { sess.dcx() .struct_span_err(duplicate.span, "`clippy::msrv` is defined multiple times") - .span_note(msrv_attr.span, "first definition found here") + .span_note_mv(msrv_attr.span, "first definition found here") .emit(); } diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index 849920bb76d5..3761ba81f521 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -145,7 +145,7 @@ pub(super) fn check<'tcx>( if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) { if let Some(id) = path_to_local(cast_expr) && let Some(span) = cx.tcx.hir().opt_span(id) - && span.ctxt() != cast_expr.span.ctxt() + && !span.eq_ctxt(cast_expr.span) { // Binding context is different than the identifiers context. // Weird macro wizardry could be involved here. diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index d91af76f5e0d..bd07c19a2d81 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -12,7 +12,6 @@ use rustc_errors::Applicability; use rustc_hir::def_id::DefIdSet; use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::query::Key; use rustc_session::impl_lint_pass; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; @@ -574,7 +573,7 @@ fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignore let caller_ty = cx.typeck_results().expr_ty(caller_expr); // Check if given type has inner mutability and was not set to ignored by the configuration let is_inner_mut_ty = is_interior_mut_ty(cx, caller_ty) - && !matches!(caller_ty.ty_adt_id(), Some(adt_id) if ignored_ty_ids.contains(&adt_id)); + && !matches!(caller_ty.ty_adt_def(), Some(adt) if ignored_ty_ids.contains(&adt.did())); is_inner_mut_ty || caller_ty.is_mutable_ptr() diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index 43eb6a9b8386..788fe8287278 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -118,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { vis.visit_ty(impl_.self_ty); for target in &vis.found { - if item.span.ctxt() != target.span().ctxt() { + if !item.span.eq_ctxt(target.span()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index d68c5c4bac68..5288efd8df8c 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -225,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn { _: LocalDefId, ) { if (!matches!(kind, FnKind::Closure) && matches!(decl.output, FnRetTy::DefaultReturn(_))) - || span.ctxt() != body.value.span.ctxt() + || !span.eq_ctxt(body.value.span) || in_external_macro(cx.sess(), span) { return; diff --git a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs index 6a82d8f756ad..3a8ca37610a9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs @@ -6,7 +6,6 @@ use clippy_utils::ty::is_type_lang_item; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath}; use rustc_lint::LateContext; -use rustc_middle::query::Key; use rustc_middle::ty; use rustc_middle::ty::Ty; use rustc_span::{sym, Symbol}; @@ -18,10 +17,10 @@ use rustc_span::{sym, Symbol}; /// `vec![1,2].drain(..).collect::>()` /// ^^^^^^^^^ ^^^^^^^^^^ false fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>, sym: Symbol) -> bool { - if let Some(expr_adt_did) = expr.ty_adt_id() - && let Some(recv_adt_did) = recv.ty_adt_id() + if let Some(expr_adt) = expr.ty_adt_def() + && let Some(recv_adt) = recv.ty_adt_def() { - cx.tcx.is_diagnostic_item(sym, expr_adt_did) && cx.tcx.is_diagnostic_item(sym, recv_adt_did) + cx.tcx.is_diagnostic_item(sym, expr_adt.did()) && cx.tcx.is_diagnostic_item(sym, recv_adt.did()) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs index 63e64a5b35d0..47c9438c588f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -67,7 +67,7 @@ pub(super) fn check<'tcx>( } } - if unwrap_arg.span.ctxt() != map_span.ctxt() { + if !unwrap_arg.span.eq_ctxt(map_span) { return; } diff --git a/src/tools/clippy/clippy_lints/src/methods/redundant_as_str.rs b/src/tools/clippy/clippy_lints/src/methods/redundant_as_str.rs index 98cd6afc2b79..2a2feedd2b49 100644 --- a/src/tools/clippy/clippy_lints/src/methods/redundant_as_str.rs +++ b/src/tools/clippy/clippy_lints/src/methods/redundant_as_str.rs @@ -4,7 +4,6 @@ use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::query::Key; use rustc_span::Span; pub(super) fn check( @@ -14,11 +13,7 @@ pub(super) fn check( as_str_span: Span, other_method_span: Span, ) { - if cx - .tcx - .lang_items() - .string() - .is_some_and(|id| Some(id) == cx.typeck_results().expr_ty(recv).ty_adt_id()) + if cx.typeck_results().expr_ty(recv).ty_adt_def().is_some_and(|adt| Some(adt.did()) == cx.tcx.lang_items().string()) { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 04d2ced6abf8..c32025fcbb6a 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -4,7 +4,6 @@ use clippy_utils::{def_path_def_ids, trait_ref_of_method}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::query::Key; use rustc_middle::ty::{Adt, Ty}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; @@ -166,7 +165,7 @@ impl MutableKeyType { // Determines if a type contains interior mutability which would affect its implementation of // [`Hash`] or [`Ord`]. if is_interior_mut_ty(cx, subst_ty) - && !matches!(subst_ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id)) + && !matches!(subst_ty.ty_adt_def(), Some(adt) if self.ignore_mut_def_ids.contains(&adt.did())) { span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type"); } diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 4013cb34561a..f8365deebd46 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -15,7 +15,6 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; -use rustc_middle::query::Key; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; @@ -188,7 +187,7 @@ impl NonCopyConst { } fn is_ty_ignored(&self, ty: Ty<'_>) -> bool { - matches!(ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id)) + matches!(ty.ty_adt_def(), Some(adt) if self.ignore_mut_def_ids.contains(&adt.did())) } fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index c0d0d2b93dc0..5df645491ff8 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -4,7 +4,6 @@ use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::query::Key; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::sym; @@ -17,10 +16,10 @@ pub(super) fn check<'tcx>( to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, ) -> bool { - let (ty::Int(_) | ty::Uint(_), Some(to_ty_id)) = (&from_ty.kind(), to_ty.ty_adt_id()) else { + let (ty::Int(_) | ty::Uint(_), Some(to_ty_adt)) = (&from_ty.kind(), to_ty.ty_adt_def()) else { return false; }; - let Some(to_type_sym) = cx.tcx.get_diagnostic_name(to_ty_id) else { + let Some(to_type_sym) = cx.tcx.get_diagnostic_name(to_ty_adt.did()) else { return false; }; diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index db80e07ca1c4..19d38903ade2 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -136,7 +136,7 @@ pub fn get_unique_attr<'a>( if let Some(duplicate) = unique_attr { sess.dcx() .struct_span_err(attr.span, format!("`{name}` is defined multiple times")) - .span_note(duplicate.span, "first definition found here") + .span_note_mv(duplicate.span, "first definition found here") .emit(); } else { unique_attr = Some(attr); diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 4cf5a710586c..49f1226e2cc3 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -483,6 +483,7 @@ impl TargetCfgs { let mut targets: HashMap = serde_json::from_str(&rustc_output( config, &["--print=all-target-specs-json", "-Zunstable-options"], + Default::default(), )) .unwrap(); @@ -495,16 +496,33 @@ impl TargetCfgs { let mut all_families = HashSet::new(); let mut all_pointer_widths = HashSet::new(); - // Handle custom target specs, which are not included in `--print=all-target-specs-json`. - if config.target.ends_with(".json") { - targets.insert( - config.target.clone(), - serde_json::from_str(&rustc_output( - config, - &["--print=target-spec-json", "-Zunstable-options", "--target", &config.target], - )) - .unwrap(), - ); + // If current target is not included in the `--print=all-target-specs-json` output, + // we check whether it is a custom target from the user or a synthetic target from bootstrap. + if !targets.contains_key(&config.target) { + let mut envs: HashMap = HashMap::new(); + + if let Ok(t) = std::env::var("RUST_TARGET_PATH") { + envs.insert("RUST_TARGET_PATH".into(), t); + } + + // This returns false only when the target is neither a synthetic target + // nor a custom target from the user, indicating it is most likely invalid. + if config.target.ends_with(".json") || !envs.is_empty() { + targets.insert( + config.target.clone(), + serde_json::from_str(&rustc_output( + config, + &[ + "--print=target-spec-json", + "-Zunstable-options", + "--target", + &config.target, + ], + envs, + )) + .unwrap(), + ); + } } for (target, cfg) in targets.iter() { @@ -549,7 +567,9 @@ impl TargetCfgs { // code below extracts them from `--print=cfg`: make sure to only override fields that can // actually be changed with `-C` flags. for config in - rustc_output(config, &["--print=cfg", "--target", &config.target]).trim().lines() + rustc_output(config, &["--print=cfg", "--target", &config.target], Default::default()) + .trim() + .lines() { let (name, value) = config .split_once("=\"") @@ -628,11 +648,12 @@ pub enum Endian { Big, } -fn rustc_output(config: &Config, args: &[&str]) -> String { +fn rustc_output(config: &Config, args: &[&str], envs: HashMap) -> String { let mut command = Command::new(&config.rustc_path); add_dylib_path(&mut command, iter::once(&config.compile_lib_path)); command.args(&config.target_rustcflags).args(args); command.env("RUSTC_BOOTSTRAP", "1"); + command.envs(envs); let output = match command.output() { Ok(output) => output, diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index b258b748ca87..8be4def15ded 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -19,7 +19,6 @@ use miropt_test_tools::{files_for_miropt_test, MiroptTest, MiroptTestFile}; use regex::{Captures, Regex}; use rustfix::{apply_suggestions, get_suggestions_from_json, Filter}; -use std::borrow::Cow; use std::collections::{HashMap, HashSet}; use std::env; use std::ffi::{OsStr, OsString}; @@ -725,7 +724,7 @@ impl<'test> TestCx<'test> { /// Replace line numbers in coverage reports with the placeholder `LL`, /// so that the tests are less sensitive to lines being added/removed. - fn anonymize_coverage_line_numbers(coverage: &str) -> Cow<'_, str> { + fn anonymize_coverage_line_numbers(coverage: &str) -> String { // The coverage reporter prints line numbers at the start of a line. // They are truncated or left-padded to occupy exactly 5 columns. // (`LineNumberColumnWidth` in `SourceCoverageViewText.cpp`.) @@ -733,9 +732,28 @@ impl<'test> TestCx<'test> { // // Line numbers that appear inside expansion/instantiation subviews // have an additional prefix of ` |` for each nesting level. + // + // Branch views also include the relevant line number, so we want to + // redact those too. (These line numbers don't have padding.) + // + // Note: The pattern `(?m:^)` matches the start of a line. + + // ` 1|` => ` LL|` + // ` 10|` => ` LL|` + // ` 100|` => ` LL|` + // ` | 1000|` => ` | LL|` + // ` | | 1000|` => ` | | LL|` static LINE_NUMBER_RE: Lazy = Lazy::new(|| Regex::new(r"(?m:^)(?(?: \|)*) *[0-9]+\|").unwrap()); - LINE_NUMBER_RE.replace_all(coverage, "$prefix LL|") + let coverage = LINE_NUMBER_RE.replace_all(&coverage, "${prefix} LL|"); + + // ` | Branch (1:` => ` | Branch (LL:` + // ` | | Branch (10:` => ` | | Branch (LL:` + static BRANCH_LINE_NUMBER_RE: Lazy = + Lazy::new(|| Regex::new(r"(?m:^)(?(?: \|)+ Branch \()[0-9]+:").unwrap()); + let coverage = BRANCH_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:"); + + coverage.into_owned() } /// Coverage reports can describe multiple source files, separated by diff --git a/src/tools/compiletest/src/runtest/tests.rs b/src/tools/compiletest/src/runtest/tests.rs index fb3dd326a4c8..ee42243e83d8 100644 --- a/src/tools/compiletest/src/runtest/tests.rs +++ b/src/tools/compiletest/src/runtest/tests.rs @@ -48,3 +48,75 @@ fn normalize_platform_differences() { r#"println!("test\ntest")"#, ); } + +/// Test for anonymizing line numbers in coverage reports, especially for +/// branch regions. +/// +/// FIXME(#119681): This test can be removed when we have examples of branch +/// coverage in the actual coverage test suite. +#[test] +fn anonymize_coverage_line_numbers() { + let anon = |coverage| TestCx::anonymize_coverage_line_numbers(coverage); + + let input = r#" + 6| 3|fn print_size() { + 7| 3| if std::mem::size_of::() > 4 { + ------------------ + | Branch (7:8): [True: 0, False: 1] + | Branch (7:8): [True: 0, False: 1] + | Branch (7:8): [True: 1, False: 0] + ------------------ + 8| 1| println!("size > 4"); +"#; + + let expected = r#" + LL| 3|fn print_size() { + LL| 3| if std::mem::size_of::() > 4 { + ------------------ + | Branch (LL:8): [True: 0, False: 1] + | Branch (LL:8): [True: 0, False: 1] + | Branch (LL:8): [True: 1, False: 0] + ------------------ + LL| 1| println!("size > 4"); +"#; + + assert_eq!(anon(input), expected); + + ////////// + + let input = r#" + 12| 3|} + ------------------ + | branch_generics::print_size::<()>: + | 6| 1|fn print_size() { + | 7| 1| if std::mem::size_of::() > 4 { + | ------------------ + | | Branch (7:8): [True: 0, False: 1] + | ------------------ + | 8| 0| println!("size > 4"); + | 9| 1| } else { + | 10| 1| println!("size <= 4"); + | 11| 1| } + | 12| 1|} + ------------------ +"#; + + let expected = r#" + LL| 3|} + ------------------ + | branch_generics::print_size::<()>: + | LL| 1|fn print_size() { + | LL| 1| if std::mem::size_of::() > 4 { + | ------------------ + | | Branch (LL:8): [True: 0, False: 1] + | ------------------ + | LL| 0| println!("size > 4"); + | LL| 1| } else { + | LL| 1| println!("size <= 4"); + | LL| 1| } + | LL| 1|} + ------------------ +"#; + + assert_eq!(anon(input), expected); +} diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 5be8ef7996bb..c5cd30ccc343 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -15,6 +15,7 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ ("future-incompatible", "Lints that detect code that has future-compatibility problems"), ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"), ("rust-2021-compatibility", "Lints used to transition code from the 2018 edition to 2021"), + ("rust-2024-compatibility", "Lints used to transition code from the 2021 edition to 2024"), ]; type LintGroups = BTreeMap>; diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 548e12ffdeaf..bdf2416a20e6 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -5bcd86d89b2b7b6a490f7e075dd4eb346deb5f98 +94807670a6a3834cc9b71b0b803d49d307c9ba5d diff --git a/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs b/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs index d5e6d37226ab..762a8d85314f 100644 --- a/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs +++ b/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs @@ -1,6 +1,8 @@ //! Ensure that thread-local statics get deallocated when the thread dies. #![feature(thread_local)] +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#![allow(static_mut_ref)] #[thread_local] static mut TLS: u8 = 0; diff --git a/src/tools/miri/tests/pass/static_mut.rs b/src/tools/miri/tests/pass/static_mut.rs index 218b02525bd5..c1e58b70adb0 100644 --- a/src/tools/miri/tests/pass/static_mut.rs +++ b/src/tools/miri/tests/pass/static_mut.rs @@ -1,4 +1,7 @@ static mut FOO: i32 = 42; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static BAR: Foo = Foo(unsafe { &FOO as *const _ }); #[allow(dead_code)] diff --git a/src/tools/miri/tests/pass/tls/tls_static.rs b/src/tools/miri/tests/pass/tls/tls_static.rs index fc4c8a283ddb..9be00af47aa3 100644 --- a/src/tools/miri/tests/pass/tls/tls_static.rs +++ b/src/tools/miri/tests/pass/tls/tls_static.rs @@ -8,6 +8,8 @@ //! test, we also check that thread-locals act as per-thread statics. #![feature(thread_local)] +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#![allow(static_mut_ref)] use std::thread; diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index c7d110eafb66..6670e92f51bc 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -569,6 +569,7 @@ dependencies = [ "expect-test", "hir-def", "hir-expand", + "indexmap", "intern", "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 7054020086ea..4ee8064b5e34 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -1,6 +1,6 @@ [workspace] members = ["xtask/", "lib/*", "crates/*"] -exclude = ["crates/proc-macro-srv/proc-macro-test/"] +exclude = ["crates/proc-macro-srv/proc-macro-test/imp"] resolver = "2" [workspace.package] @@ -138,4 +138,4 @@ dashmap = { version = "=5.5.3", features = ["raw-api"] } collapsible_if = "allow" needless_pass_by_value = "allow" nonminimal_bool = "allow" -redundant_pattern_matching = "allow" \ No newline at end of file +redundant_pattern_matching = "allow" diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index a45ec844aba0..c728570d9866 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -17,7 +17,7 @@ use smallvec::SmallVec; use syntax::{ ast::{ self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasLoopBody, HasName, - SlicePatComponents, + RangeItem, SlicePatComponents, }, AstNode, AstPtr, SyntaxNodePtr, }; @@ -622,7 +622,8 @@ impl ExprCollector<'_> { ast::Expr::IndexExpr(e) => { let base = self.collect_expr_opt(e.base()); let index = self.collect_expr_opt(e.index()); - self.alloc_expr(Expr::Index { base, index }, syntax_ptr) + let is_assignee_expr = self.is_lowering_assignee_expr; + self.alloc_expr(Expr::Index { base, index, is_assignee_expr }, syntax_ptr) } ast::Expr::RangeExpr(e) => { let lhs = e.start().map(|lhs| self.collect_expr(lhs)); @@ -1609,7 +1610,7 @@ impl ExprCollector<'_> { |name| self.alloc_expr_desugared(Expr::Path(Path::from(name))), |name, span| { if let Some(span) = span { - mappings.push((span, name.clone())) + mappings.push((span, name)) } }, ), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs index 6ecf1c20d6c1..02b19ade44ba 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs @@ -376,7 +376,7 @@ impl Printer<'_> { w!(self, ") "); } } - Expr::Index { base, index } => { + Expr::Index { base, index, is_assignee_expr: _ } => { self.print_expr(*base); w!(self, "["); self.print_expr(*index); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs index b163112db918..a95b78614e82 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs @@ -128,7 +128,7 @@ fn parse_repr_tt(tt: &Subtree) -> Option { } else { 0 }; - let pack = Align::from_bytes(pack).unwrap(); + let pack = Align::from_bytes(pack).unwrap_or(Align::ONE); min_pack = Some(if let Some(min_pack) = min_pack { min_pack.min(pack) } else { pack }); ReprFlags::empty() diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index 591ee77c70a4..5890e818c46f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -265,6 +265,7 @@ pub enum Expr { Index { base: ExprId, index: ExprId, + is_assignee_expr: bool, }, Closure { args: Box<[PatId]>, @@ -432,7 +433,7 @@ impl Expr { f(rhs); } } - Expr::Index { base, index } => { + Expr::Index { base, index, .. } => { f(*base); f(*index); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs index aea7229bd648..989bbc7bfb2d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs @@ -3,13 +3,13 @@ use std::{fmt, hash::BuildHasherDefault}; use base_db::CrateId; -use fst::{self, raw::IndexedValue, Streamer}; +use fst::{self, raw::IndexedValue, Automaton, Streamer}; use hir_expand::name::Name; use indexmap::IndexMap; use itertools::Itertools; use rustc_hash::{FxHashSet, FxHasher}; use smallvec::SmallVec; -use stdx::format_to; +use stdx::{format_to, TupleExt}; use triomphe::Arc; use crate::{ @@ -20,12 +20,10 @@ use crate::{ AssocItemId, ModuleDefId, ModuleId, TraitId, }; -type FxIndexMap = IndexMap>; - /// Item import details stored in the `ImportMap`. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct ImportInfo { - /// A name that can be used to import the item, relative to the crate's root. + /// A name that can be used to import the item, relative to the container. pub name: Name, /// The module containing this item. pub container: ModuleId, @@ -35,22 +33,22 @@ pub struct ImportInfo { pub is_unstable: bool, } -type ImportMapIndex = FxIndexMap, IsTraitAssocItem)>; - /// A map from publicly exported items to its name. /// -/// Reexports of items are taken into account, ie. if something is exported under multiple -/// names, the one with the shortest import path will be used. +/// Reexports of items are taken into account. #[derive(Default)] pub struct ImportMap { - map: ImportMapIndex, - /// List of keys stored in `map`, sorted lexicographically by their `ModPath`. Indexed by the - /// values returned by running `fst`. + /// Maps from `ItemInNs` to information of imports that bring the item into scope. + item_to_info_map: ImportMapIndex, + /// List of keys stored in [`Self::item_to_info_map`], sorted lexicographically by their + /// [`Name`]. Indexed by the values returned by running `fst`. /// - /// Since a name can refer to multiple items due to namespacing, we store all items with the - /// same name right after each other. This allows us to find all items after the FST gives us - /// the index of the first one. - importables: Vec, + /// Since a name can refer to multiple items due to namespacing and import aliases, we store all + /// items with the same name right after each other. This allows us to find all items after the + /// fst gives us the index of the first one. + /// + /// The [`u32`] is the index into the smallvec in the value of [`Self::item_to_info_map`]. + importables: Vec<(ItemInNs, u32)>, fst: fst::Map>, } @@ -60,10 +58,13 @@ enum IsTraitAssocItem { No, } +type FxIndexMap = IndexMap>; +type ImportMapIndex = FxIndexMap, IsTraitAssocItem)>; + impl ImportMap { pub fn dump(&self, db: &dyn DefDatabase) -> String { let mut out = String::new(); - for (k, v) in self.map.iter() { + for (k, v) in self.item_to_info_map.iter() { format_to!(out, "{:?} ({:?}) -> ", k, v.1); for v in &v.0 { format_to!(out, "{}:{:?}, ", v.name.display(db.upcast()), v.container); @@ -76,177 +77,191 @@ impl ImportMap { pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { let _p = profile::span("import_map_query"); - let map = collect_import_map(db, krate); + let map = Self::collect_import_map(db, krate); let mut importables: Vec<_> = map .iter() - // We've only collected items, whose name cannot be tuple field. - .flat_map(|(&item, (info, is_assoc))| { - info.iter().map(move |info| { - (item, *is_assoc, info.name.as_str().unwrap().to_ascii_lowercase()) - }) + // We've only collected items, whose name cannot be tuple field so unwrapping is fine. + .flat_map(|(&item, (info, _))| { + info.iter() + .enumerate() + .map(move |(idx, info)| (item, info.name.to_smol_str(), idx as u32)) }) .collect(); - importables.sort_by(|(_, l_is_assoc, lhs_name), (_, r_is_assoc, rhs_name)| { - lhs_name.cmp(rhs_name).then_with(|| l_is_assoc.cmp(r_is_assoc)) + importables.sort_by(|(_, l_info, _), (_, r_info, _)| { + let lhs_chars = l_info.chars().map(|c| c.to_ascii_lowercase()); + let rhs_chars = r_info.chars().map(|c| c.to_ascii_lowercase()); + lhs_chars.cmp(rhs_chars) }); importables.dedup(); // Build the FST, taking care not to insert duplicate values. let mut builder = fst::MapBuilder::memory(); - let iter = importables + let mut iter = importables .iter() .enumerate() - .dedup_by(|(_, (_, _, lhs)), (_, (_, _, rhs))| lhs == rhs); - for (start_idx, (_, _, name)) in iter { - let _ = builder.insert(name, start_idx as u64); + .dedup_by(|&(_, (_, lhs, _)), &(_, (_, rhs, _))| lhs.eq_ignore_ascii_case(rhs)); + + let mut insert = |name: &str, start, end| { + builder.insert(name.to_ascii_lowercase(), ((start as u64) << 32) | end as u64).unwrap() + }; + + if let Some((mut last, (_, name, _))) = iter.next() { + debug_assert_eq!(last, 0); + let mut last_name = name; + for (next, (_, next_name, _)) in iter { + insert(last_name, last, next); + last = next; + last_name = next_name; + } + insert(last_name, last, importables.len()); } - Arc::new(ImportMap { - map, - fst: builder.into_map(), - importables: importables.into_iter().map(|(item, _, _)| item).collect(), - }) + let importables = importables.into_iter().map(|(item, _, idx)| (item, idx)).collect(); + Arc::new(ImportMap { item_to_info_map: map, fst: builder.into_map(), importables }) } pub fn import_info_for(&self, item: ItemInNs) -> Option<&[ImportInfo]> { - self.map.get(&item).map(|(info, _)| &**info) + self.item_to_info_map.get(&item).map(|(info, _)| &**info) } -} -fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex { - let _p = profile::span("collect_import_map"); + fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex { + let _p = profile::span("collect_import_map"); - let def_map = db.crate_def_map(krate); - let mut map = FxIndexMap::default(); + let def_map = db.crate_def_map(krate); + let mut map = FxIndexMap::default(); - // We look only into modules that are public(ly reexported), starting with the crate root. - let root = def_map.module_id(DefMap::ROOT); - let mut worklist = vec![root]; - let mut visited = FxHashSet::default(); + // We look only into modules that are public(ly reexported), starting with the crate root. + let root = def_map.module_id(DefMap::ROOT); + let mut worklist = vec![root]; + let mut visited = FxHashSet::default(); - while let Some(module) = worklist.pop() { - if !visited.insert(module) { - continue; - } - let ext_def_map; - let mod_data = if module.krate == krate { - &def_map[module.local_id] - } else { - // The crate might reexport a module defined in another crate. - ext_def_map = module.def_map(db); - &ext_def_map[module.local_id] - }; - - let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| { - let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public); - if per_ns.is_none() { None } else { Some((name, per_ns)) } - }); - - for (name, per_ns) in visible_items { - for (item, import) in per_ns.iter_items() { - let attr_id = if let Some(import) = import { - match import { - ImportOrExternCrate::ExternCrate(id) => Some(id.into()), - ImportOrExternCrate::Import(id) => Some(id.import.into()), - } - } else { - match item { - ItemInNs::Types(id) | ItemInNs::Values(id) => id.try_into().ok(), - ItemInNs::Macros(id) => Some(id.into()), - } - }; - let (is_doc_hidden, is_unstable) = attr_id.map_or((false, false), |attr_id| { - let attrs = db.attrs(attr_id); - (attrs.has_doc_hidden(), attrs.is_unstable()) - }); - - let import_info = ImportInfo { - name: name.clone(), - container: module, - is_doc_hidden, - is_unstable, - }; - - if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() { - collect_trait_assoc_items( - db, - &mut map, - tr, - matches!(item, ItemInNs::Types(_)), - &import_info, - ); - } - - let (infos, _) = - map.entry(item).or_insert_with(|| (SmallVec::new(), IsTraitAssocItem::No)); - infos.reserve_exact(1); - infos.push(import_info); - - // If we've just added a module, descend into it. - if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { - worklist.push(mod_id); - } - } - } - } - map.shrink_to_fit(); - map -} - -fn collect_trait_assoc_items( - db: &dyn DefDatabase, - map: &mut ImportMapIndex, - tr: TraitId, - is_type_in_ns: bool, - trait_import_info: &ImportInfo, -) { - let _p = profile::span("collect_trait_assoc_items"); - for &(ref assoc_item_name, item) in &db.trait_data(tr).items { - let module_def_id = match item { - AssocItemId::FunctionId(f) => ModuleDefId::from(f), - AssocItemId::ConstId(c) => ModuleDefId::from(c), - // cannot use associated type aliases directly: need a `::TypeAlias` - // qualifier, ergo no need to store it for imports in import_map - AssocItemId::TypeAliasId(_) => { - cov_mark::hit!(type_aliases_ignored); + while let Some(module) = worklist.pop() { + if !visited.insert(module) { continue; } - }; - let assoc_item = if is_type_in_ns { - ItemInNs::Types(module_def_id) - } else { - ItemInNs::Values(module_def_id) - }; + let ext_def_map; + let mod_data = if module.krate == krate { + &def_map[module.local_id] + } else { + // The crate might reexport a module defined in another crate. + ext_def_map = module.def_map(db); + &ext_def_map[module.local_id] + }; - let attrs = &db.attrs(item.into()); - let assoc_item_info = ImportInfo { - container: trait_import_info.container, - name: assoc_item_name.clone(), - is_doc_hidden: attrs.has_doc_hidden(), - is_unstable: attrs.is_unstable(), - }; + let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| { + let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public); + if per_ns.is_none() { + None + } else { + Some((name, per_ns)) + } + }); - let (infos, _) = - map.entry(assoc_item).or_insert_with(|| (SmallVec::new(), IsTraitAssocItem::Yes)); - infos.reserve_exact(1); - infos.push(assoc_item_info); + for (name, per_ns) in visible_items { + for (item, import) in per_ns.iter_items() { + let attr_id = if let Some(import) = import { + match import { + ImportOrExternCrate::ExternCrate(id) => Some(id.into()), + ImportOrExternCrate::Import(id) => Some(id.import.into()), + } + } else { + match item { + ItemInNs::Types(id) | ItemInNs::Values(id) => id.try_into().ok(), + ItemInNs::Macros(id) => Some(id.into()), + } + }; + let (is_doc_hidden, is_unstable) = attr_id.map_or((false, false), |attr_id| { + let attrs = db.attrs(attr_id); + (attrs.has_doc_hidden(), attrs.is_unstable()) + }); + + let import_info = ImportInfo { + name: name.clone(), + container: module, + is_doc_hidden, + is_unstable, + }; + + if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() { + Self::collect_trait_assoc_items( + db, + &mut map, + tr, + matches!(item, ItemInNs::Types(_)), + &import_info, + ); + } + + let (infos, _) = + map.entry(item).or_insert_with(|| (SmallVec::new(), IsTraitAssocItem::No)); + infos.reserve_exact(1); + infos.push(import_info); + + // If we've just added a module, descend into it. + if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { + worklist.push(mod_id); + } + } + } + } + map.shrink_to_fit(); + map } -} -impl PartialEq for ImportMap { - fn eq(&self, other: &Self) -> bool { - // `fst` and `importables` are built from `map`, so we don't need to compare them. - self.map == other.map + fn collect_trait_assoc_items( + db: &dyn DefDatabase, + map: &mut ImportMapIndex, + tr: TraitId, + is_type_in_ns: bool, + trait_import_info: &ImportInfo, + ) { + let _p = profile::span("collect_trait_assoc_items"); + for &(ref assoc_item_name, item) in &db.trait_data(tr).items { + let module_def_id = match item { + AssocItemId::FunctionId(f) => ModuleDefId::from(f), + AssocItemId::ConstId(c) => ModuleDefId::from(c), + // cannot use associated type aliases directly: need a `::TypeAlias` + // qualifier, ergo no need to store it for imports in import_map + AssocItemId::TypeAliasId(_) => { + cov_mark::hit!(type_aliases_ignored); + continue; + } + }; + let assoc_item = if is_type_in_ns { + ItemInNs::Types(module_def_id) + } else { + ItemInNs::Values(module_def_id) + }; + + let attrs = &db.attrs(item.into()); + let assoc_item_info = ImportInfo { + container: trait_import_info.container, + name: assoc_item_name.clone(), + is_doc_hidden: attrs.has_doc_hidden(), + is_unstable: attrs.is_unstable(), + }; + + let (infos, _) = + map.entry(assoc_item).or_insert_with(|| (SmallVec::new(), IsTraitAssocItem::Yes)); + infos.reserve_exact(1); + infos.push(assoc_item_info); + } } } impl Eq for ImportMap {} +impl PartialEq for ImportMap { + fn eq(&self, other: &Self) -> bool { + // `fst` and `importables` are built from `map`, so we don't need to compare them. + self.item_to_info_map == other.item_to_info_map + } +} impl fmt::Debug for ImportMap { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut importable_names: Vec<_> = self - .map + .item_to_info_map .iter() .map(|(item, (infos, _))| { let l = infos.len(); @@ -264,8 +279,8 @@ impl fmt::Debug for ImportMap { } /// A way to match import map contents against the search query. -#[derive(Copy, Clone, Debug)] -enum SearchMode { +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum SearchMode { /// Import map entry should strictly match the query string. Exact, /// Import map entry should contain all letters from the query string, @@ -275,6 +290,42 @@ enum SearchMode { Prefix, } +impl SearchMode { + pub fn check(self, query: &str, case_sensitive: bool, candidate: &str) -> bool { + match self { + SearchMode::Exact if case_sensitive => candidate == query, + SearchMode::Exact => candidate.eq_ignore_ascii_case(&query), + SearchMode::Prefix => { + query.len() <= candidate.len() && { + let prefix = &candidate[..query.len() as usize]; + if case_sensitive { + prefix == query + } else { + prefix.eq_ignore_ascii_case(&query) + } + } + } + SearchMode::Fuzzy => { + let mut name = candidate; + query.chars().all(|query_char| { + let m = if case_sensitive { + name.match_indices(query_char).next() + } else { + name.match_indices([query_char, query_char.to_ascii_uppercase()]).next() + }; + match m { + Some((index, _)) => { + name = &name[index + 1..]; + true + } + None => false, + } + }) + } + } + } +} + /// Three possible ways to search for the name in associated and/or other items. #[derive(Debug, Clone, Copy)] pub enum AssocSearchMode { @@ -293,7 +344,6 @@ pub struct Query { search_mode: SearchMode, assoc_mode: AssocSearchMode, case_sensitive: bool, - limit: usize, } impl Query { @@ -305,7 +355,6 @@ impl Query { search_mode: SearchMode::Exact, assoc_mode: AssocSearchMode::Include, case_sensitive: false, - limit: usize::MAX, } } @@ -327,11 +376,6 @@ impl Query { Self { assoc_mode, ..self } } - /// Limits the returned number of items to `limit`. - pub fn limit(self, limit: usize) -> Self { - Self { limit, ..self } - } - /// Respect casing of the query string when matching. pub fn case_sensitive(self) -> Self { Self { case_sensitive: true, ..self } @@ -344,39 +388,6 @@ impl Query { _ => true, } } - - /// Checks whether the import map entry matches the query. - fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool { - let _p = profile::span("import_map::Query::import_matches"); - - // FIXME: Can we get rid of the alloc here? - let input = import.name.to_smol_str(); - let mut _s_slot; - let case_insensitive = enforce_lowercase || !self.case_sensitive; - let input = if case_insensitive { - _s_slot = String::from(input); - _s_slot.make_ascii_lowercase(); - &*_s_slot - } else { - &*input - }; - - let query_string = if case_insensitive { &self.lowercased } else { &self.query }; - - match self.search_mode { - SearchMode::Exact => input == *query_string, - SearchMode::Prefix => input.starts_with(query_string), - SearchMode::Fuzzy => { - let mut input_chars = input.chars(); - for query_char in query_string.chars() { - if !input_chars.any(|it| it == query_char) { - return false; - } - } - true - } - } - } } /// Searches dependencies of `krate` for an importable name matching `query`. @@ -394,73 +405,66 @@ pub fn search_dependencies( let import_maps: Vec<_> = graph[krate].dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect(); - let automaton = fst::automaton::Subsequence::new(&query.lowercased); - let mut op = fst::map::OpBuilder::new(); - for map in &import_maps { - op = op.add(map.fst.search(&automaton)); + + match query.search_mode { + SearchMode::Exact => { + let automaton = fst::automaton::Str::new(&query.lowercased); + + for map in &import_maps { + op = op.add(map.fst.search(&automaton)); + } + search_maps(&import_maps, op.union(), query) + } + SearchMode::Fuzzy => { + let automaton = fst::automaton::Subsequence::new(&query.lowercased); + + for map in &import_maps { + op = op.add(map.fst.search(&automaton)); + } + search_maps(&import_maps, op.union(), query) + } + SearchMode::Prefix => { + let automaton = fst::automaton::Str::new(&query.lowercased).starts_with(); + + for map in &import_maps { + op = op.add(map.fst.search(&automaton)); + } + search_maps(&import_maps, op.union(), query) + } } +} - let mut stream = op.union(); - +fn search_maps( + import_maps: &[Arc], + mut stream: fst::map::Union<'_>, + query: &Query, +) -> FxHashSet { let mut res = FxHashSet::default(); - let mut common_importable_data_scratch = vec![]; - // FIXME: Improve this, its rather unreadable and does duplicate amount of work while let Some((_, indexed_values)) = stream.next() { - for &IndexedValue { index, value } in indexed_values { - let import_map = &import_maps[index]; - let importables @ [importable, ..] = &import_map.importables[value as usize..] else { - continue; - }; - let &(ref importable_data, is_trait_assoc_item) = &import_map.map[importable]; - if !query.matches_assoc_mode(is_trait_assoc_item) { - continue; - } + for &IndexedValue { index: import_map_idx, value } in indexed_values { + let end = (value & 0xFFFF_FFFF) as usize; + let start = (value >> 32) as usize; + let ImportMap { item_to_info_map, importables, .. } = &*import_maps[import_map_idx]; + let importables = &importables[start as usize..end]; - // Fetch all the known names of this importable item (to handle import aliases/renames) - common_importable_data_scratch.extend( - importable_data - .iter() - .filter(|&info| query.import_matches(info, true)) - // Name shared by the importable items in this group. - .map(|info| info.name.to_smol_str()), - ); - if common_importable_data_scratch.is_empty() { - continue; - } - common_importable_data_scratch.sort(); - common_importable_data_scratch.dedup(); - - let iter = - common_importable_data_scratch.drain(..).flat_map(|common_importable_name| { - // Add the items from this name group. Those are all subsequent items in - // `importables` whose name match `common_importable_name`. - - importables - .iter() - .copied() - .take_while(move |item| { - let &(ref import_infos, assoc_mode) = &import_map.map[item]; - query.matches_assoc_mode(assoc_mode) - && import_infos.iter().any(|info| { - info.name - .to_smol_str() - .eq_ignore_ascii_case(&common_importable_name) - }) - }) - .filter(move |item| { - !query.case_sensitive || { - // we've already checked the common importables name case-insensitively - let &(ref import_infos, _) = &import_map.map[item]; - import_infos.iter().any(|info| query.import_matches(info, false)) - } - }) + let iter = importables + .iter() + .copied() + .filter_map(|(item, info_idx)| { + let (import_infos, assoc_mode) = &item_to_info_map[&item]; + query + .matches_assoc_mode(*assoc_mode) + .then(|| (item, &import_infos[info_idx as usize])) + }) + .filter(|&(_, info)| { + query.search_mode.check( + &query.query, + query.case_sensitive, + &info.name.to_smol_str(), + ) }); - res.extend(iter); - - if res.len() >= query.limit { - return res; - } + res.extend(iter.map(TupleExt::head)); } } @@ -480,7 +484,7 @@ mod tests { impl ImportMap { fn fmt_for_test(&self, db: &dyn DefDatabase) -> String { let mut importable_paths: Vec<_> = self - .map + .item_to_info_map .iter() .flat_map(|(item, (info, _))| info.iter().map(move |info| (item, info))) .map(|(item, info)| { @@ -907,28 +911,28 @@ mod tests { #[test] fn search_mode() { let ra_fixture = r#" - //- /main.rs crate:main deps:dep - //- /dep.rs crate:dep deps:tdep - use tdep::fmt as fmt_dep; - pub mod fmt { - pub trait Display { - fn fmt(); - } - } - #[macro_export] - macro_rules! Fmt { - () => {}; - } - pub struct Fmt; +//- /main.rs crate:main deps:dep +//- /dep.rs crate:dep deps:tdep +use tdep::fmt as fmt_dep; +pub mod fmt { + pub trait Display { + fn fmt(); + } +} +#[macro_export] +macro_rules! Fmt { + () => {}; +} +pub struct Fmt; - pub fn format() {} - pub fn no() {} +pub fn format() {} +pub fn no() {} - //- /tdep.rs crate:tdep - pub mod fmt { - pub struct NotImportableFromMain; - } - "#; +//- /tdep.rs crate:tdep +pub mod fmt { + pub struct NotImportableFromMain; +} +"#; check_search( ra_fixture, @@ -996,19 +1000,6 @@ mod tests { dep::fmt::Display::fmt (a) "#]], ); - - check_search( - ra_fixture, - "main", - Query::new("fmt".to_string()), - expect![[r#" - dep::Fmt (m) - dep::Fmt (t) - dep::Fmt (v) - dep::fmt (t) - dep::fmt::Display::fmt (a) - "#]], - ); } #[test] @@ -1043,32 +1034,4 @@ mod tests { "#]], ); } - - #[test] - fn search_limit() { - check_search( - r#" - //- /main.rs crate:main deps:dep - //- /dep.rs crate:dep - pub mod fmt { - pub trait Display { - fn fmt(); - } - } - #[macro_export] - macro_rules! Fmt { - () => {}; - } - pub struct Fmt; - - pub fn format() {} - pub fn no() {} - "#, - "main", - Query::new("".to_string()).fuzzy().limit(1), - expect![[r#" - dep::fmt::Display (t) - "#]], - ); - } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 22ba3aab4e9f..250d7b677b5d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -307,6 +307,15 @@ pub struct FieldId { pub type LocalFieldId = Idx; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct TupleId(pub u32); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct TupleFieldId { + pub tuple: TupleId, + pub index: u32, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ConstId(salsa::InternId); type ConstLoc = AssocItemLoc; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 3763bfcbcfaf..a18ac4b28c4e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -1397,7 +1397,7 @@ impl DefCollector<'_> { always!(krate == loc.def.krate); DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate) } - _ => DefDiagnostic::macro_error(module_id, loc.kind.clone(), err.to_string()), + _ => DefDiagnostic::macro_error(module_id, loc.kind, err.to_string()), }; self.def_map.diagnostics.push(diag); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index f7a26e436dee..ed04582cb0ab 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -390,7 +390,13 @@ fn parse_macro_expansion( let expand_to = loc.expand_to(); let mbe::ValueResult { value: tt, err } = macro_expand(db, macro_file.macro_call_id, loc); - let (parse, rev_token_map) = token_tree_to_syntax_node(&tt, expand_to); + let (parse, rev_token_map) = token_tree_to_syntax_node( + match &tt { + CowArc::Arc(it) => it, + CowArc::Owned(it) => it, + }, + expand_to, + ); ExpandResult { value: (parse, Arc::new(rev_token_map)), err } } @@ -669,15 +675,20 @@ fn macro_expander(db: &dyn ExpandDatabase, id: MacroDefId) -> TokenExpander { } } +enum CowArc { + Arc(Arc), + Owned(T), +} + fn macro_expand( db: &dyn ExpandDatabase, macro_call_id: MacroCallId, loc: MacroCallLoc, -) -> ExpandResult> { +) -> ExpandResult> { let _p = profile::span("macro_expand"); let ExpandResult { value: tt, mut err } = match loc.def.kind { - MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id), + MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id).map(CowArc::Arc), MacroDefKind::BuiltInDerive(expander, ..) => { let (root, map) = parse_with_map(db, loc.kind.file_id()); let root = root.syntax_node(); @@ -692,7 +703,7 @@ fn macro_expand( let ValueResult { value, err } = db.macro_arg(macro_call_id); let Some((macro_arg, undo_info)) = value else { return ExpandResult { - value: Arc::new(tt::Subtree { + value: CowArc::Owned(tt::Subtree { delimiter: tt::Delimiter::invisible_spanned(loc.call_site), token_trees: Vec::new(), }), @@ -718,7 +729,7 @@ fn macro_expand( // As such we just return the input subtree here. MacroDefKind::BuiltInEager(..) if loc.eager.is_none() => { return ExpandResult { - value: macro_arg.clone(), + value: CowArc::Arc(macro_arg.clone()), err: err.map(|err| { let mut buf = String::new(); for err in &**err { @@ -752,12 +763,17 @@ fn macro_expand( // Skip checking token tree limit for include! macro call if !loc.def.is_include() { // Set a hard limit for the expanded tt - if let Err(value) = check_tt_count(&tt, loc.call_site) { - return value; + if let Err(value) = check_tt_count(&tt) { + return value.map(|()| { + CowArc::Owned(tt::Subtree { + delimiter: tt::Delimiter::invisible_spanned(loc.call_site), + token_trees: vec![], + }) + }); } } - ExpandResult { value: Arc::new(tt), err } + ExpandResult { value: CowArc::Owned(tt), err } } fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult> { @@ -796,8 +812,13 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult Result<(), ExpandResult>> { +fn check_tt_count(tt: &tt::Subtree) -> Result<(), ExpandResult<()>> { let count = tt.count(); if TOKEN_LIMIT.check(count).is_err() { Err(ExpandResult { - value: Arc::new(tt::Subtree { - delimiter: tt::Delimiter::invisible_spanned(call_site), - token_trees: vec![], - }), + value: (), err: Some(ExpandError::other(format!( "macro invocation exceeds token limit: produced {} tokens, limit is {}", count, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index b5197d4c25d2..6a122e0859cc 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -220,6 +220,8 @@ pub enum MacroCallKind { }, Attr { ast_id: AstId, + // FIXME: This is being interned, subtrees can very quickly differ just slightly causing + // leakage problems here attr_args: Option>, /// Syntactical index of the invoking `#[attribute]`. /// diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index 1873e7bfe6a5..c7807bcf9aa1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -32,6 +32,7 @@ once_cell = "1.17.0" triomphe.workspace = true nohash-hasher.workspace = true typed-arena = "2.0.1" +indexmap.workspace = true rustc-dependencies.workspace = true @@ -60,4 +61,4 @@ test-fixture.workspace = true in-rust-tree = ["rustc-dependencies/in-rust-tree"] [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index 9792d945eb8f..5528ad3ab4ab 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -142,15 +142,15 @@ pub fn intern_const_ref( LiteralConstRef::Int(i) => { // FIXME: We should handle failure of layout better. let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); - ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) + ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default()) } LiteralConstRef::UInt(i) => { let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); - ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) + ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default()) } - LiteralConstRef::Bool(b) => ConstScalar::Bytes(vec![*b as u8], MemoryMap::default()), + LiteralConstRef::Bool(b) => ConstScalar::Bytes(Box::new([*b as u8]), MemoryMap::default()), LiteralConstRef::Char(c) => { - ConstScalar::Bytes((*c as u32).to_le_bytes().to_vec(), MemoryMap::default()) + ConstScalar::Bytes((*c as u32).to_le_bytes().into(), MemoryMap::default()) } LiteralConstRef::Unknown => ConstScalar::Unknown, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index d81926f7c976..23d951542214 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -515,7 +515,7 @@ fn render_const_scalar( TyKind::Dyn(_) => { let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap()); let ty_id = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap()); - let Ok(t) = memory_map.vtable.ty(ty_id) else { + let Ok(t) = memory_map.vtable_ty(ty_id) else { return f.write_str(""); }; let Ok(layout) = f.db.layout_of_ty(t.clone(), trait_env) else { @@ -609,7 +609,7 @@ fn render_const_scalar( } hir_def::AdtId::EnumId(e) => { let Some((var_id, var_layout)) = - detect_variant_from_bytes(&layout, f.db, trait_env.clone(), b, e) + detect_variant_from_bytes(&layout, f.db, trait_env, b, e) else { return f.write_str(""); }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 8053300ad220..a78e3e7dc251 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -41,9 +41,10 @@ use hir_def::{ resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, type_ref::TypeRef, AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, ItemContainerId, Lookup, - TraitId, TypeAliasId, VariantId, + TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId, }; use hir_expand::name::{name, Name}; +use indexmap::IndexSet; use la_arena::{ArenaMap, Entry}; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::{always, never}; @@ -403,11 +404,15 @@ pub struct InferenceResult { /// For each method call expr, records the function it resolves to. method_resolutions: FxHashMap, /// For each field access expr, records the field it resolves to. - field_resolutions: FxHashMap, + field_resolutions: FxHashMap>, /// For each struct literal or pattern, records the variant it resolves to. variant_resolutions: FxHashMap, /// For each associated item record what it resolves to assoc_resolutions: FxHashMap, + /// Whenever a tuple field expression access a tuple field, we allocate a tuple id in + /// [`InferenceContext`] and store the tuples substitution there. This map is the reverse of + /// that which allows us to resolve a [`TupleFieldId`]s type. + pub tuple_field_access_types: FxHashMap, pub diagnostics: Vec, pub type_of_expr: ArenaMap, /// For each pattern record the type it resolves to. @@ -447,7 +452,7 @@ impl InferenceResult { pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> { self.method_resolutions.get(&expr).cloned() } - pub fn field_resolution(&self, expr: ExprId) -> Option { + pub fn field_resolution(&self, expr: ExprId) -> Option> { self.field_resolutions.get(&expr).copied() } pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option { @@ -517,6 +522,8 @@ pub(crate) struct InferenceContext<'a> { /// The traits in scope, disregarding block modules. This is used for caching purposes. traits_in_scope: FxHashSet, pub(crate) result: InferenceResult, + tuple_field_accesses_rev: + IndexSet>, /// The return type of the function being inferred, the closure or async block if we're /// currently within one. /// @@ -598,6 +605,7 @@ impl<'a> InferenceContext<'a> { InferenceContext { result: InferenceResult::default(), table: unify::InferenceTable::new(db, trait_env), + tuple_field_accesses_rev: Default::default(), return_ty: TyKind::Error.intern(Interner), // set in collect_* calls resume_yield_tys: None, return_coercion: None, @@ -621,7 +629,13 @@ impl<'a> InferenceContext<'a> { // used this function for another workaround, mention it here. If you really need this function and believe that // there is no problem in it being `pub(crate)`, remove this comment. pub(crate) fn resolve_all(self) -> InferenceResult { - let InferenceContext { mut table, mut result, deferred_cast_checks, .. } = self; + let InferenceContext { + mut table, + mut result, + deferred_cast_checks, + tuple_field_accesses_rev, + .. + } = self; // Destructure every single field so whenever new fields are added to `InferenceResult` we // don't forget to handle them here. let InferenceResult { @@ -645,6 +659,7 @@ impl<'a> InferenceContext<'a> { // to resolve them here. closure_info: _, mutated_bindings_in_closure: _, + tuple_field_access_types: _, } = &mut result; table.fallback_if_possible(); @@ -720,6 +735,11 @@ impl<'a> InferenceContext<'a> { for adjustment in pat_adjustments.values_mut().flatten() { *adjustment = table.resolve_completely(adjustment.clone()); } + result.tuple_field_access_types = tuple_field_accesses_rev + .into_iter() + .enumerate() + .map(|(idx, subst)| (TupleId(idx as u32), table.resolve_completely(subst))) + .collect(); result } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index af74df1032cb..118b9c0149f6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -1,18 +1,19 @@ //! Inference of closure parameter types based on the closure's expected type. -use std::{cmp, collections::HashMap, convert::Infallible, mem}; +use std::{cmp, convert::Infallible, mem}; use chalk_ir::{ cast::Cast, fold::{FallibleTypeFolder, TypeFoldable}, AliasEq, AliasTy, BoundVar, DebruijnIndex, FnSubst, Mutability, TyKind, WhereClause, }; +use either::Either; use hir_def::{ data::adt::VariantData, hir::{Array, BinaryOp, BindingId, CaptureBy, Expr, ExprId, Pat, PatId, Statement, UnaryOp}, lang_item::LangItem, resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, - DefWithBodyId, FieldId, HasModule, VariantId, + DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId, }; use hir_expand::name; use rustc_hash::FxHashMap; @@ -129,7 +130,7 @@ impl HirPlace { ctx.owner.module(ctx.db.upcast()).krate(), ); } - ty.clone() + ty } fn capture_kind_of_truncated_place( @@ -186,7 +187,7 @@ impl CapturedItem { result = format!("*{result}"); field_need_paren = true; } - ProjectionElem::Field(f) => { + ProjectionElem::Field(Either::Left(f)) => { if field_need_paren { result = format!("({result})"); } @@ -207,7 +208,15 @@ impl CapturedItem { result = format!("{result}.{field}"); field_need_paren = false; } - &ProjectionElem::TupleOrClosureField(field) => { + ProjectionElem::Field(Either::Right(f)) => { + let field = f.index; + if field_need_paren { + result = format!("({result})"); + } + result = format!("{result}.{field}"); + field_need_paren = false; + } + &ProjectionElem::ClosureField(field) => { if field_need_paren { result = format!("({result})"); } @@ -236,7 +245,7 @@ pub(crate) struct CapturedItemWithoutTy { impl CapturedItemWithoutTy { fn with_ty(self, ctx: &mut InferenceContext<'_>) -> CapturedItem { - let ty = self.place.ty(ctx).clone(); + let ty = self.place.ty(ctx); let ty = match &self.kind { CaptureKind::ByValue => ty, CaptureKind::ByRef(bk) => { @@ -329,15 +338,10 @@ impl InferenceContext<'_> { } } } - Expr::Field { expr, name } => { + Expr::Field { expr, name: _ } => { let mut place = self.place_of_expr(*expr)?; - if let TyKind::Tuple(..) = self.expr_ty(*expr).kind(Interner) { - let index = name.as_tuple_index()?; - place.projections.push(ProjectionElem::TupleOrClosureField(index)) - } else { - let field = self.result.field_resolution(tgt_expr)?; - place.projections.push(ProjectionElem::Field(field)); - } + let field = self.result.field_resolution(tgt_expr)?; + place.projections.push(ProjectionElem::Field(field)); return Some(place); } Expr::UnaryOp { expr, op: UnaryOp::Deref } => { @@ -392,7 +396,7 @@ impl InferenceContext<'_> { fn consume_place(&mut self, place: HirPlace, span: MirSpan) { if self.is_upvar(&place) { - let ty = place.ty(self).clone(); + let ty = place.ty(self); let kind = if self.is_ty_copy(ty) { CaptureKind::ByRef(BorrowKind::Shared) } else { @@ -598,7 +602,7 @@ impl InferenceContext<'_> { self.consume_expr(expr); } } - Expr::Index { base, index } => { + Expr::Index { base, index, is_assignee_expr: _ } => { self.select_from_expr(*base); self.consume_expr(*index); } @@ -774,7 +778,7 @@ impl InferenceContext<'_> { fn minimize_captures(&mut self) { self.current_captures.sort_by_key(|it| it.place.projections.len()); - let mut hash_map = HashMap::::new(); + let mut hash_map = FxHashMap::::default(); let result = mem::take(&mut self.current_captures); for item in result { let mut lookup_place = HirPlace { local: item.place.local, projections: vec![] }; @@ -825,7 +829,10 @@ impl InferenceContext<'_> { let it = al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev())); for (arg, i) in it { let mut p = place.clone(); - p.projections.push(ProjectionElem::TupleOrClosureField(i)); + p.projections.push(ProjectionElem::Field(Either::Right(TupleFieldId { + tuple: TupleId(!0), // dummy this, as its unused anyways + index: i as u32, + }))); self.consume_with_pat(p, *arg); } } @@ -850,10 +857,10 @@ impl InferenceContext<'_> { continue; }; let mut p = place.clone(); - p.projections.push(ProjectionElem::Field(FieldId { + p.projections.push(ProjectionElem::Field(Either::Left(FieldId { parent: variant.into(), local_id, - })); + }))); self.consume_with_pat(p, arg); } } @@ -894,10 +901,10 @@ impl InferenceContext<'_> { al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev())); for (arg, (i, _)) in it { let mut p = place.clone(); - p.projections.push(ProjectionElem::Field(FieldId { + p.projections.push(ProjectionElem::Field(Either::Left(FieldId { parent: variant.into(), local_id: i, - })); + }))); self.consume_with_pat(p, *arg); } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 84954ca7e904..db631c8517c1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -6,6 +6,7 @@ use std::{ }; use chalk_ir::{cast::Cast, fold::Shift, DebruijnIndex, Mutability, TyVariableKind}; +use either::Either; use hir_def::{ generics::TypeOrConstParamData, hir::{ @@ -13,7 +14,7 @@ use hir_def::{ }, lang_item::{LangItem, LangItemTarget}, path::{GenericArg, GenericArgs}, - BlockId, ConstParamId, FieldId, ItemContainerId, Lookup, + BlockId, ConstParamId, FieldId, ItemContainerId, Lookup, TupleFieldId, TupleId, }; use hir_expand::name::{name, Name}; use stdx::always; @@ -744,7 +745,7 @@ impl InferenceContext<'_> { (RangeOp::Inclusive, _, None) => self.err_ty(), } } - Expr::Index { base, index } => { + Expr::Index { base, index, is_assignee_expr } => { let base_ty = self.infer_expr_inner(*base, &Expectation::none()); let index_ty = self.infer_expr(*index, &Expectation::none()); @@ -772,11 +773,24 @@ impl InferenceContext<'_> { .build(); self.write_method_resolution(tgt_expr, func, substs); } - self.resolve_associated_type_with_params( - self_ty, - self.resolve_ops_index_output(), - &[index_ty.cast(Interner)], - ) + let assoc = self.resolve_ops_index_output(); + let res = self.resolve_associated_type_with_params( + self_ty.clone(), + assoc, + &[index_ty.clone().cast(Interner)], + ); + + if *is_assignee_expr { + if let Some(index_trait) = self.resolve_lang_trait(LangItem::IndexMut) { + let trait_ref = TyBuilder::trait_ref(self.db, index_trait) + .push(self_ty) + .fill(|_| index_ty.clone().cast(Interner)) + .build(); + self.push_obligation(trait_ref.cast(Interner)); + } + } + + res } else { self.err_ty() } @@ -964,7 +978,7 @@ impl InferenceContext<'_> { .push(callee_ty.clone()) .push(TyBuilder::tuple_with(params.iter().cloned())) .build(); - self.write_method_resolution(tgt_expr, func, subst.clone()); + self.write_method_resolution(tgt_expr, func, subst); } } @@ -1393,7 +1407,7 @@ impl InferenceContext<'_> { &mut self, receiver_ty: &Ty, name: &Name, - ) -> Option<(Ty, Option, Vec, bool)> { + ) -> Option<(Ty, Either, Vec, bool)> { let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone(), false); let mut private_field = None; let res = autoderef.by_ref().find_map(|(derefed_ty, _)| { @@ -1405,7 +1419,20 @@ impl InferenceContext<'_> { .get(idx) .map(|a| a.assert_ty_ref(Interner)) .cloned() - .map(|ty| (None, ty)) + .map(|ty| { + ( + Either::Right(TupleFieldId { + tuple: TupleId( + self.tuple_field_accesses_rev + .insert_full(substs.clone()) + .0 + as u32, + ), + index: idx as u32, + }), + ty, + ) + }) }); } TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => { @@ -1431,7 +1458,7 @@ impl InferenceContext<'_> { let ty = self.db.field_types(field_id.parent)[field_id.local_id] .clone() .substitute(Interner, ¶meters); - Some((Some(field_id), ty)) + Some((Either::Left(field_id), ty)) }); Some(match res { @@ -1451,7 +1478,7 @@ impl InferenceContext<'_> { let ty = self.insert_type_vars(ty); let ty = self.normalize_associated_types_in(ty); - (ty, Some(field_id), adjustments, false) + (ty, Either::Left(field_id), adjustments, false) } }) } @@ -1474,11 +1501,9 @@ impl InferenceContext<'_> { match self.lookup_field(&receiver_ty, name) { Some((ty, field_id, adjustments, is_public)) => { self.write_expr_adj(receiver, adjustments); - if let Some(field_id) = field_id { - self.result.field_resolutions.insert(tgt_expr, field_id); - } + self.result.field_resolutions.insert(tgt_expr, field_id); if !is_public { - if let Some(field) = field_id { + if let Either::Left(field) = field_id { // FIXME: Merge this diagnostic into UnresolvedField? self.result .diagnostics @@ -1568,9 +1593,7 @@ impl InferenceContext<'_> { { Some((ty, field_id, adjustments, _public)) => { self.write_expr_adj(receiver, adjustments); - if let Some(field_id) = field_id { - self.result.field_resolutions.insert(tgt_expr, field_id); - } + self.result.field_resolutions.insert(tgt_expr, field_id); Some(ty) } None => None, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index b8a1af96fba6..663ea8532318 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -96,7 +96,7 @@ impl InferenceContext<'_> { Expr::RecordLit { path: _, fields, spread, ellipsis: _, is_assignee_expr: _ } => { self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread)) } - &Expr::Index { base, index } => { + &Expr::Index { base, index, is_assignee_expr: _ } => { if mutability == Mutability::Mut { if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { if let Some(index_trait) = self diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index acdb540289d7..1bf8babe8365 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -233,7 +233,6 @@ impl InferenceContext<'_> { }; let mut expectations_iter = expectations .iter() - .cloned() .map(|a| a.assert_ty_ref(Interner).clone()) .chain(repeat_with(|| self.table.new_type_var())); @@ -336,7 +335,7 @@ impl InferenceContext<'_> { &Pat::Lit(expr) => { // Don't emit type mismatches again, the expression lowering already did that. let ty = self.infer_lit_pat(expr, &expected); - self.write_pat_ty(pat, ty.clone()); + self.write_pat_ty(pat, ty); return self.pat_ty_after_adjustment(pat); } Pat::Box { inner } => match self.resolve_boxed_box() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs index e4dd4b86cf99..eb6296f7a04a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs @@ -1,9 +1,15 @@ //! Implementation of the Chalk `Interner` trait, which allows customizing the //! representation of the various objects Chalk deals with (types, goals etc.). -use crate::{chalk_db, tls, ConstScalar, GenericArg}; +use crate::{ + chalk_db, tls, AliasTy, CanonicalVarKind, CanonicalVarKinds, ClosureId, Const, ConstData, + ConstScalar, Constraint, Constraints, FnDefId, GenericArg, GenericArgData, Goal, GoalData, + Goals, InEnvironment, Lifetime, LifetimeData, OpaqueTy, OpaqueTyId, ProgramClause, + ProgramClauseData, ProgramClauses, ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, + Substitution, Ty, TyData, TyKind, VariableKind, VariableKinds, +}; use base_db::salsa::InternId; -use chalk_ir::{Goal, GoalData}; +use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variance}; use hir_def::TypeAliasId; use intern::{impl_internable, Interned}; use smallvec::SmallVec; @@ -31,36 +37,37 @@ impl std::ops::Deref for InternedWrapper { } impl_internable!( - InternedWrapper>>, + InternedWrapper>, InternedWrapper>, - InternedWrapper>, - InternedWrapper>, - InternedWrapper>, + InternedWrapper, + InternedWrapper, + InternedWrapper, InternedWrapper, - InternedWrapper>>, - InternedWrapper>>, - InternedWrapper>>, - InternedWrapper>, + InternedWrapper>, + InternedWrapper>, + InternedWrapper>, + InternedWrapper>, ); impl chalk_ir::interner::Interner for Interner { - type InternedType = Interned>>; - type InternedLifetime = Interned>>; - type InternedConst = Interned>>; + type InternedType = Interned>; + type InternedLifetime = Interned>; + type InternedConst = Interned>; type InternedConcreteConst = ConstScalar; - type InternedGenericArg = chalk_ir::GenericArgData; - type InternedGoal = Arc>; - type InternedGoals = Vec>; + type InternedGenericArg = GenericArgData; + // We could do the following, but that saves "only" 20mb on self while increasing inferecene + // time by ~2.5% + // type InternedGoal = Interned>; + type InternedGoal = Arc; + type InternedGoals = Vec; type InternedSubstitution = Interned>>; - type InternedProgramClauses = Interned>>>; - type InternedProgramClause = chalk_ir::ProgramClauseData; - type InternedQuantifiedWhereClauses = - Interned>>>; - type InternedVariableKinds = Interned>>>; - type InternedCanonicalVarKinds = - Interned>>>; - type InternedConstraints = Vec>>; - type InternedVariances = Interned>>; + type InternedProgramClauses = Interned>>; + type InternedProgramClause = ProgramClauseData; + type InternedQuantifiedWhereClauses = Interned>>; + type InternedVariableKinds = Interned>>; + type InternedCanonicalVarKinds = Interned>>; + type InternedConstraints = Vec>; + type InternedVariances = SmallVec<[Variance; 16]>; type DefId = InternId; type InternedAdtId = hir_def::AdtId; type Identifier = TypeAliasId; @@ -88,68 +95,51 @@ impl chalk_ir::interner::Interner for Interner { } fn debug_opaque_ty_id( - opaque_ty_id: chalk_ir::OpaqueTyId, + opaque_ty_id: OpaqueTyId, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "OpaqueTy#{}", opaque_ty_id.0)) } - fn debug_fn_def_id( - fn_def_id: chalk_ir::FnDefId, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { + fn debug_fn_def_id(fn_def_id: FnDefId, fmt: &mut fmt::Formatter<'_>) -> Option { tls::with_current_program(|prog| Some(prog?.debug_fn_def_id(fn_def_id, fmt))) } fn debug_closure_id( - _fn_def_id: chalk_ir::ClosureId, + _fn_def_id: ClosureId, _fmt: &mut fmt::Formatter<'_>, ) -> Option { None } - fn debug_alias( - alias: &chalk_ir::AliasTy, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { + fn debug_alias(alias: &AliasTy, fmt: &mut fmt::Formatter<'_>) -> Option { use std::fmt::Debug; match alias { - chalk_ir::AliasTy::Projection(projection_ty) => { - Interner::debug_projection_ty(projection_ty, fmt) - } - chalk_ir::AliasTy::Opaque(opaque_ty) => Some(opaque_ty.fmt(fmt)), + AliasTy::Projection(projection_ty) => Interner::debug_projection_ty(projection_ty, fmt), + AliasTy::Opaque(opaque_ty) => Some(opaque_ty.fmt(fmt)), } } fn debug_projection_ty( - proj: &chalk_ir::ProjectionTy, + proj: &ProjectionTy, fmt: &mut fmt::Formatter<'_>, ) -> Option { tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt))) } - fn debug_opaque_ty( - opaque_ty: &chalk_ir::OpaqueTy, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { + fn debug_opaque_ty(opaque_ty: &OpaqueTy, fmt: &mut fmt::Formatter<'_>) -> Option { Some(write!(fmt, "{:?}", opaque_ty.opaque_ty_id)) } - fn debug_ty(ty: &chalk_ir::Ty, fmt: &mut fmt::Formatter<'_>) -> Option { + fn debug_ty(ty: &Ty, fmt: &mut fmt::Formatter<'_>) -> Option { Some(write!(fmt, "{:?}", ty.data(Interner))) } - fn debug_lifetime( - lifetime: &chalk_ir::Lifetime, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { + fn debug_lifetime(lifetime: &Lifetime, fmt: &mut fmt::Formatter<'_>) -> Option { Some(write!(fmt, "{:?}", lifetime.data(Interner))) } - fn debug_const( - constant: &chalk_ir::Const, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { + fn debug_const(constant: &Const, fmt: &mut fmt::Formatter<'_>) -> Option { Some(write!(fmt, "{:?}", constant.data(Interner))) } @@ -161,102 +151,99 @@ impl chalk_ir::interner::Interner for Interner { } fn debug_variable_kinds( - variable_kinds: &chalk_ir::VariableKinds, + variable_kinds: &VariableKinds, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", variable_kinds.as_slice(Interner))) } fn debug_variable_kinds_with_angles( - variable_kinds: &chalk_ir::VariableKinds, + variable_kinds: &VariableKinds, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", variable_kinds.inner_debug(Interner))) } fn debug_canonical_var_kinds( - canonical_var_kinds: &chalk_ir::CanonicalVarKinds, + canonical_var_kinds: &CanonicalVarKinds, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", canonical_var_kinds.as_slice(Interner))) } - fn debug_goal(goal: &Goal, fmt: &mut fmt::Formatter<'_>) -> Option { + fn debug_goal(goal: &Goal, fmt: &mut fmt::Formatter<'_>) -> Option { let goal_data = goal.data(Interner); Some(write!(fmt, "{goal_data:?}")) } - fn debug_goals( - goals: &chalk_ir::Goals, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { + fn debug_goals(goals: &Goals, fmt: &mut fmt::Formatter<'_>) -> Option { Some(write!(fmt, "{:?}", goals.debug(Interner))) } fn debug_program_clause_implication( - pci: &chalk_ir::ProgramClauseImplication, + pci: &ProgramClauseImplication, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", pci.debug(Interner))) } fn debug_program_clause( - clause: &chalk_ir::ProgramClause, + clause: &ProgramClause, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", clause.data(Interner))) } fn debug_program_clauses( - clauses: &chalk_ir::ProgramClauses, + clauses: &ProgramClauses, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", clauses.as_slice(Interner))) } fn debug_substitution( - substitution: &chalk_ir::Substitution, + substitution: &Substitution, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", substitution.debug(Interner))) } fn debug_separator_trait_ref( - separator_trait_ref: &chalk_ir::SeparatorTraitRef<'_, Interner>, + separator_trait_ref: &SeparatorTraitRef<'_, Interner>, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", separator_trait_ref.debug(Interner))) } fn debug_quantified_where_clauses( - clauses: &chalk_ir::QuantifiedWhereClauses, + clauses: &QuantifiedWhereClauses, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", clauses.as_slice(Interner))) } fn debug_constraints( - _clauses: &chalk_ir::Constraints, + _clauses: &Constraints, _fmt: &mut fmt::Formatter<'_>, ) -> Option { None } - fn intern_ty(self, kind: chalk_ir::TyKind) -> Self::InternedType { + fn intern_ty(self, kind: TyKind) -> Self::InternedType { let flags = kind.compute_flags(self); - Interned::new(InternedWrapper(chalk_ir::TyData { kind, flags })) + Interned::new(InternedWrapper(TyData { kind, flags })) } - fn ty_data(self, ty: &Self::InternedType) -> &chalk_ir::TyData { + fn ty_data(self, ty: &Self::InternedType) -> &TyData { &ty.0 } - fn intern_lifetime(self, lifetime: chalk_ir::LifetimeData) -> Self::InternedLifetime { + fn intern_lifetime(self, lifetime: LifetimeData) -> Self::InternedLifetime { Interned::new(InternedWrapper(lifetime)) } - fn lifetime_data(self, lifetime: &Self::InternedLifetime) -> &chalk_ir::LifetimeData { + fn lifetime_data(self, lifetime: &Self::InternedLifetime) -> &LifetimeData { &lifetime.0 } - fn intern_const(self, constant: chalk_ir::ConstData) -> Self::InternedConst { + fn intern_const(self, constant: ConstData) -> Self::InternedConst { Interned::new(InternedWrapper(constant)) } - fn const_data(self, constant: &Self::InternedConst) -> &chalk_ir::ConstData { + fn const_data(self, constant: &Self::InternedConst) -> &ConstData { &constant.0 } @@ -269,36 +256,33 @@ impl chalk_ir::interner::Interner for Interner { !matches!(c1, ConstScalar::Bytes(..)) || !matches!(c2, ConstScalar::Bytes(..)) || (c1 == c2) } - fn intern_generic_arg( - self, - parameter: chalk_ir::GenericArgData, - ) -> Self::InternedGenericArg { + fn intern_generic_arg(self, parameter: GenericArgData) -> Self::InternedGenericArg { parameter } - fn generic_arg_data( - self, - parameter: &Self::InternedGenericArg, - ) -> &chalk_ir::GenericArgData { + fn generic_arg_data(self, parameter: &Self::InternedGenericArg) -> &GenericArgData { parameter } - fn intern_goal(self, goal: GoalData) -> Self::InternedGoal { + fn intern_goal(self, goal: GoalData) -> Self::InternedGoal { Arc::new(goal) } - fn goal_data(self, goal: &Self::InternedGoal) -> &GoalData { + fn goal_data(self, goal: &Self::InternedGoal) -> &GoalData { goal } fn intern_goals( self, - data: impl IntoIterator, E>>, + data: impl IntoIterator>, ) -> Result { + // let hash = + // std::hash::BuildHasher::hash_one(&BuildHasherDefault::::default(), &goal); + // Interned::new(InternedWrapper(PreHashedWrapper(goal, hash))) data.into_iter().collect() } - fn goals_data(self, goals: &Self::InternedGoals) -> &[Goal] { + fn goals_data(self, goals: &Self::InternedGoals) -> &[Goal] { goals } @@ -313,37 +297,28 @@ impl chalk_ir::interner::Interner for Interner { &substitution.as_ref().0 } - fn intern_program_clause( - self, - data: chalk_ir::ProgramClauseData, - ) -> Self::InternedProgramClause { + fn intern_program_clause(self, data: ProgramClauseData) -> Self::InternedProgramClause { data } - fn program_clause_data( - self, - clause: &Self::InternedProgramClause, - ) -> &chalk_ir::ProgramClauseData { + fn program_clause_data(self, clause: &Self::InternedProgramClause) -> &ProgramClauseData { clause } fn intern_program_clauses( self, - data: impl IntoIterator, E>>, + data: impl IntoIterator>, ) -> Result { Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) } - fn program_clauses_data( - self, - clauses: &Self::InternedProgramClauses, - ) -> &[chalk_ir::ProgramClause] { + fn program_clauses_data(self, clauses: &Self::InternedProgramClauses) -> &[ProgramClause] { clauses } fn intern_quantified_where_clauses( self, - data: impl IntoIterator, E>>, + data: impl IntoIterator>, ) -> Result { Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) } @@ -351,27 +326,24 @@ impl chalk_ir::interner::Interner for Interner { fn quantified_where_clauses_data( self, clauses: &Self::InternedQuantifiedWhereClauses, - ) -> &[chalk_ir::QuantifiedWhereClause] { + ) -> &[QuantifiedWhereClause] { clauses } fn intern_generic_arg_kinds( self, - data: impl IntoIterator, E>>, + data: impl IntoIterator>, ) -> Result { Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) } - fn variable_kinds_data( - self, - parameter_kinds: &Self::InternedVariableKinds, - ) -> &[chalk_ir::VariableKind] { + fn variable_kinds_data(self, parameter_kinds: &Self::InternedVariableKinds) -> &[VariableKind] { ¶meter_kinds.as_ref().0 } fn intern_canonical_var_kinds( self, - data: impl IntoIterator, E>>, + data: impl IntoIterator>, ) -> Result { Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) } @@ -379,30 +351,30 @@ impl chalk_ir::interner::Interner for Interner { fn canonical_var_kinds_data( self, canonical_var_kinds: &Self::InternedCanonicalVarKinds, - ) -> &[chalk_ir::CanonicalVarKind] { + ) -> &[CanonicalVarKind] { canonical_var_kinds } fn intern_constraints( self, - data: impl IntoIterator>, E>>, + data: impl IntoIterator, E>>, ) -> Result { data.into_iter().collect() } fn constraints_data( self, constraints: &Self::InternedConstraints, - ) -> &[chalk_ir::InEnvironment>] { + ) -> &[InEnvironment] { constraints } fn intern_variances( self, - data: impl IntoIterator>, + data: impl IntoIterator>, ) -> Result { - Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) + data.into_iter().collect::>() } - fn variances_data(self, variances: &Self::InternedVariances) -> &[chalk_ir::Variance] { + fn variances_data(self, variances: &Self::InternedVariances) -> &[Variance] { variances } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index bfc4f1383ec6..68619bb8b18c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -164,7 +164,7 @@ fn layout_of_simd_ty( }; // Compute the ABI of the element type: - let e_ly = db.layout_of_ty(e_ty, env.clone())?; + let e_ly = db.layout_of_ty(e_ty, env)?; let Abi::Scalar(e_abi) = e_ly.abi else { return Err(LayoutError::Unknown); }; @@ -204,17 +204,17 @@ pub fn layout_of_ty_query( }; let cx = LayoutCx { target: &target }; let dl = &*cx.current_data_layout(); - let ty = normalize(db, trait_env.clone(), ty.clone()); + let ty = normalize(db, trait_env.clone(), ty); let result = match ty.kind(Interner) { TyKind::Adt(AdtId(def), subst) => { if let hir_def::AdtId::StructId(s) = def { let data = db.struct_data(*s); let repr = data.repr.unwrap_or_default(); if repr.simd() { - return layout_of_simd_ty(db, *s, subst, trait_env.clone(), &target); + return layout_of_simd_ty(db, *s, subst, trait_env, &target); } }; - return db.layout_of_adt(*def, subst.clone(), trait_env.clone()); + return db.layout_of_adt(*def, subst.clone(), trait_env); } TyKind::Scalar(s) => match s { chalk_ir::Scalar::Bool => Layout::scalar( @@ -280,7 +280,7 @@ pub fn layout_of_ty_query( } TyKind::Array(element, count) => { let count = try_const_usize(db, &count).ok_or(LayoutError::HasErrorConst)? as u64; - let element = db.layout_of_ty(element.clone(), trait_env.clone())?; + let element = db.layout_of_ty(element.clone(), trait_env)?; let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?; let abi = if count != 0 && matches!(element.abi, Abi::Uninhabited) { @@ -303,7 +303,7 @@ pub fn layout_of_ty_query( } } TyKind::Slice(element) => { - let element = db.layout_of_ty(element.clone(), trait_env.clone())?; + let element = db.layout_of_ty(element.clone(), trait_env)?; Layout { variants: Variants::Single { index: struct_variant_idx() }, fields: FieldsShape::Array { stride: element.size, count: 0 }, @@ -345,7 +345,7 @@ pub fn layout_of_ty_query( })) .intern(Interner); } - unsized_part = normalize(db, trait_env.clone(), unsized_part); + unsized_part = normalize(db, trait_env, unsized_part); let metadata = match unsized_part.kind(Interner) { TyKind::Slice(_) | TyKind::Str => { scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false)) @@ -384,7 +384,7 @@ pub fn layout_of_ty_query( match impl_trait_id { crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { let infer = db.infer(func.into()); - return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env.clone()); + return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env); } crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { return Err(LayoutError::NotImplemented) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index 9937113685ca..ef0be7ab2daf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -220,6 +220,36 @@ fn recursive() { ); } +#[test] +fn repr_packed() { + size_and_align! { + #[repr(packed)] + struct Goal; + } + size_and_align! { + #[repr(packed(2))] + struct Goal; + } + size_and_align! { + #[repr(packed(4))] + struct Goal; + } + size_and_align! { + #[repr(packed)] + struct Goal(i32); + } + size_and_align! { + #[repr(packed(2))] + struct Goal(i32); + } + size_and_align! { + #[repr(packed(4))] + struct Goal(i32); + } + + check_size_and_align("#[repr(packed(5))] struct Goal(i32);", "", 4, 1); +} + #[test] fn generic() { size_and_align! { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index cf174feed24b..793b52b49faa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -37,22 +37,22 @@ mod tests; mod test_db; use std::{ - collections::{hash_map::Entry, HashMap}, - hash::Hash, + collections::hash_map::Entry, + hash::{BuildHasherDefault, Hash}, }; use chalk_ir::{ fold::{Shift, TypeFoldable}, interner::HasInterner, visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, - NoSolution, TyData, + NoSolution, }; use either::Either; use hir_def::{hir::ExprId, type_ref::Rawness, GeneralConstId, TypeOrConstParamId}; use hir_expand::name; use la_arena::{Arena, Idx}; use mir::{MirEvalError, VTableMap}; -use rustc_hash::FxHashSet; +use rustc_hash::{FxHashMap, FxHashSet}; use syntax::ast::{make, ConstArg}; use traits::FnTrait; use triomphe::Arc; @@ -152,32 +152,64 @@ pub type DomainGoal = chalk_ir::DomainGoal; pub type Goal = chalk_ir::Goal; pub type AliasEq = chalk_ir::AliasEq; pub type Solution = chalk_solve::Solution; +pub type Constraint = chalk_ir::Constraint; +pub type Constraints = chalk_ir::Constraints; pub type ConstrainedSubst = chalk_ir::ConstrainedSubst; pub type Guidance = chalk_solve::Guidance; pub type WhereClause = chalk_ir::WhereClause; +pub type CanonicalVarKind = chalk_ir::CanonicalVarKind; +pub type GoalData = chalk_ir::GoalData; +pub type Goals = chalk_ir::Goals; +pub type ProgramClauseData = chalk_ir::ProgramClauseData; +pub type ProgramClause = chalk_ir::ProgramClause; +pub type ProgramClauses = chalk_ir::ProgramClauses; +pub type TyData = chalk_ir::TyData; +pub type Variances = chalk_ir::Variances; + /// A constant can have reference to other things. Memory map job is holding /// the necessary bits of memory of the const eval session to keep the constant /// meaningful. #[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct MemoryMap { - pub memory: HashMap>, - pub vtable: VTableMap, +pub enum MemoryMap { + #[default] + Empty, + Simple(Box<[u8]>), + Complex(Box), } -impl MemoryMap { - fn insert(&mut self, addr: usize, x: Vec) { +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub struct ComplexMemoryMap { + memory: FxHashMap>, + vtable: VTableMap, +} + +impl ComplexMemoryMap { + fn insert(&mut self, addr: usize, val: Box<[u8]>) { match self.memory.entry(addr) { Entry::Occupied(mut e) => { - if e.get().len() < x.len() { - e.insert(x); + if e.get().len() < val.len() { + e.insert(val); } } Entry::Vacant(e) => { - e.insert(x); + e.insert(val); } } } +} + +impl MemoryMap { + pub fn vtable_ty(&self, id: usize) -> Result<&Ty, MirEvalError> { + match self { + MemoryMap::Empty | MemoryMap::Simple(_) => Err(MirEvalError::InvalidVTableId(id)), + MemoryMap::Complex(cm) => cm.vtable.ty(id), + } + } + + fn simple(v: Box<[u8]>) -> Self { + MemoryMap::Simple(v) + } /// This functions convert each address by a function `f` which gets the byte intervals and assign an address /// to them. It is useful when you want to load a constant with a memory map in a new memory. You can pass an @@ -185,22 +217,33 @@ impl MemoryMap { fn transform_addresses( &self, mut f: impl FnMut(&[u8], usize) -> Result, - ) -> Result, MirEvalError> { - self.memory - .iter() - .map(|x| { - let addr = *x.0; - let align = if addr == 0 { 64 } else { (addr - (addr & (addr - 1))).min(64) }; - Ok((addr, f(x.1, align)?)) - }) - .collect() + ) -> Result, MirEvalError> { + let mut transform = |(addr, val): (&usize, &Box<[u8]>)| { + let addr = *addr; + let align = if addr == 0 { 64 } else { (addr - (addr & (addr - 1))).min(64) }; + f(val, align).and_then(|it| Ok((addr, it))) + }; + match self { + MemoryMap::Empty => Ok(Default::default()), + MemoryMap::Simple(m) => transform((&0, m)).map(|(addr, val)| { + let mut map = FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default()); + map.insert(addr, val); + map + }), + MemoryMap::Complex(cm) => cm.memory.iter().map(transform).collect(), + } } - fn get<'a>(&'a self, addr: usize, size: usize) -> Option<&'a [u8]> { + fn get(&self, addr: usize, size: usize) -> Option<&[u8]> { if size == 0 { Some(&[]) } else { - self.memory.get(&addr)?.get(0..size) + match self { + MemoryMap::Empty => Some(&[]), + MemoryMap::Simple(m) if addr == 0 => m.get(0..size), + MemoryMap::Simple(_) => None, + MemoryMap::Complex(cm) => cm.memory.get(&addr)?.get(0..size), + } } } } @@ -208,7 +251,7 @@ impl MemoryMap { /// A concrete constant value #[derive(Debug, Clone, PartialEq, Eq)] pub enum ConstScalar { - Bytes(Vec, MemoryMap), + Bytes(Box<[u8]>, MemoryMap), // FIXME: this is a hack to get around chalk not being able to represent unevaluatable // constants UnevaluatedConst(GeneralConstId, Substitution), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 041d61c1b153..33619edfee93 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -1350,7 +1350,7 @@ pub(crate) fn resolve_indexing_op( ty: Canonical, index_trait: TraitId, ) -> Option { - let mut table = InferenceTable::new(db, env.clone()); + let mut table = InferenceTable::new(db, env); let ty = table.instantiate_canonical(ty); let deref_chain = autoderef_method_receiver(&mut table, ty); for (ty, adj) in deref_chain { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index f1795e71d945..7bef6f0d0f71 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -14,9 +14,10 @@ use crate::{ }; use base_db::CrateId; use chalk_ir::Mutability; +use either::Either; use hir_def::{ hir::{BindingId, Expr, ExprId, Ordering, PatId}, - DefWithBodyId, FieldId, StaticId, UnionId, VariantId, + DefWithBodyId, FieldId, StaticId, TupleFieldId, UnionId, VariantId, }; use la_arena::{Arena, ArenaMap, Idx, RawIdx}; @@ -97,16 +98,16 @@ pub enum Operand { } impl Operand { - fn from_concrete_const(data: Vec, memory_map: MemoryMap, ty: Ty) -> Self { + fn from_concrete_const(data: Box<[u8]>, memory_map: MemoryMap, ty: Ty) -> Self { Operand::Constant(intern_const_scalar(ConstScalar::Bytes(data, memory_map), ty)) } - fn from_bytes(data: Vec, ty: Ty) -> Self { + fn from_bytes(data: Box<[u8]>, ty: Ty) -> Self { Operand::from_concrete_const(data, MemoryMap::default(), ty) } fn const_zst(ty: Ty) -> Operand { - Self::from_bytes(vec![], ty) + Self::from_bytes(Box::default(), ty) } fn from_fn( @@ -117,16 +118,16 @@ impl Operand { let ty = chalk_ir::TyKind::FnDef(CallableDefId::FunctionId(func_id).to_chalk(db), generic_args) .intern(Interner); - Operand::from_bytes(vec![], ty) + Operand::from_bytes(Box::default(), ty) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ProjectionElem { Deref, - Field(FieldId), + Field(Either), // FIXME: get rid of this, and use FieldId for tuples and closures - TupleOrClosureField(usize), + ClosureField(usize), Index(V), ConstantIndex { offset: u64, from_end: bool }, Subslice { from: u64, to: u64 }, @@ -161,7 +162,7 @@ impl ProjectionElem { return TyKind::Error.intern(Interner); } }, - ProjectionElem::Field(f) => match &base.kind(Interner) { + ProjectionElem::Field(Either::Left(f)) => match &base.kind(Interner) { TyKind::Adt(_, subst) => { db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst) } @@ -170,19 +171,25 @@ impl ProjectionElem { return TyKind::Error.intern(Interner); } }, - ProjectionElem::TupleOrClosureField(f) => match &base.kind(Interner) { + ProjectionElem::Field(Either::Right(f)) => match &base.kind(Interner) { TyKind::Tuple(_, subst) => subst .as_slice(Interner) - .get(*f) + .get(f.index as usize) .map(|x| x.assert_ty_ref(Interner)) .cloned() .unwrap_or_else(|| { never!("Out of bound tuple field"); TyKind::Error.intern(Interner) }), + _ => { + never!("Only tuple has tuple field"); + return TyKind::Error.intern(Interner); + } + }, + ProjectionElem::ClosureField(f) => match &base.kind(Interner) { TyKind::Closure(id, subst) => closure_field(*id, subst, *f), _ => { - never!("Only tuple or closure has tuple or closure field"); + never!("Only closure has closure field"); return TyKind::Error.intern(Interner); } }, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index 74c5efd6c3f4..e79c87a02f40 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -205,7 +205,7 @@ fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> Projectio | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Field(_) - | ProjectionElem::TupleOrClosureField(_) + | ProjectionElem::ClosureField(_) | ProjectionElem::Index(_) => { is_part_of = true; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index fbfb6ff8cddd..16075d907343 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -1,13 +1,6 @@ //! This module provides a MIR interpreter, which is used in const eval. -use std::{ - borrow::Cow, - cell::RefCell, - collections::{HashMap, HashSet}, - fmt::Write, - iter, mem, - ops::Range, -}; +use std::{borrow::Cow, cell::RefCell, fmt::Write, iter, mem, ops::Range}; use base_db::{CrateId, FileId}; use chalk_ir::{cast::Cast, Mutability}; @@ -40,8 +33,8 @@ use crate::{ name, static_lifetime, traits::FnTrait, utils::{detect_variant_from_bytes, ClosureSubst}, - CallableDefId, ClosureId, Const, ConstScalar, FnDefId, Interner, MemoryMap, Substitution, - TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, + CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstScalar, FnDefId, Interner, MemoryMap, + Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, }; use super::{ @@ -98,6 +91,15 @@ impl VTableMap { let id = from_bytes!(usize, bytes); self.ty(id) } + + pub fn shrink_to_fit(&mut self) { + self.id_to_ty.shrink_to_fit(); + self.ty_to_id.shrink_to_fit(); + } + + fn is_empty(&self) -> bool { + self.id_to_ty.is_empty() && self.ty_to_id.is_empty() + } } #[derive(Debug, Default, Clone, PartialEq, Eq)] @@ -251,13 +253,6 @@ impl From for IntervalOrOwned { } impl IntervalOrOwned { - pub(crate) fn to_vec(self, memory: &Evaluator<'_>) -> Result> { - Ok(match self { - IntervalOrOwned::Owned(o) => o, - IntervalOrOwned::Borrowed(b) => b.get(memory)?.to_vec(), - }) - } - fn get<'a>(&'a self, memory: &'a Evaluator<'a>) -> Result<&'a [u8]> { Ok(match self { IntervalOrOwned::Owned(o) => o, @@ -291,8 +286,8 @@ impl Address { } } - fn to_bytes(&self) -> Vec { - usize::to_le_bytes(self.to_usize()).to_vec() + fn to_bytes(&self) -> [u8; mem::size_of::()] { + usize::to_le_bytes(self.to_usize()) } fn to_usize(&self) -> usize { @@ -391,7 +386,7 @@ impl MirEvalError { write!( f, "Layout for type `{}` is not available due {err:?}", - ty.display(db).with_closure_style(ClosureStyle::ClosureWithId).to_string() + ty.display(db).with_closure_style(ClosureStyle::ClosureWithId) )?; } MirEvalError::MirLowerError(func, err) => { @@ -510,6 +505,20 @@ struct Locals { drop_flags: DropFlags, } +pub struct MirOutput { + stdout: Vec, + stderr: Vec, +} + +impl MirOutput { + pub fn stdout(&self) -> Cow<'_, str> { + String::from_utf8_lossy(&self.stdout) + } + pub fn stderr(&self) -> Cow<'_, str> { + String::from_utf8_lossy(&self.stderr) + } +} + pub fn interpret_mir( db: &dyn HirDatabase, body: Arc, @@ -520,27 +529,31 @@ pub fn interpret_mir( // (and probably should) do better here, for example by excluding bindings outside of the target expression. assert_placeholder_ty_is_unused: bool, trait_env: Option>, -) -> (Result, String, String) { +) -> (Result, MirOutput) { let ty = body.locals[return_slot()].ty.clone(); let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env); let it: Result = (|| { if evaluator.ptr_size() != std::mem::size_of::() { not_supported!("targets with different pointer size from host"); } - let bytes = evaluator.interpret_mir(body.clone(), None.into_iter())?; + let interval = evaluator.interpret_mir(body.clone(), None.into_iter())?; + let bytes = interval.get(&evaluator)?; let mut memory_map = evaluator.create_memory_map( - &bytes, + bytes, &ty, &Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() }, )?; - memory_map.vtable = evaluator.vtable_map.clone(); + let bytes = bytes.into(); + let memory_map = if memory_map.memory.is_empty() && evaluator.vtable_map.is_empty() { + MemoryMap::Empty + } else { + memory_map.vtable = mem::take(&mut evaluator.vtable_map); + memory_map.vtable.shrink_to_fit(); + MemoryMap::Complex(Box::new(memory_map)) + }; return Ok(intern_const_scalar(ConstScalar::Bytes(bytes, memory_map), ty)); })(); - ( - it, - String::from_utf8_lossy(&evaluator.stdout).into_owned(), - String::from_utf8_lossy(&evaluator.stderr).into_owned(), - ) + (it, MirOutput { stdout: evaluator.stdout, stderr: evaluator.stderr }) } #[cfg(test)] @@ -562,7 +575,7 @@ impl Evaluator<'_> { code_stack: vec![], vtable_map: VTableMap::default(), thread_local_storage: TlsData::default(), - static_locations: HashMap::default(), + static_locations: Default::default(), db, random_state: oorandom::Rand64::new(0), trait_env: trait_env.unwrap_or_else(|| db.trait_environment_for_body(owner)), @@ -573,11 +586,11 @@ impl Evaluator<'_> { stack_depth_limit: 100, execution_limit: EXECUTION_LIMIT, memory_limit: 1000_000_000, // 2GB, 1GB for stack and 1GB for heap - layout_cache: RefCell::new(HashMap::default()), - projected_ty_cache: RefCell::new(HashMap::default()), - not_special_fn_cache: RefCell::new(HashSet::default()), - mir_or_dyn_index_cache: RefCell::new(HashMap::default()), - unused_locals_store: RefCell::new(HashMap::default()), + layout_cache: RefCell::new(Default::default()), + projected_ty_cache: RefCell::new(Default::default()), + not_special_fn_cache: RefCell::new(Default::default()), + mir_or_dyn_index_cache: RefCell::new(Default::default()), + unused_locals_store: RefCell::new(Default::default()), cached_ptr_size: match db.target_data_layout(crate_id) { Some(it) => it.pointer_size.bytes_usize(), None => 8, @@ -720,13 +733,19 @@ impl Evaluator<'_> { self.size_of_sized(&inner_ty, locals, "array inner type should be sized")?; addr = addr.offset(ty_size * (from as usize)); } - &ProjectionElem::TupleOrClosureField(f) => { + &ProjectionElem::ClosureField(f) => { let layout = self.layout(&prev_ty)?; let offset = layout.fields.offset(f).bytes_usize(); addr = addr.offset(offset); - metadata = None; // tuple field is always sized + metadata = None; } - ProjectionElem::Field(f) => { + ProjectionElem::Field(Either::Right(f)) => { + let layout = self.layout(&prev_ty)?; + let offset = layout.fields.offset(f.index as usize).bytes_usize(); + addr = addr.offset(offset); + metadata = None; // tuple field is always sized FIXME: This is wrong, the tail can be unsized + } + ProjectionElem::Field(Either::Left(f)) => { let layout = self.layout(&prev_ty)?; let variant_layout = match &layout.variants { Variants::Single { .. } => &layout, @@ -797,11 +816,11 @@ impl Evaluator<'_> { }) } - fn interpret_mir( - &mut self, + fn interpret_mir<'slf>( + &'slf mut self, body: Arc, args: impl Iterator, - ) -> Result> { + ) -> Result { if let Some(it) = self.stack_depth_limit.checked_sub(1) { self.stack_depth_limit = it; } else { @@ -831,8 +850,8 @@ impl Evaluator<'_> { match &statement.kind { StatementKind::Assign(l, r) => { let addr = self.place_addr(l, &locals)?; - let result = self.eval_rvalue(r, &mut locals)?.to_vec(&self)?; - self.write_memory(addr, &result)?; + let result = self.eval_rvalue(r, &mut locals)?; + self.copy_from_interval_or_owned(addr, result)?; locals .drop_flags .add_place(l.clone(), &locals.body.projection_store); @@ -951,7 +970,7 @@ impl Evaluator<'_> { None => { self.code_stack = prev_code_stack; self.stack_depth_limit += 1; - return Ok(return_interval.get(self)?.to_vec()); + return Ok(return_interval); } Some(bb) => { // We don't support const promotion, so we can't truncate the stack yet. @@ -1044,7 +1063,7 @@ impl Evaluator<'_> { Rvalue::Use(it) => Borrowed(self.eval_operand(it, locals)?), Rvalue::Ref(_, p) => { let (addr, _, metadata) = self.place_addr_and_ty_and_metadata(p, locals)?; - let mut r = addr.to_bytes(); + let mut r = addr.to_bytes().to_vec(); if let Some(metadata) = metadata { r.extend(metadata.get(self)?); } @@ -1277,7 +1296,7 @@ impl Evaluator<'_> { not_supported!("unsized box initialization"); }; let addr = self.heap_allocate(size, align)?; - Owned(addr.to_bytes()) + Owned(addr.to_bytes().to_vec()) } Rvalue::CopyForDeref(_) => not_supported!("copy for deref"), Rvalue::Aggregate(kind, values) => { @@ -1514,7 +1533,7 @@ impl Evaluator<'_> { } }, TyKind::Dyn(_) => { - let vtable = self.vtable_map.id(current_ty.clone()); + let vtable = self.vtable_map.id(current_ty); let mut r = Vec::with_capacity(16); let addr = addr.get(self)?; r.extend(addr.iter().copied()); @@ -1709,7 +1728,18 @@ impl Evaluator<'_> { } let addr = self.heap_allocate(size, align)?; self.write_memory(addr, &v)?; - self.patch_addresses(&patch_map, &memory_map.vtable, addr, ty, locals)?; + self.patch_addresses( + &patch_map, + |bytes| match &memory_map { + MemoryMap::Empty | MemoryMap::Simple(_) => { + Err(MirEvalError::InvalidVTableId(from_bytes!(usize, bytes))) + } + MemoryMap::Complex(cm) => cm.vtable.ty_of_bytes(bytes), + }, + addr, + ty, + locals, + )?; Ok(Interval::new(addr, size)) } @@ -1761,6 +1791,13 @@ impl Evaluator<'_> { Ok(()) } + fn copy_from_interval_or_owned(&mut self, addr: Address, r: IntervalOrOwned) -> Result<()> { + match r { + IntervalOrOwned::Borrowed(r) => self.copy_from_interval(addr, r), + IntervalOrOwned::Owned(r) => self.write_memory(addr, &r), + } + } + fn copy_from_interval(&mut self, addr: Address, r: Interval) -> Result<()> { if r.size == 0 { return Ok(()); @@ -1881,13 +1918,18 @@ impl Evaluator<'_> { } } - fn create_memory_map(&self, bytes: &[u8], ty: &Ty, locals: &Locals) -> Result { + fn create_memory_map( + &self, + bytes: &[u8], + ty: &Ty, + locals: &Locals, + ) -> Result { fn rec( this: &Evaluator<'_>, bytes: &[u8], ty: &Ty, locals: &Locals, - mm: &mut MemoryMap, + mm: &mut ComplexMemoryMap, ) -> Result<()> { match ty.kind(Interner) { TyKind::Ref(_, _, t) => { @@ -1897,7 +1939,7 @@ impl Evaluator<'_> { let addr_usize = from_bytes!(usize, bytes); mm.insert( addr_usize, - this.read_memory(Address::from_usize(addr_usize), size)?.to_vec(), + this.read_memory(Address::from_usize(addr_usize), size)?.into(), ) } None => { @@ -1923,7 +1965,7 @@ impl Evaluator<'_> { let size = element_size * count; let addr = Address::from_bytes(addr)?; let b = this.read_memory(addr, size)?; - mm.insert(addr.to_usize(), b.to_vec()); + mm.insert(addr.to_usize(), b.into()); if let Some(ty) = check_inner { for i in 0..count { let offset = element_size * i; @@ -1996,15 +2038,15 @@ impl Evaluator<'_> { } Ok(()) } - let mut mm = MemoryMap::default(); - rec(self, bytes, ty, locals, &mut mm)?; + let mut mm = ComplexMemoryMap::default(); + rec(&self, bytes, ty, locals, &mut mm)?; Ok(mm) } - fn patch_addresses( + fn patch_addresses<'vtable>( &mut self, - patch_map: &HashMap, - old_vtable: &VTableMap, + patch_map: &FxHashMap, + ty_of_bytes: impl Fn(&[u8]) -> Result<&'vtable Ty> + Copy, addr: Address, ty: &Ty, locals: &Locals, @@ -2031,7 +2073,7 @@ impl Evaluator<'_> { } } TyKind::Function(_) => { - let ty = old_vtable.ty_of_bytes(self.read_memory(addr, my_size)?)?.clone(); + let ty = ty_of_bytes(self.read_memory(addr, my_size)?)?.clone(); let new_id = self.vtable_map.id(ty); self.write_memory(addr, &new_id.to_le_bytes())?; } @@ -2042,7 +2084,7 @@ impl Evaluator<'_> { let ty = ty.clone().substitute(Interner, subst); self.patch_addresses( patch_map, - old_vtable, + ty_of_bytes, addr.offset(offset), &ty, locals, @@ -2064,7 +2106,7 @@ impl Evaluator<'_> { let ty = ty.clone().substitute(Interner, subst); self.patch_addresses( patch_map, - old_vtable, + ty_of_bytes, addr.offset(offset), &ty, locals, @@ -2077,7 +2119,7 @@ impl Evaluator<'_> { for (id, ty) in subst.iter(Interner).enumerate() { let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument let offset = layout.fields.offset(id).bytes_usize(); - self.patch_addresses(patch_map, old_vtable, addr.offset(offset), ty, locals)?; + self.patch_addresses(patch_map, ty_of_bytes, addr.offset(offset), ty, locals)?; } } TyKind::Array(inner, len) => { @@ -2089,7 +2131,7 @@ impl Evaluator<'_> { for i in 0..len { self.patch_addresses( patch_map, - old_vtable, + ty_of_bytes, addr.offset(i * size), inner, locals, @@ -2160,14 +2202,14 @@ impl Evaluator<'_> { .map_err(|it| MirEvalError::MirLowerErrorForClosure(closure, it))?; let closure_data = if mir_body.locals[mir_body.param_locals[0]].ty.as_reference().is_some() { - closure_data.addr.to_bytes() + closure_data.addr.to_bytes().to_vec() } else { closure_data.get(self)?.to_owned() }; let arg_bytes = iter::once(Ok(closure_data)) .chain(args.iter().map(|it| Ok(it.get(&self)?.to_owned()))) .collect::>>()?; - let bytes = self + let interval = self .interpret_mir(mir_body, arg_bytes.into_iter().map(IntervalOrOwned::Owned)) .map_err(|e| { MirEvalError::InFunction( @@ -2175,7 +2217,7 @@ impl Evaluator<'_> { vec![(Either::Right(closure), span, locals.body.owner)], ) })?; - destination.write_from_bytes(self, &bytes)?; + destination.write_from_interval(self, interval)?; Ok(None) } @@ -2368,7 +2410,7 @@ impl Evaluator<'_> { vec![(Either::Left(def), span, locals.body.owner)], ) })?; - destination.write_from_bytes(self, &result)?; + destination.write_from_interval(self, result)?; None }) } @@ -2546,7 +2588,7 @@ impl Evaluator<'_> { body, locals, drop_fn, - [IntervalOrOwned::Owned(addr.to_bytes())].into_iter(), + iter::once(IntervalOrOwned::Owned(addr.to_bytes().to_vec())), span, Interval { addr: Address::Invalid(0), size: 0 }, None, @@ -2674,11 +2716,12 @@ pub fn render_const_using_debug_impl( ) else { not_supported!("std::fmt::format not found"); }; - let message_string = evaluator.interpret_mir( + let interval = evaluator.interpret_mir( db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?, [IntervalOrOwned::Borrowed(Interval { addr: a3, size: evaluator.ptr_size() * 6 })] .into_iter(), )?; + let message_string = interval.get(&evaluator)?; let addr = Address::from_bytes(&message_string[evaluator.ptr_size()..2 * evaluator.ptr_size()])?; let size = from_bytes!(usize, message_string[2 * evaluator.ptr_size()..]); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 2de99e41659c..ff26a3d0be17 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -322,12 +322,13 @@ impl Evaluator<'_> { let hir_def::resolver::ValueNs::FunctionId(format_fn) = format_fn else { not_supported!("std::fmt::format is not a function") }; - let message_string = self.interpret_mir( + let interval = self.interpret_mir( self.db .mir_body(format_fn.into()) .map_err(|e| MirEvalError::MirLowerError(format_fn, e))?, args.map(|x| IntervalOrOwned::Owned(x.clone())), )?; + let message_string = interval.get(self)?; let addr = Address::from_bytes(&message_string[self.ptr_size()..2 * self.ptr_size()])?; let size = from_bytes!(usize, message_string[2 * self.ptr_size()..]); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index b0f929279a5c..6552bf493377 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -31,9 +31,9 @@ fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalEr db.trait_environment(func_id.into()), ) .map_err(|e| MirEvalError::MirLowerError(func_id.into(), e))?; - let (result, stdout, stderr) = interpret_mir(db, body, false, None); + let (result, output) = interpret_mir(db, body, false, None); result?; - Ok((stdout, stderr)) + Ok((output.stdout().into_owned(), output.stderr().into_owned())) } fn check_pass(ra_fixture: &str) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 639fabc198c1..c02c5ef8767f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -15,7 +15,7 @@ use hir_def::{ path::Path, resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs}, AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId, - Lookup, TraitId, TypeOrConstParamId, + Lookup, TraitId, TupleId, TypeOrConstParamId, }; use hir_expand::name::Name; use la_arena::ArenaMap; @@ -177,7 +177,7 @@ impl MirLowerError { )?; writeln!(f, "Provided args: [")?; for g in subst.iter(Interner) { - write!(f, " {},", g.display(db).to_string())?; + write!(f, " {},", g.display(db))?; } writeln!(f, "]")?; } @@ -540,7 +540,7 @@ impl<'ctx> MirLowerCtx<'ctx> { self.write_bytes_to_place( then_target, place.clone(), - vec![1], + Box::new([1]), TyBuilder::bool(), MirSpan::Unknown, )?; @@ -548,7 +548,7 @@ impl<'ctx> MirLowerCtx<'ctx> { self.write_bytes_to_place( else_target, place, - vec![0], + Box::new([0]), TyBuilder::bool(), MirSpan::Unknown, )?; @@ -602,7 +602,7 @@ impl<'ctx> MirLowerCtx<'ctx> { generic_args, ) .intern(Interner); - let func = Operand::from_bytes(vec![], ty); + let func = Operand::from_bytes(Box::default(), ty); return self.lower_call_and_args( func, iter::once(*callee).chain(args.iter().copied()), @@ -615,7 +615,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let callee_ty = self.expr_ty_after_adjustments(*callee); match &callee_ty.kind(Interner) { chalk_ir::TyKind::FnDef(..) => { - let func = Operand::from_bytes(vec![], callee_ty.clone()); + let func = Operand::from_bytes(Box::default(), callee_ty.clone()); self.lower_call_and_args( func, args.iter().copied(), @@ -828,12 +828,12 @@ impl<'ctx> MirLowerCtx<'ctx> { Some(it) => it, None => { let p = sp.project( - ProjectionElem::Field(FieldId { + ProjectionElem::Field(Either::Left(FieldId { parent: variant_id, local_id: LocalFieldId::from_raw(RawIdx::from( i as u32, )), - }), + })), &mut self.result.projection_store, ); Operand::Copy(p) @@ -855,7 +855,10 @@ impl<'ctx> MirLowerCtx<'ctx> { let local_id = variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?; let place = place.project( - PlaceElem::Field(FieldId { parent: union_id.into(), local_id }), + PlaceElem::Field(Either::Left(FieldId { + parent: union_id.into(), + local_id, + })), &mut self.result.projection_store, ); self.lower_expr_to_place(*expr, place, current) @@ -1110,7 +1113,7 @@ impl<'ctx> MirLowerCtx<'ctx> { Some("start") => lp.take(), Some("end") => rp.take(), Some("exhausted") => { - Some(Operand::from_bytes(vec![0], TyBuilder::bool())) + Some(Operand::from_bytes(Box::new([0]), TyBuilder::bool())) } _ => None, }; @@ -1142,8 +1145,8 @@ impl<'ctx> MirLowerCtx<'ctx> { .map(|it| match it { ProjectionElem::Deref => ProjectionElem::Deref, ProjectionElem::Field(it) => ProjectionElem::Field(it), - ProjectionElem::TupleOrClosureField(it) => { - ProjectionElem::TupleOrClosureField(it) + ProjectionElem::ClosureField(it) => { + ProjectionElem::ClosureField(it) } ProjectionElem::ConstantIndex { offset, from_end } => { ProjectionElem::ConstantIndex { offset, from_end } @@ -1273,7 +1276,10 @@ impl<'ctx> MirLowerCtx<'ctx> { Expr::Tuple { exprs, is_assignee_expr: _ } => { for (i, expr) in exprs.iter().enumerate() { let rhs = rhs.project( - ProjectionElem::TupleOrClosureField(i), + ProjectionElem::Field(Either::Right(TupleFieldId { + tuple: TupleId(!0), // Dummy this as its unused + index: i as u32, + })), &mut self.result.projection_store, ); let Some(c) = self.lower_destructing_assignment(current, *expr, rhs, span)? @@ -1337,11 +1343,14 @@ impl<'ctx> MirLowerCtx<'ctx> { fn push_field_projection(&mut self, place: &mut Place, expr_id: ExprId) -> Result<()> { if let Expr::Field { expr, name } = &self.body[expr_id] { if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind(Interner) { - let index = name - .as_tuple_index() - .ok_or(MirLowerError::TypeError("named field on tuple"))?; + let index = + name.as_tuple_index().ok_or(MirLowerError::TypeError("named field on tuple"))? + as u32; *place = place.project( - ProjectionElem::TupleOrClosureField(index), + ProjectionElem::Field(Either::Right(TupleFieldId { + tuple: TupleId(!0), // dummy as its unused + index, + })), &mut self.result.projection_store, ) } else { @@ -1386,46 +1395,43 @@ impl<'ctx> MirLowerCtx<'ctx> { } fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result { - let size = self - .db - .layout_of_ty(ty.clone(), self.db.trait_environment_for_body(self.owner))? - .size - .bytes_usize(); - let bytes = match l { + let size = || { + self.db + .layout_of_ty(ty.clone(), self.db.trait_environment_for_body(self.owner)) + .map(|it| it.size.bytes_usize()) + }; + const USIZE_SIZE: usize = mem::size_of::(); + let bytes: Box<[_]> = match l { hir_def::hir::Literal::String(b) => { - let b = b.as_bytes(); - let mut data = Vec::with_capacity(mem::size_of::() * 2); - data.extend(0usize.to_le_bytes()); - data.extend(b.len().to_le_bytes()); - let mut mm = MemoryMap::default(); - mm.insert(0, b.to_vec()); - return Ok(Operand::from_concrete_const(data, mm, ty)); + let mut data = [0; { 2 * USIZE_SIZE }]; + data[..USIZE_SIZE].copy_from_slice(&0usize.to_le_bytes()); + data[USIZE_SIZE..].copy_from_slice(&b.len().to_le_bytes()); + let mm = MemoryMap::simple(b.as_bytes().into()); + return Ok(Operand::from_concrete_const(Box::new(data), mm, ty)); } hir_def::hir::Literal::CString(b) => { - let bytes = b.iter().copied().chain(iter::once(0)).collect::>(); + let bytes = b.iter().copied().chain(iter::once(0)).collect::>(); - let mut data = Vec::with_capacity(mem::size_of::() * 2); - data.extend(0usize.to_le_bytes()); - data.extend(bytes.len().to_le_bytes()); - let mut mm = MemoryMap::default(); - mm.insert(0, bytes); - return Ok(Operand::from_concrete_const(data, mm, ty)); + let mut data = [0; { 2 * USIZE_SIZE }]; + data[..USIZE_SIZE].copy_from_slice(&0usize.to_le_bytes()); + data[USIZE_SIZE..].copy_from_slice(&bytes.len().to_le_bytes()); + let mm = MemoryMap::simple(bytes); + return Ok(Operand::from_concrete_const(Box::new(data), mm, ty)); } hir_def::hir::Literal::ByteString(b) => { - let mut data = Vec::with_capacity(mem::size_of::() * 2); - data.extend(0usize.to_le_bytes()); - data.extend(b.len().to_le_bytes()); - let mut mm = MemoryMap::default(); - mm.insert(0, b.to_vec()); - return Ok(Operand::from_concrete_const(data, mm, ty)); + let mut data = [0; { 2 * USIZE_SIZE }]; + data[..USIZE_SIZE].copy_from_slice(&0usize.to_le_bytes()); + data[USIZE_SIZE..].copy_from_slice(&b.len().to_le_bytes()); + let mm = MemoryMap::simple(b.clone()); + return Ok(Operand::from_concrete_const(Box::new(data), mm, ty)); } - hir_def::hir::Literal::Char(c) => u32::from(*c).to_le_bytes().into(), - hir_def::hir::Literal::Bool(b) => vec![*b as u8], - hir_def::hir::Literal::Int(it, _) => it.to_le_bytes()[0..size].into(), - hir_def::hir::Literal::Uint(it, _) => it.to_le_bytes()[0..size].into(), - hir_def::hir::Literal::Float(f, _) => match size { - 8 => f.into_f64().to_le_bytes().into(), - 4 => f.into_f32().to_le_bytes().into(), + hir_def::hir::Literal::Char(c) => Box::new(u32::from(*c).to_le_bytes()), + hir_def::hir::Literal::Bool(b) => Box::new([*b as u8]), + hir_def::hir::Literal::Int(it, _) => Box::from(&it.to_le_bytes()[0..size()?]), + hir_def::hir::Literal::Uint(it, _) => Box::from(&it.to_le_bytes()[0..size()?]), + hir_def::hir::Literal::Float(f, _) => match size()? { + 8 => Box::new(f.into_f64().to_le_bytes()), + 4 => Box::new(f.into_f32().to_le_bytes()), _ => { return Err(MirLowerError::TypeError("float with size other than 4 or 8 bytes")) } @@ -1474,7 +1480,7 @@ impl<'ctx> MirLowerCtx<'ctx> { &mut self, prev_block: BasicBlockId, place: Place, - cv: Vec, + cv: Box<[u8]>, ty: Ty, span: MirSpan, ) -> Result<()> { @@ -2041,10 +2047,11 @@ pub fn mir_body_for_closure_query( match (it, y) { (ProjectionElem::Deref, ProjectionElem::Deref) => (), (ProjectionElem::Field(it), ProjectionElem::Field(y)) if it == y => (), - ( - ProjectionElem::TupleOrClosureField(it), - ProjectionElem::TupleOrClosureField(y), - ) if it == y => (), + (ProjectionElem::ClosureField(it), ProjectionElem::ClosureField(y)) + if it == y => + { + () + } _ => return false, } } @@ -2054,7 +2061,7 @@ pub fn mir_body_for_closure_query( Some(it) => { p.local = closure_local; let mut next_projs = closure_projection.clone(); - next_projs.push(PlaceElem::TupleOrClosureField(it.1)); + next_projs.push(PlaceElem::ClosureField(it.1)); let prev_projs = p.projection; if it.0.kind != CaptureKind::ByValue { next_projs.push(ProjectionElem::Deref); @@ -2063,8 +2070,8 @@ pub fn mir_body_for_closure_query( prev_projs .lookup(&store) .iter() - .cloned() - .skip(it.0.place.projections.len()), + .skip(it.0.place.projections.len()) + .cloned(), ); p.projection = store.intern(next_projs.into()); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs index 8c078eb4ad75..cb5588a5c13d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs @@ -218,7 +218,7 @@ impl MirLowerCtx<'_> { self.push_field_projection(&mut r, expr_id)?; Ok(Some((r, current))) } - Expr::Index { base, index } => { + Expr::Index { base, index, is_assignee_expr: _ } => { let base_ty = self.expr_ty_after_adjustments(*base); let index_ty = self.expr_ty_after_adjustments(*index); if index_ty != TyBuilder::usize() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index 1120bb1c1123..98c2e7c63bc1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -108,7 +108,12 @@ impl MirLowerCtx<'_> { current_else, args, *ellipsis, - (0..subst.len(Interner)).map(|i| PlaceElem::TupleOrClosureField(i)), + (0..subst.len(Interner)).map(|i| { + PlaceElem::Field(Either::Right(TupleFieldId { + tuple: TupleId(!0), // Dummy as it is unused + index: i as u32, + })) + }), &(&mut cond_place), mode, )? @@ -239,7 +244,7 @@ impl MirLowerCtx<'_> { ); } else { let c = Operand::from_concrete_const( - pattern_len.to_le_bytes().to_vec(), + pattern_len.to_le_bytes().into(), MemoryMap::default(), TyBuilder::usize(), ); @@ -566,7 +571,10 @@ impl MirLowerCtx<'_> { let field_id = variant_data.field(&x.name).ok_or(MirLowerError::UnresolvedField)?; Ok(( - PlaceElem::Field(FieldId { parent: v.into(), local_id: field_id }), + PlaceElem::Field(Either::Left(FieldId { + parent: v.into(), + local_id: field_id, + })), x.pat, )) }) @@ -574,10 +582,9 @@ impl MirLowerCtx<'_> { self.pattern_match_adt(current, current_else, it.into_iter(), cond_place, mode)? } AdtPatternShape::Tuple { args, ellipsis } => { - let fields = variant_data - .fields() - .iter() - .map(|(x, _)| PlaceElem::Field(FieldId { parent: v.into(), local_id: x })); + let fields = variant_data.fields().iter().map(|(x, _)| { + PlaceElem::Field(Either::Left(FieldId { parent: v.into(), local_id: x })) + }); self.pattern_match_tuple_like( current, current_else, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs index a91f90bc249e..366c2f662b54 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs @@ -5,6 +5,7 @@ use std::{ mem, }; +use either::Either; use hir_def::{body::Body, hir::BindingId}; use hir_expand::name::Name; use la_arena::ArenaMap; @@ -298,7 +299,7 @@ impl<'a> MirPrettyCtx<'a> { f(this, local, head); w!(this, ")"); } - ProjectionElem::Field(field) => { + ProjectionElem::Field(Either::Left(field)) => { let variant_data = field.parent.variant_data(this.db.upcast()); let name = &variant_data.fields()[field.local_id].name; match field.parent { @@ -320,7 +321,11 @@ impl<'a> MirPrettyCtx<'a> { } } } - ProjectionElem::TupleOrClosureField(it) => { + ProjectionElem::Field(Either::Right(field)) => { + f(this, local, head); + w!(this, ".{}", field.index); + } + ProjectionElem::ClosureField(it) => { f(this, local, head); w!(this, ".{}", it); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 003ae60e8e51..d270328605a9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -4506,3 +4506,50 @@ fn ttt() { "#, ); } + +#[test] +fn infer_borrow() { + check_types( + r#" +//- minicore: index +pub struct SomeMap; + +pub trait Borrow { + fn borrow(&self) -> &Borrowed; +} + +impl Borrow for T { + fn borrow(&self) -> &T { + self + } +} + +impl Borrow for &T { + fn borrow(&self) -> &T { + &**self + } +} + +impl> core::ops::Index for SomeMap { + type Output = (); + + fn index(&self, _: KB) -> &() { + &() + } +} + +impl core::ops::IndexMut for SomeMap { + fn index_mut(&mut self, _: K) -> &mut () { + &mut () + } +} + +fn foo() { + let mut map = SomeMap; + map["a"] = (); + map; + //^^^ SomeMap<&str> +} +"#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index d60d20f5b7ee..60ddc4aa86fe 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -1,5 +1,7 @@ //! Attributes & documentation for hir types. +use std::ops::ControlFlow; + use base_db::FileId; use hir_def::{ attr::AttrsWithOwner, @@ -13,13 +15,13 @@ use hir_expand::{ name::Name, span_map::{RealSpanMap, SpanMapRef}, }; -use hir_ty::db::HirDatabase; +use hir_ty::{db::HirDatabase, method_resolution}; use syntax::{ast, AstNode}; use crate::{ Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl, - Field, Function, GenericParam, Impl, LifetimeParam, Macro, Module, ModuleDef, Static, Struct, - Trait, TraitAlias, TypeAlias, TypeParam, Union, Variant, VariantDef, + Field, Function, GenericParam, HasCrate, Impl, LifetimeParam, Macro, Module, ModuleDef, Static, + Struct, Trait, TraitAlias, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, }; pub trait HasAttrs { @@ -99,9 +101,6 @@ pub fn resolve_doc_path_on( link: &str, ns: Option, ) -> Option { - // AttrDefId::FieldId(it) => it.parent.resolver(db.upcast()), - // AttrDefId::EnumVariantId(it) => it.parent.resolver(db.upcast()), - resolve_doc_path_on_(db, link, def.attr_id(), ns) } @@ -205,8 +204,14 @@ fn resolve_assoc_or_field( } }; - // FIXME: Resolve associated items here, e.g. `Option::map`. Note that associated items take - // precedence over fields. + // Resolve inherent items first, then trait items, then fields. + if let Some(assoc_item_def) = resolve_assoc_item(db, &ty, &name, ns) { + return Some(assoc_item_def); + } + + if let Some(impl_trait_item_def) = resolve_impl_trait_item(db, resolver, &ty, &name, ns) { + return Some(impl_trait_item_def); + } let variant_def = match ty.as_adt()? { Adt::Struct(it) => it.into(), @@ -216,6 +221,65 @@ fn resolve_assoc_or_field( resolve_field(db, variant_def, name, ns) } +fn resolve_assoc_item( + db: &dyn HirDatabase, + ty: &Type, + name: &Name, + ns: Option, +) -> Option { + ty.iterate_assoc_items(db, ty.krate(db), move |assoc_item| { + if assoc_item.name(db)? != *name { + return None; + } + as_module_def_if_namespace_matches(assoc_item, ns) + }) +} + +fn resolve_impl_trait_item( + db: &dyn HirDatabase, + resolver: Resolver, + ty: &Type, + name: &Name, + ns: Option, +) -> Option { + let canonical = ty.canonical(); + let krate = ty.krate(db); + let environment = resolver.generic_def().map_or_else( + || crate::TraitEnvironment::empty(krate.id).into(), + |d| db.trait_environment(d), + ); + let traits_in_scope = resolver.traits_in_scope(db.upcast()); + + let mut result = None; + + // `ty.iterate_path_candidates()` require a scope, which is not available when resolving + // attributes here. Use path resolution directly instead. + // + // FIXME: resolve type aliases (which are not yielded by iterate_path_candidates) + method_resolution::iterate_path_candidates( + &canonical, + db, + environment, + &traits_in_scope, + method_resolution::VisibleFromModule::None, + Some(name), + &mut |assoc_item_id| { + // If two traits in scope define the same item, Rustdoc links to no specific trait (for + // instance, given two methods `a`, Rustdoc simply links to `method.a` with no + // disambiguation) so we just pick the first one we find as well. + result = as_module_def_if_namespace_matches(assoc_item_id.into(), ns); + + if result.is_some() { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }, + ); + + result +} + fn resolve_field( db: &dyn HirDatabase, def: VariantDef, @@ -228,6 +292,19 @@ fn resolve_field( def.fields(db).into_iter().find(|f| f.name(db) == name).map(DocLinkDef::Field) } +fn as_module_def_if_namespace_matches( + assoc_item: AssocItem, + ns: Option, +) -> Option { + let (def, expected_ns) = match assoc_item { + AssocItem::Function(it) => (ModuleDef::Function(it), Namespace::Values), + AssocItem::Const(it) => (ModuleDef::Const(it), Namespace::Values), + AssocItem::TypeAlias(it) => (ModuleDef::TypeAlias(it), Namespace::Types), + }; + + (ns.unwrap_or(expected_ns) == expected_ns).then(|| DocLinkDef::ModuleDef(def)) +} + fn modpath_from_str(db: &dyn HirDatabase, link: &str) -> Option { // FIXME: this is not how we should get a mod path here. let try_get_modpath = |link: &str| { diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 5847c8a9fb52..9b99b141fc5e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -19,8 +19,8 @@ use hir_ty::{ use crate::{ Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, LifetimeParam, Macro, Module, SelfParam, - Static, Struct, Trait, TraitAlias, TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, - Union, Variant, + Static, Struct, Trait, TraitAlias, TupleField, TyBuilder, Type, TypeAlias, TypeOrConstParam, + TypeParam, Union, Variant, }; impl HirDisplay for Function { @@ -257,6 +257,13 @@ impl HirDisplay for Field { } } +impl HirDisplay for TupleField { + fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + write!(f, "pub {}: ", self.name().display(f.db.upcast()))?; + self.ty(f.db).hir_fmt(f) + } +} + impl HirDisplay for Variant { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 09b56e138241..0266915c39b6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -55,7 +55,7 @@ use hir_def::{ AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, - Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, + Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, }; use hir_expand::{attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, MacroCallKind}; @@ -1038,6 +1038,29 @@ pub struct Field { pub(crate) id: LocalFieldId, } +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +pub struct TupleField { + pub owner: DefWithBodyId, + pub tuple: TupleId, + pub index: u32, +} + +impl TupleField { + pub fn name(&self) -> Name { + Name::new_tuple_field(self.index as usize) + } + + pub fn ty(&self, db: &dyn HirDatabase) -> Type { + let ty = db.infer(self.owner).tuple_field_access_types[&self.tuple] + .as_slice(Interner) + .get(self.index as usize) + .and_then(|arg| arg.ty(Interner)) + .cloned() + .unwrap_or_else(|| TyKind::Error.intern(Interner)); + Type { env: db.trait_environment_for_body(self.owner), ty } + } +} + #[derive(Debug, PartialEq, Eq)] pub enum FieldSource { Named(ast::RecordField), @@ -1070,7 +1093,7 @@ impl Field { pub fn layout(&self, db: &dyn HirDatabase) -> Result { db.layout_of_ty( - self.ty(db).ty.clone(), + self.ty(db).ty, db.trait_environment(match hir_def::VariantId::from(self.parent) { hir_def::VariantId::EnumVariantId(id) => GenericDefId::EnumVariantId(id), hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()), @@ -1831,7 +1854,7 @@ impl DefWithBody { let local = Local { parent: self.into(), binding_id }; match (need_mut, local.is_mut(db)) { (mir::MutabilityReason::Unused, _) => { - let should_ignore = matches!(body[binding_id].name.as_str(), Some(it) if it.starts_with("_")); + let should_ignore = matches!(body[binding_id].name.as_str(), Some(it) if it.starts_with('_')); if !should_ignore { acc.push(UnusedVariable { local }.into()) } @@ -1856,7 +1879,7 @@ impl DefWithBody { } (mir::MutabilityReason::Not, true) => { if !infer.mutated_bindings_in_closure.contains(&binding_id) { - let should_ignore = matches!(body[binding_id].name.as_str(), Some(it) if it.starts_with("_")); + let should_ignore = matches!(body[binding_id].name.as_str(), Some(it) if it.starts_with('_')); if !should_ignore { acc.push(UnusedMut { local }.into()) } @@ -2160,7 +2183,7 @@ impl Function { return r; } }; - let (result, stdout, stderr) = interpret_mir(db, body, false, None); + let (result, output) = interpret_mir(db, body, false, None); let mut text = match result { Ok(_) => "pass".to_string(), Err(e) => { @@ -2169,10 +2192,12 @@ impl Function { r } }; + let stdout = output.stdout().into_owned(); if !stdout.is_empty() { text += "\n--------- stdout ---------\n"; text += &stdout; } + let stderr = output.stdout().into_owned(); if !stderr.is_empty() { text += "\n--------- stderr ---------\n"; text += &stderr; @@ -3648,7 +3673,6 @@ impl Closure { let (captures, _) = infer.closure_info(&self.id); captures .iter() - .cloned() .map(|capture| Type { env: db.trait_environment_for_body(owner), ty: capture.ty(&self.subst), @@ -4121,6 +4145,10 @@ impl Type { } } + pub(crate) fn canonical(&self) -> Canonical { + hir_ty::replace_errors_with_variables(&self.ty) + } + /// Returns types that this type dereferences to (including this type itself). The returned /// iterator won't yield the same type more than once even if the deref chain contains a cycle. pub fn autoderef(&self, db: &dyn HirDatabase) -> impl Iterator + '_ { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index fdc604a006fc..f51fe80931c6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -40,7 +40,7 @@ use crate::{ Access, Adjust, Adjustment, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, DeriveHelper, Field, Function, HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, Struct, ToolModule, Trait, - Type, TypeAlias, TypeParam, VariantDef, + TupleField, Type, TypeAlias, TypeParam, VariantDef, }; pub enum DescendPreference { @@ -428,7 +428,7 @@ impl<'db> SemanticsImpl<'db> { if let Some(original_string) = ast::String::cast(original_token.clone()) { if let Some(quote) = original_string.open_quote_text_range() { return self - .descend_into_macros(DescendPreference::SameText, original_token.clone()) + .descend_into_macros(DescendPreference::SameText, original_token) .into_iter() .find_map(|token| { self.resolve_offset_in_format_args( @@ -1085,14 +1085,14 @@ impl<'db> SemanticsImpl<'db> { self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call) } - pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option { + pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option> { self.analyze(field.syntax())?.resolve_field(self.db, field) } pub fn resolve_field_fallback( &self, field: &ast::FieldExpr, - ) -> Option> { + ) -> Option, Function>> { self.analyze(field.syntax())?.resolve_field_fallback(self.db, field) } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 54b4d81012f3..73f8db762ae8 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -50,7 +50,7 @@ use triomphe::Arc; use crate::{ db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static, - Struct, ToolModule, Trait, TraitAlias, Type, TypeAlias, Variant, + Struct, ToolModule, Trait, TraitAlias, TupleField, Type, TypeAlias, Variant, }; /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of @@ -297,7 +297,11 @@ impl SourceAnalyzer { Some((f_in_trait, substs)) => Some(Either::Left( self.resolve_impl_method_or_trait_def(db, f_in_trait, substs).into(), )), - None => inference_result.field_resolution(expr_id).map(Into::into).map(Either::Right), + None => inference_result + .field_resolution(expr_id) + .and_then(Either::left) + .map(Into::into) + .map(Either::Right), } } @@ -305,20 +309,28 @@ impl SourceAnalyzer { &self, db: &dyn HirDatabase, field: &ast::FieldExpr, - ) -> Option { + ) -> Option> { + let &(def, ..) = self.def.as_ref()?; let expr_id = self.expr_id(db, &field.clone().into())?; - self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into()) + self.infer.as_ref()?.field_resolution(expr_id).map(|it| { + it.map_either(Into::into, |f| TupleField { owner: def, tuple: f.tuple, index: f.index }) + }) } pub(crate) fn resolve_field_fallback( &self, db: &dyn HirDatabase, field: &ast::FieldExpr, - ) -> Option> { + ) -> Option, Function>> { + let &(def, ..) = self.def.as_ref()?; let expr_id = self.expr_id(db, &field.clone().into())?; let inference_result = self.infer.as_ref()?; match inference_result.field_resolution(expr_id) { - Some(field) => Some(Either::Left(field.into())), + Some(field) => Some(Either::Left(field.map_either(Into::into, |f| TupleField { + owner: def, + tuple: f.tuple, + index: f.index, + }))), None => inference_result.method_resolution(expr_id).map(|(f, substs)| { Either::Right(self.resolve_impl_method_or_trait_def(db, f, substs).into()) }), diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index 4da0dfba6755..841ddfb9c437 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -18,11 +18,11 @@ use crate::{Module, ModuleDef, Semantics}; /// possible. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FileSymbol { - // even though name can be derived from the def, we store it for efficiency pub name: SmolStr, pub def: ModuleDef, pub loc: DeclarationLocation, pub container_name: Option, + /// Whether this symbol is a doc alias for the original symbol. pub is_alias: bool, pub is_assoc: bool, } @@ -163,11 +163,9 @@ impl<'a> SymbolCollector<'a> { } // Record renamed imports. - // In case it imports multiple items under different namespaces we just pick one arbitrarily + // FIXME: In case it imports multiple items under different namespaces we just pick one arbitrarily // for now. for id in scope.imports() { - let loc = id.import.lookup(self.db.upcast()); - loc.id.item_tree(self.db.upcast()); let source = id.import.child_source(self.db.upcast()); let Some(use_tree_src) = source.value.get(id.idx) else { continue }; let Some(rename) = use_tree_src.rename() else { continue }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs index 1f785b5d0a81..7b71d9b86968 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs @@ -89,12 +89,14 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; // ``` pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let (import_assets, syntax_under_caret) = find_importable_node(ctx)?; - let mut proposed_imports = import_assets.search_for_imports( - &ctx.sema, - ctx.config.insert_use.prefix_kind, - ctx.config.prefer_no_std, - ctx.config.prefer_no_std, - ); + let mut proposed_imports: Vec<_> = import_assets + .search_for_imports( + &ctx.sema, + ctx.config.insert_use.prefix_kind, + ctx.config.prefer_no_std, + ctx.config.prefer_no_std, + ) + .collect(); if proposed_imports.is_empty() { return None; } @@ -113,6 +115,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< )?; // we aren't interested in different namespaces + proposed_imports.sort_by(|a, b| a.import_path.cmp(&b.import_path)); proposed_imports.dedup_by(|a, b| a.import_path == b.import_path); let current_node = match ctx.covering_element() { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs index b7b00e7ed068..dc1952c3ff3c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs @@ -301,7 +301,7 @@ fn replace_usages( // add imports across modules where needed if let Some((import_scope, path)) = import_data { - let scope = match import_scope.clone() { + let scope = match import_scope { ImportScope::File(it) => ImportScope::File(edit.make_mut(it)), ImportScope::Module(it) => ImportScope::Module(edit.make_mut(it)), ImportScope::Block(it) => ImportScope::Block(edit.make_mut(it)), @@ -329,7 +329,7 @@ fn augment_references_with_imports( references .into_iter() .filter_map(|FileReference { range, name, .. }| { - let name = name.clone().into_name_like()?; + let name = name.into_name_like()?; ctx.sema.scope(name.syntax()).map(|scope| (range, name, scope.module())) }) .map(|(range, name, ref_module)| { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs index 5f7056b9c1c4..79c34c14da72 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs @@ -1,5 +1,6 @@ use hir::Semantics; use ide_db::RootDatabase; +use syntax::ast::RangeItem; use syntax::ast::{edit::AstNodeEdit, AstNode, HasName, LetStmt, Name, Pat}; use syntax::T; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs index 399f87c8f509..c30f3e1c3b2b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs @@ -49,8 +49,8 @@ pub(crate) fn convert_nested_function_to_closure( target, |edit| { let params = ¶m_list.syntax().text().to_string(); - let params = params.strip_prefix("(").unwrap_or(params); - let params = params.strip_suffix(")").unwrap_or(params); + let params = params.strip_prefix('(').unwrap_or(params); + let params = params.strip_suffix(')').unwrap_or(params); let mut body = body.to_string(); if !has_semicolon(&function) { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs index 79b46d66121e..41366658a74b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs @@ -190,7 +190,7 @@ fn augment_references_with_imports( ctx.sema.scope(name.syntax()).map(|scope| (name, scope.module())) }) .map(|(name, ref_module)| { - let new_name = edit.make_mut(name.clone()); + let new_name = edit.make_mut(name); // if the referenced module is not the same as the target one and has not been seen before, add an import let import_data = if ref_module.nearest_non_block_module(ctx.db()) != *target_module diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index 37db27a8fc02..65e2a0184779 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -6,6 +6,7 @@ use ide_db::{ defs::Definition, helpers::mod_path_to_ast, imports::insert_use::{insert_use, ImportScope, InsertUseConfig}, + path_transform::PathTransform, search::FileReference, FxHashSet, RootDatabase, }; @@ -105,6 +106,16 @@ pub(crate) fn extract_struct_from_enum_variant( .generic_param_list() .and_then(|known_generics| extract_generic_params(&known_generics, &field_list)); let generics = generic_params.as_ref().map(|generics| generics.clone_for_update()); + + // resolve GenericArg in field_list to actual type + let field_list = field_list.clone_for_update(); + if let Some((target_scope, source_scope)) = + ctx.sema.scope(enum_ast.syntax()).zip(ctx.sema.scope(field_list.syntax())) + { + PathTransform::generic_transformation(&target_scope, &source_scope) + .apply(field_list.syntax()); + } + let def = create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast); @@ -244,8 +255,6 @@ fn create_struct_def( // for fields without any existing visibility, use visibility of enum let field_list: ast::FieldList = match field_list { Either::Left(field_list) => { - let field_list = field_list.clone_for_update(); - if let Some(vis) = &enum_vis { field_list .fields() @@ -254,11 +263,9 @@ fn create_struct_def( .for_each(|it| insert_vis(it.syntax(), vis.syntax())); } - field_list.into() + field_list.clone().into() } Either::Right(field_list) => { - let field_list = field_list.clone_for_update(); - if let Some(vis) = &enum_vis { field_list .fields() @@ -267,7 +274,7 @@ fn create_struct_def( .for_each(|it| insert_vis(it.syntax(), vis.syntax())); } - field_list.into() + field_list.clone().into() } }; field_list.reindent_to(IndentLevel::single()); @@ -425,6 +432,59 @@ mod tests { use super::*; + #[test] + fn issue_16197() { + check_assist( + extract_struct_from_enum_variant, + r#" +enum Foo { + Bar $0{ node: Box }, + Nil, +} +"#, + r#" +struct Bar{ node: Box } + +enum Foo { + Bar(Bar), + Nil, +} +"#, + ); + check_assist( + extract_struct_from_enum_variant, + r#" +enum Foo { + Bar $0{ node: Box, a: Arc> }, + Nil, +} +"#, + r#" +struct Bar{ node: Box, a: Arc> } + +enum Foo { + Bar(Bar), + Nil, +} +"#, + ); + check_assist( + extract_struct_from_enum_variant, + r#" +enum Foo { + Nil(Box$0, Arc>), +} +"#, + r#" +struct Nil(Box, Arc>); + +enum Foo { + Nil(Nil), +} +"#, + ); + } + #[test] fn test_extract_struct_several_fields_tuple() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index 874b81d3b637..0b3bd0bed6ed 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -112,7 +112,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let insert_place = edit.make_syntax_mut(place); // Adjust ws to insert depending on if this is all inline or on separate lines - let trailing_ws = if prev_ws.is_some_and(|it| it.text().starts_with("\n")) { + let trailing_ws = if prev_ws.is_some_and(|it| it.text().starts_with('\n')) { format!("\n{indent_to}") } else { format!(" ") diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs index db1e0ceaec1e..dc02aaf9af68 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -147,7 +147,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' None => { let name = &strukt_name.to_string(); let params = strukt.generic_param_list(); - let ty_params = params.clone(); + let ty_params = params; let where_clause = strukt.where_clause(); let impl_def = make::impl_( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs index 0d34502add94..339c3ac71ecd 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -17,7 +17,7 @@ use syntax::{ self, edit::{self, AstNodeEdit}, make, AssocItem, GenericArgList, GenericParamList, HasGenericParams, HasName, - HasTypeBounds, HasVisibility as astHasVisibility, Path, + HasTypeBounds, HasVisibility as astHasVisibility, Path, WherePred, }, ted::{self, Position}, AstNode, NodeOrToken, SmolStr, SyntaxKind, @@ -217,9 +217,9 @@ impl Struct { }; acc.add_group( - &GroupLabel(format!("Generate delegate impls for field `{}`", field.name)), + &GroupLabel(format!("Generate delegate trait impls for field `{}`", field.name)), AssistId("generate_delegate_trait", ide_db::assists::AssistKind::Generate), - format!("Generate delegate impl `{}` for `{}`", signature, field.name), + format!("Generate delegate trait impl `{}` for `{}`", signature, field.name), field.range, |builder| { builder.insert( @@ -243,12 +243,12 @@ fn generate_impl( let db = ctx.db(); let ast_strukt = &strukt.strukt; let strukt_ty = make::ty_path(make::ext::ident_path(&strukt.name.to_string())); + let strukt_params = ast_strukt.generic_param_list(); match delegee { Delegee::Bound(delegee) => { let bound_def = ctx.sema.source(delegee.to_owned())?.value; let bound_params = bound_def.generic_param_list(); - let strukt_params = ast_strukt.generic_param_list(); delegate = make::impl_trait( delegee.is_unsafe(db), @@ -266,11 +266,8 @@ fn generate_impl( .clone_for_update(); // Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths - let qualified_path_type = make::path_from_text(&format!( - "<{} as {}>", - field_ty.to_string(), - delegate.trait_()?.to_string() - )); + let qualified_path_type = + make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?)); let delegate_assoc_items = delegate.get_or_create_assoc_item_list(); match bound_def.assoc_item_list() { @@ -295,63 +292,73 @@ fn generate_impl( } Delegee::Impls(trait_, old_impl) => { let old_impl = ctx.sema.source(old_impl.to_owned())?.value; + let old_impl_params = old_impl.generic_param_list(); + + // 1) Resolve conflicts between generic parameters in old_impl and + // those in strukt. + // + // These generics parameters will also be used in `field_ty` and + // `where_clauses`, so we should substitude arguments in them as well. + let strukt_params = resolve_name_conflicts(strukt_params, &old_impl_params); + let (field_ty, ty_where_clause) = match &strukt_params { + Some(strukt_params) => { + let args = strukt_params.to_generic_args(); + let field_ty = rename_strukt_args(ctx, ast_strukt, field_ty, &args)?; + let where_clause = ast_strukt + .where_clause() + .and_then(|wc| Some(rename_strukt_args(ctx, ast_strukt, &wc, &args)?)); + (field_ty, where_clause) + } + None => (field_ty.clone_for_update(), None), + }; + + // 2) Handle instantiated generics in `field_ty`. + + // 2.1) Some generics used in `self_ty` may be instantiated, so they + // are no longer generics, we should remove and instantiate those + // generics in advance. // `old_trait_args` contains names of generic args for trait in `old_impl` - let old_trait_args = old_impl + let old_impl_trait_args = old_impl .trait_()? .generic_arg_list() .map(|l| l.generic_args().map(|arg| arg.to_string())) .map_or_else(|| FxHashSet::default(), |it| it.collect()); - let old_impl_params = old_impl.generic_param_list(); + let trait_gen_params = remove_instantiated_params( + &old_impl.self_ty()?, + old_impl_params.clone(), + &old_impl_trait_args, + ); - // Resolve conflicts with generic parameters in strukt. - // These generics parameters will also be used in `field_ty` and `where_clauses`, - // so we should substitude arguments in them as well. - let (renamed_strukt_params, field_ty, ty_where_clause) = if let Some(strukt_params) = - resolve_conflicts_for_strukt(ast_strukt, old_impl_params.as_ref()) - { - let strukt_args = strukt_params.to_generic_args(); - let field_ty = - subst_name_in_strukt(ctx, ast_strukt, field_ty, strukt_args.clone())?; - let wc = ast_strukt - .where_clause() - .and_then(|wc| Some(subst_name_in_strukt(ctx, ast_strukt, &wc, strukt_args)?)); - (Some(strukt_params), field_ty, wc) - } else { - (None, field_ty.clone_for_update(), None) - }; - - // Some generics used in `field_ty` may be instantiated, so they are no longer - // `generics`. We should remove them from generics params, and use the rest params. - let trait_gen_params = - remove_instantiated_params(&old_impl.self_ty()?, old_impl_params, &old_trait_args); - - // Generate generic args that applied to current impl, this step will also remove unused params - let args_for_impl = - get_args_for_impl(&old_impl, &field_ty, &trait_gen_params, &old_trait_args); + // 2.2) Generate generic args applied on impl. + let transform_args = generate_args_for_impl( + old_impl_params, + &old_impl.self_ty()?, + &field_ty, + &trait_gen_params, + &old_impl_trait_args, + ); + // 2.3) Instantiate generics with `transform_impl`, this step also + // remove unused params. let mut trait_gen_args = old_impl.trait_()?.generic_arg_list(); - if let Some(arg_list) = &mut trait_gen_args { - *arg_list = arg_list.clone_for_update(); - transform_impl(ctx, ast_strukt, &old_impl, &args_for_impl, &arg_list.syntax())?; + if let Some(trait_args) = &mut trait_gen_args { + *trait_args = trait_args.clone_for_update(); + transform_impl(ctx, ast_strukt, &old_impl, &transform_args, &trait_args.syntax())?; } - let mut type_gen_args = - renamed_strukt_params.clone().map(|params| params.to_generic_args()); - if let Some(type_args) = &mut type_gen_args { - *type_args = type_args.clone_for_update(); - transform_impl(ctx, ast_strukt, &old_impl, &args_for_impl, &type_args.syntax())?; - } + let type_gen_args = strukt_params.clone().map(|params| params.to_generic_args()); let path_type = make::ty(&trait_.name(db).to_smol_str()).clone_for_update(); - transform_impl(ctx, ast_strukt, &old_impl, &args_for_impl, &path_type.syntax())?; + transform_impl(ctx, ast_strukt, &old_impl, &transform_args, &path_type.syntax())?; + // 3) Generate delegate trait impl delegate = make::impl_trait( trait_.is_unsafe(db), trait_gen_params, trait_gen_args, - renamed_strukt_params, + strukt_params, type_gen_args, trait_.is_auto(db), path_type, @@ -363,30 +370,26 @@ fn generate_impl( .clone_for_update(); // Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths - let qualified_path_type = make::path_from_text(&format!( - "<{} as {}>", - field_ty.to_string(), - delegate.trait_()?.to_string() - )); + let qualified_path_type = + make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?)); + // 4) Transform associated items in delegte trait impl let delegate_assoc_items = delegate.get_or_create_assoc_item_list(); for item in old_impl .get_or_create_assoc_item_list() .assoc_items() .filter(|item| matches!(item, AssocItem::MacroCall(_)).not()) { - let assoc = process_assoc_item( - transform_assoc_item(ctx, ast_strukt, &old_impl, &args_for_impl, item)?, - qualified_path_type.clone(), - &field_name, - )?; + let item = item.clone_for_update(); + transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item.syntax())?; + let assoc = process_assoc_item(item, qualified_path_type.clone(), &field_name)?; delegate_assoc_items.add_item(assoc); } - // Remove unused where clauses + // 5) Remove useless where clauses if let Some(wc) = delegate.where_clause() { - remove_useless_where_clauses(&delegate, wc)?; + remove_useless_where_clauses(&delegate.trait_()?, &delegate.self_ty()?, wc); } } } @@ -394,32 +397,6 @@ fn generate_impl( Some(delegate) } -fn transform_assoc_item( - ctx: &AssistContext<'_>, - strukt: &ast::Struct, - old_impl: &ast::Impl, - args: &Option, - item: AssocItem, -) -> Option { - let source_scope = ctx.sema.scope(&item.syntax()).unwrap(); - let target_scope = ctx.sema.scope(&strukt.syntax())?; - let hir_old_impl = ctx.sema.to_impl_def(old_impl)?; - let item = item.clone_for_update(); - let transform = args.as_ref().map_or_else( - || PathTransform::generic_transformation(&target_scope, &source_scope), - |args| { - PathTransform::impl_transformation( - &target_scope, - &source_scope, - hir_old_impl, - args.clone(), - ) - }, - ); - transform.apply(&item.syntax()); - Some(item) -} - fn transform_impl( ctx: &AssistContext<'_>, strukt: &ast::Struct, @@ -463,11 +440,11 @@ fn remove_instantiated_params( .segments() .filter_map(|seg| seg.generic_arg_list()) .flat_map(|it| it.generic_args()) - // However, if the param is also used in the trait arguments, it shouldn't be removed. + // However, if the param is also used in the trait arguments, + // it shouldn't be removed now, which will be instantiated in + // later `path_transform` .filter(|arg| !old_trait_args.contains(&arg.to_string())) - .for_each(|arg| { - new_gpl.remove_generic_arg(&arg); - }); + .for_each(|arg| new_gpl.remove_generic_arg(&arg)); (new_gpl.generic_params().count() > 0).then_some(new_gpl) }) } @@ -475,49 +452,37 @@ fn remove_instantiated_params( } } -fn remove_useless_where_clauses(delegate: &ast::Impl, wc: ast::WhereClause) -> Option<()> { - let trait_args = - delegate.trait_()?.generic_arg_list().map(|trait_args| trait_args.generic_args()); - let strukt_args = - delegate.self_ty()?.generic_arg_list().map(|strukt_args| strukt_args.generic_args()); - let used_generic_names = match (trait_args, strukt_args) { - (None, None) => None, - (None, Some(y)) => Some(y.map(|arg| arg.to_string()).collect::>()), - (Some(x), None) => Some(x.map(|arg| arg.to_string()).collect::>()), - (Some(x), Some(y)) => Some(x.chain(y).map(|arg| arg.to_string()).collect::>()), - }; +fn remove_useless_where_clauses(trait_ty: &ast::Type, self_ty: &ast::Type, wc: ast::WhereClause) { + let live_generics = [trait_ty, self_ty] + .into_iter() + .flat_map(|ty| ty.generic_arg_list()) + .flat_map(|gal| gal.generic_args()) + .map(|x| x.to_string()) + .collect::>(); - // Keep clauses that have generic clauses after substitution, and remove the rest - if let Some(used_generic_names) = used_generic_names { - wc.predicates() - .filter(|pred| { - pred.syntax() - .descendants_with_tokens() - .filter_map(|e| e.into_token()) - .find(|e| { - e.kind() == SyntaxKind::IDENT && used_generic_names.contains(&e.to_string()) - }) - .is_none() - }) - .for_each(|pred| { - wc.remove_predicate(pred); - }); - } else { - wc.predicates().for_each(|pred| wc.remove_predicate(pred)); - } + // Keep where-clauses that have generics after substitution, and remove the + // rest. + let has_live_generics = |pred: &WherePred| { + pred.syntax() + .descendants_with_tokens() + .filter_map(|e| e.into_token()) + .any(|e| e.kind() == SyntaxKind::IDENT && live_generics.contains(&e.to_string())) + .not() + }; + wc.predicates().filter(has_live_generics).for_each(|pred| wc.remove_predicate(pred)); if wc.predicates().count() == 0 { // Remove useless whitespaces - wc.syntax() - .siblings_with_tokens(syntax::Direction::Prev) - .skip(1) - .take_while(|node_or_tok| node_or_tok.kind() == SyntaxKind::WHITESPACE) - .for_each(|ws| ted::remove(ws)); - wc.syntax() - .siblings_with_tokens(syntax::Direction::Next) - .skip(1) - .take_while(|node_or_tok| node_or_tok.kind() == SyntaxKind::WHITESPACE) + [syntax::Direction::Prev, syntax::Direction::Next] + .into_iter() + .flat_map(|dir| { + wc.syntax() + .siblings_with_tokens(dir) + .skip(1) + .take_while(|node_or_tok| node_or_tok.kind() == SyntaxKind::WHITESPACE) + }) .for_each(|ws| ted::remove(ws)); + ted::insert( ted::Position::after(wc.syntax()), NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)), @@ -525,84 +490,63 @@ fn remove_useless_where_clauses(delegate: &ast::Impl, wc: ast::WhereClause) -> O // Remove where clause ted::remove(wc.syntax()); } - - Some(()) } -fn get_args_for_impl( - old_impl: &ast::Impl, +// Generate generic args that should be apply to current impl. +// +// For exmaple, say we have implementation `impl Trait for B`, +// and `b: B` in struct `S`. Then the `A` should be instantiated to `T`. +// While the last two generic args `B` and `C` doesn't change, it remains +// ``. So we apply `` as generic arguments to impl. +fn generate_args_for_impl( + old_impl_gpl: Option, + self_ty: &ast::Type, field_ty: &ast::Type, trait_params: &Option, old_trait_args: &FxHashSet, ) -> Option { - // Generate generic args that should be apply to current impl - // - // For exmaple, if we have `impl Trait for B`, and `b: B` in `S`, - // then the generic `A` should be renamed to `T`. While the last two generic args - // doesn't change, it renames . So we apply `` as generic arguments - // to impl. - let old_impl_params = old_impl.generic_param_list(); - let self_ty = old_impl.self_ty(); + let Some(old_impl_args) = old_impl_gpl.map(|gpl| gpl.to_generic_args().generic_args()) else { + return None; + }; + // Create pairs of the args of `self_ty` and corresponding `field_ty` to + // form the substitution list + let mut arg_substs = FxHashMap::default(); - if let (Some(old_impl_gpl), Some(self_ty)) = (old_impl_params, self_ty) { - // Make pair of the arguments of `field_ty` and `old_strukt_args` to - // get the list for substitution - let mut arg_substs = FxHashMap::default(); - - match field_ty { - field_ty @ ast::Type::PathType(_) => { - let field_args = field_ty.generic_arg_list(); - if let (Some(field_args), Some(old_impl_args)) = - (field_args, self_ty.generic_arg_list()) - { - field_args.generic_args().zip(old_impl_args.generic_args()).for_each( - |(field_arg, impl_arg)| { - arg_substs.entry(impl_arg.to_string()).or_insert(field_arg); - }, - ) - } + match field_ty { + field_ty @ ast::Type::PathType(_) => { + let field_args = field_ty.generic_arg_list().map(|gal| gal.generic_args()); + let self_ty_args = self_ty.generic_arg_list().map(|gal| gal.generic_args()); + if let (Some(field_args), Some(self_ty_args)) = (field_args, self_ty_args) { + self_ty_args.zip(field_args).for_each(|(self_ty_arg, field_arg)| { + arg_substs.entry(self_ty_arg.to_string()).or_insert(field_arg); + }) } - _ => {} } - - let args = old_impl_gpl - .to_generic_args() - .generic_args() - .map(|old_arg| { - arg_substs.get(&old_arg.to_string()).map_or_else( - || old_arg.clone(), - |replace_with| { - // The old_arg will be replaced, so it becomes redundant - let old_arg_name = old_arg.to_string(); - if old_trait_args.contains(&old_arg_name) { - // However, we should check type bounds and where clauses on old_arg, - // if it has type bound, we should keep the type bound. - // match trait_params.and_then(|params| params.remove_generic_arg(&old_arg)) { - // Some(ast::GenericParam::TypeParam(ty)) => { - // ty.type_bound_list().and_then(|bounds| ) - // } - // _ => {} - // } - if let Some(params) = trait_params { - params.remove_generic_arg(&old_arg); - } - } - replace_with.clone() - }, - ) - }) - .collect_vec(); - args.is_empty().not().then(|| make::generic_arg_list(args.into_iter())) - } else { - None + _ => {} } + + let args = old_impl_args + .map(|old_arg| { + arg_substs.get(&old_arg.to_string()).map_or_else( + || old_arg.clone(), + |replace_with| { + // The old_arg will be replaced, so it becomes redundant + if trait_params.is_some() && old_trait_args.contains(&old_arg.to_string()) { + trait_params.as_ref().unwrap().remove_generic_arg(&old_arg) + } + replace_with.clone() + }, + ) + }) + .collect_vec(); + args.is_empty().not().then(|| make::generic_arg_list(args.into_iter())) } -fn subst_name_in_strukt( +fn rename_strukt_args( ctx: &AssistContext<'_>, strukt: &ast::Struct, item: &N, - args: GenericArgList, + args: &GenericArgList, ) -> Option where N: ast::AstNode, @@ -611,9 +555,11 @@ where let hir_adt = hir::Adt::from(hir_strukt); let item = item.clone_for_update(); - let item_scope = ctx.sema.scope(item.syntax())?; - let transform = PathTransform::adt_transformation(&item_scope, &item_scope, hir_adt, args); + let scope = ctx.sema.scope(item.syntax())?; + + let transform = PathTransform::adt_transformation(&scope, &scope, hir_adt, args.clone()); transform.apply(&item.syntax()); + Some(item) } @@ -627,16 +573,16 @@ fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_>) -> Option<()> { .map(|_| ()) } -fn resolve_conflicts_for_strukt( - strukt: &ast::Struct, - old_impl_params: Option<&ast::GenericParamList>, +fn resolve_name_conflicts( + strukt_params: Option, + old_impl_params: &Option, ) -> Option { - match (strukt.generic_param_list(), old_impl_params) { + match (strukt_params, old_impl_params) { (Some(old_strukt_params), Some(old_impl_params)) => { let params = make::generic_param_list(std::iter::empty()).clone_for_update(); for old_strukt_param in old_strukt_params.generic_params() { - // Get old name from `strukt`` + // Get old name from `strukt` let mut name = SmolStr::from(match &old_strukt_param { ast::GenericParam::ConstParam(c) => c.name()?.to_string(), ast::GenericParam::LifetimeParam(l) => { @@ -807,7 +753,7 @@ fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option ast::Path { - make::path_from_text(&format!("{}::{}", qual_path_ty.to_string(), path_expr_seg.to_string())) + make::path_from_text(&format!("{}::{}", qual_path_ty, path_expr_seg)) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index 5bb200e84a49..50528e1caaac 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -432,7 +432,7 @@ fn get_fn_target( } None => next_space_for_fn_after_call_site(ast::CallableExpr::Call(call))?, }; - Some((target.clone(), file)) + Some((target, file)) } fn get_method_target( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs index cb8ef395650b..d90d366ffe4c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs @@ -47,7 +47,7 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_> let impl_def = ctx.find_node_at_offset::()?.clone_for_update(); let trait_ = impl_def.trait_()?; - if let ast::Type::PathType(trait_path) = trait_.clone() { + if let ast::Type::PathType(trait_path) = trait_ { let trait_type = ctx.sema.resolve_trait(&trait_path.path()?)?; let scope = ctx.sema.scope(trait_path.syntax())?; if trait_type != FamousDefs(&ctx.sema, scope.krate()).core_convert_Index()? { @@ -105,7 +105,7 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_> "Generate `IndexMut` impl from this `Index` trait", target, |edit| { - edit.insert(target.start(), format!("$0{}\n\n", impl_def.to_string())); + edit.insert(target.start(), format!("$0{}\n\n", impl_def)); }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs index 0f67380d12b6..315b6487b514 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs @@ -128,7 +128,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ builder.replace_snippet( snippet_cap, impl_name.syntax().text_range(), - format!("${{0:TraitName}}{} for {}", arg_list, impl_name.to_string()), + format!("${{0:TraitName}}{} for {}", arg_list, impl_name), ); // Insert trait before TraitImpl @@ -144,17 +144,13 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ } else { builder.replace( impl_name.syntax().text_range(), - format!("NewTrait{} for {}", arg_list, impl_name.to_string()), + format!("NewTrait{} for {}", arg_list, impl_name), ); // Insert trait before TraitImpl builder.insert( impl_ast.syntax().text_range().start(), - format!( - "{}\n\n{}", - trait_ast.to_string(), - IndentLevel::from_node(impl_ast.syntax()) - ), + format!("{}\n\n{}", trait_ast, IndentLevel::from_node(impl_ast.syntax())), ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs index fde46db3058e..086487184909 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs @@ -37,11 +37,9 @@ use crate::{ // ``` pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let (import_assets, syntax_under_caret) = find_importable_node(ctx)?; - let mut proposed_imports = import_assets.search_for_relative_paths( - &ctx.sema, - ctx.config.prefer_no_std, - ctx.config.prefer_prelude, - ); + let mut proposed_imports: Vec<_> = import_assets + .search_for_relative_paths(&ctx.sema, ctx.config.prefer_no_std, ctx.config.prefer_prelude) + .collect(); if proposed_imports.is_empty() { return None; } @@ -82,6 +80,7 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option }; // we aren't interested in different namespaces + proposed_imports.sort_by(|a, b| a.import_path.cmp(&b.import_path)); proposed_imports.dedup_by(|a, b| a.import_path == b.import_path); let group_label = group_label(candidate); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs index 0281b29cd427..99c55e9ff7c0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs @@ -43,7 +43,7 @@ pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) -> let prev_token = parens.syntax().first_token().and_then(|it| it.prev_token()); let need_to_add_ws = match prev_token { Some(it) => { - let tokens = vec![T![&], T![!], T!['('], T!['['], T!['{']]; + let tokens = [T![&], T![!], T!['('], T!['['], T!['{']]; it.kind() != SyntaxKind::WHITESPACE && !tokens.contains(&it.kind()) } None => false, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index b54e4204e3f3..788cc846c2a5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -74,7 +74,6 @@ pub(crate) fn replace_derive_with_manual_impl( current_crate, NameToImport::exact_case_sensitive(path.segments().last()?.to_string()), items_locator::AssocSearchMode::Exclude, - Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()), ) .filter_map(|item| match item.as_module_def()? { ModuleDef::Trait(trait_) => Some(trait_), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs index d74d3b264ae5..446f0be83481 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs @@ -263,7 +263,6 @@ fn import_on_the_fly( ctx.config.prefer_no_std, ctx.config.prefer_prelude, ) - .into_iter() .filter(ns_filter) .filter(|import| { let original_item = &import.original_item; @@ -271,8 +270,14 @@ fn import_on_the_fly( && !ctx.is_item_hidden(original_item) && ctx.check_stability(original_item.attrs(ctx.db).as_deref()) }) - .sorted_by_key(|located_import| { - compute_fuzzy_completion_order_key(&located_import.import_path, &user_input_lowercased) + .sorted_by(|a, b| { + let key = |import_path| { + ( + compute_fuzzy_completion_order_key(import_path, &user_input_lowercased), + import_path, + ) + }; + key(&a.import_path).cmp(&key(&b.import_path)) }) .filter_map(|import| { render_resolution_with_import(RenderContext::new(ctx), path_ctx, import) @@ -310,7 +315,6 @@ fn import_on_the_fly_pat_( ctx.config.prefer_no_std, ctx.config.prefer_prelude, ) - .into_iter() .filter(ns_filter) .filter(|import| { let original_item = &import.original_item; @@ -318,8 +322,14 @@ fn import_on_the_fly_pat_( && !ctx.is_item_hidden(original_item) && ctx.check_stability(original_item.attrs(ctx.db).as_deref()) }) - .sorted_by_key(|located_import| { - compute_fuzzy_completion_order_key(&located_import.import_path, &user_input_lowercased) + .sorted_by(|a, b| { + let key = |import_path| { + ( + compute_fuzzy_completion_order_key(import_path, &user_input_lowercased), + import_path, + ) + }; + key(&a.import_path).cmp(&key(&b.import_path)) }) .filter_map(|import| { render_resolution_with_import_pat(RenderContext::new(ctx), pattern_ctx, import) @@ -352,13 +362,18 @@ fn import_on_the_fly_method( ctx.config.prefer_no_std, ctx.config.prefer_prelude, ) - .into_iter() .filter(|import| { !ctx.is_item_hidden(&import.item_to_import) && !ctx.is_item_hidden(&import.original_item) }) - .sorted_by_key(|located_import| { - compute_fuzzy_completion_order_key(&located_import.import_path, &user_input_lowercased) + .sorted_by(|a, b| { + let key = |import_path| { + ( + compute_fuzzy_completion_order_key(import_path, &user_input_lowercased), + import_path, + ) + }; + key(&a.import_path).cmp(&key(&b.import_path)) }) .for_each(|import| match import.original_item { ItemInNs::Values(hir::ModuleDef::Function(f)) => { @@ -407,7 +422,8 @@ fn compute_fuzzy_completion_order_key( ) -> usize { cov_mark::hit!(certain_fuzzy_order_test); let import_name = match proposed_mod_path.segments().last() { - Some(name) => name.to_smol_str().to_lowercase(), + // FIXME: nasty alloc, this is a hot path! + Some(name) => name.to_smol_str().to_ascii_lowercase(), None => return usize::MAX, }; match import_name.match_indices(user_input_lowercased).next() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index ff324e7a56d6..6a98e109f6df 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -256,7 +256,6 @@ pub fn resolve_completion_edits( current_crate, NameToImport::exact_case_sensitive(imported_name), items_locator::AssocSearchMode::Include, - Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()), ); let import = items_with_name .filter_map(|candidate| { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index c58374f2e833..1af16ef857d0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -599,6 +599,7 @@ fn main() { expect![[r#" fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED + me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index ded5d4e3db53..8f55f30a2dd4 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -6,18 +6,22 @@ // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). use arrayvec::ArrayVec; +use either::Either; use hir::{ - Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper, DocLinkDef, - ExternCrateDecl, Field, Function, GenericParam, HasVisibility, Impl, Label, Local, Macro, - Module, ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, - TypeAlias, Variant, Visibility, + Adt, AsAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, Const, Crate, + DefWithBody, DeriveHelper, DocLinkDef, ExternCrateDecl, Field, Function, GenericParam, + HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module, ModuleDef, Name, PathResolution, + Semantics, Static, ToolModule, Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef, + Visibility, }; -use stdx::impl_from; +use stdx::{format_to, impl_from}; use syntax::{ ast::{self, AstNode}, match_ast, SyntaxKind, SyntaxNode, SyntaxToken, }; +use crate::documentation::{Documentation, HasDocs}; +use crate::famous_defs::FamousDefs; use crate::RootDatabase; // FIXME: a more precise name would probably be `Symbol`? @@ -25,6 +29,7 @@ use crate::RootDatabase; pub enum Definition { Macro(Macro), Field(Field), + TupleField(TupleField), Module(Module), Function(Function), Adt(Adt), @@ -76,13 +81,21 @@ impl Definition { Definition::Label(it) => it.module(db), Definition::ExternCrateDecl(it) => it.module(db), Definition::DeriveHelper(it) => it.derive().module(db), - Definition::BuiltinAttr(_) | Definition::BuiltinType(_) | Definition::ToolModule(_) => { - return None - } + Definition::BuiltinAttr(_) + | Definition::BuiltinType(_) + | Definition::TupleField(_) + | Definition::ToolModule(_) => return None, }; Some(module) } + pub fn enclosing_definition(&self, db: &RootDatabase) -> Option { + match self { + Definition::Local(it) => it.parent(db).try_into().ok(), + _ => None, + } + } + pub fn visibility(&self, db: &RootDatabase) -> Option { let vis = match self { Definition::Field(sf) => sf.visibility(db), @@ -96,7 +109,7 @@ impl Definition { Definition::TypeAlias(it) => it.visibility(db), Definition::Variant(it) => it.visibility(db), Definition::ExternCrateDecl(it) => it.visibility(db), - Definition::BuiltinType(_) => Visibility::Public, + Definition::BuiltinType(_) | Definition::TupleField(_) => Visibility::Public, Definition::Macro(_) => return None, Definition::BuiltinAttr(_) | Definition::ToolModule(_) @@ -123,6 +136,7 @@ impl Definition { Definition::TraitAlias(it) => it.name(db), Definition::TypeAlias(it) => it.name(db), Definition::BuiltinType(it) => it.name(), + Definition::TupleField(it) => it.name(), Definition::SelfType(_) => return None, Definition::Local(it) => it.name(db), Definition::GenericParam(it) => it.name(db), @@ -134,6 +148,127 @@ impl Definition { }; Some(name) } + + pub fn docs( + &self, + db: &RootDatabase, + famous_defs: Option<&FamousDefs<'_, '_>>, + ) -> Option { + let docs = match self { + Definition::Macro(it) => it.docs(db), + Definition::Field(it) => it.docs(db), + Definition::Module(it) => it.docs(db), + Definition::Function(it) => it.docs(db), + Definition::Adt(it) => it.docs(db), + Definition::Variant(it) => it.docs(db), + Definition::Const(it) => it.docs(db), + Definition::Static(it) => it.docs(db), + Definition::Trait(it) => it.docs(db), + Definition::TraitAlias(it) => it.docs(db), + Definition::TypeAlias(it) => it.docs(db), + Definition::BuiltinType(it) => { + famous_defs.and_then(|fd| { + // std exposes prim_{} modules with docstrings on the root to document the builtins + let primitive_mod = format!("prim_{}", it.name().display(fd.0.db)); + let doc_owner = find_std_module(fd, &primitive_mod)?; + doc_owner.docs(fd.0.db) + }) + } + Definition::Local(_) => None, + Definition::SelfType(impl_def) => { + impl_def.self_ty(db).as_adt().map(|adt| adt.docs(db))? + } + Definition::GenericParam(_) => None, + Definition::Label(_) => None, + Definition::ExternCrateDecl(it) => it.docs(db), + + Definition::BuiltinAttr(it) => { + let name = it.name(db); + let AttributeTemplate { word, list, name_value_str } = it.template(db)?; + let mut docs = "Valid forms are:".to_owned(); + if word { + format_to!(docs, "\n - #\\[{}]", name); + } + if let Some(list) = list { + format_to!(docs, "\n - #\\[{}({})]", name, list); + } + if let Some(name_value_str) = name_value_str { + format_to!(docs, "\n - #\\[{} = {}]", name, name_value_str); + } + Some(Documentation::new(docs.replace('*', "\\*"))) + } + Definition::ToolModule(_) => None, + Definition::DeriveHelper(_) => None, + Definition::TupleField(_) => None, + }; + + docs.or_else(|| { + // docs are missing, for assoc items of trait impls try to fall back to the docs of the + // original item of the trait + let assoc = self.as_assoc_item(db)?; + let trait_ = assoc.containing_trait_impl(db)?; + let name = Some(assoc.name(db)?); + let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?; + item.docs(db) + }) + } + + pub fn label(&self, db: &RootDatabase) -> Option { + let label = match *self { + Definition::Macro(it) => it.display(db).to_string(), + Definition::Field(it) => it.display(db).to_string(), + Definition::TupleField(it) => it.display(db).to_string(), + Definition::Module(it) => it.display(db).to_string(), + Definition::Function(it) => it.display(db).to_string(), + Definition::Adt(it) => it.display(db).to_string(), + Definition::Variant(it) => it.display(db).to_string(), + Definition::Const(it) => it.display(db).to_string(), + Definition::Static(it) => it.display(db).to_string(), + Definition::Trait(it) => it.display(db).to_string(), + Definition::TraitAlias(it) => it.display(db).to_string(), + Definition::TypeAlias(it) => it.display(db).to_string(), + Definition::BuiltinType(it) => it.name().display(db).to_string(), + Definition::Local(it) => { + let ty = it.ty(db); + let ty = ty.display_truncated(db, None); + let is_mut = if it.is_mut(db) { "mut " } else { "" }; + let desc = match it.primary_source(db).into_ident_pat() { + Some(ident) => { + let name = it.name(db); + let let_kw = if ident.syntax().parent().map_or(false, |p| { + p.kind() == SyntaxKind::LET_STMT || p.kind() == SyntaxKind::LET_EXPR + }) { + "let " + } else { + "" + }; + format!("{let_kw}{is_mut}{}: {ty}", name.display(db)) + } + None => format!("{is_mut}self: {ty}"), + }; + desc + } + Definition::SelfType(impl_def) => { + impl_def.self_ty(db).as_adt().and_then(|adt| Definition::Adt(adt).label(db))? + } + Definition::GenericParam(it) => it.display(db).to_string(), + Definition::Label(it) => it.name(db).display(db).to_string(), + Definition::ExternCrateDecl(it) => it.display(db).to_string(), + Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db)), + Definition::ToolModule(it) => it.name(db).to_string(), + Definition::DeriveHelper(it) => format!("derive_helper {}", it.name(db).display(db)), + }; + Some(label) + } +} + +fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option { + let db = famous_defs.0.db; + let std_crate = famous_defs.std()?; + let std_root_module = std_crate.root_module(); + std_root_module.children(db).find(|module| { + module.name(db).map_or(false, |module| module.display(db).to_string() == name) + }) } // FIXME: IdentClass as a name no longer fits @@ -502,9 +637,11 @@ impl NameRefClass { ast::FieldExpr(field_expr) => { sema.resolve_field_fallback(&field_expr) .map(|it| { - it.map_left(Definition::Field) - .map_right(Definition::Function) - .either(NameRefClass::Definition, NameRefClass::Definition) + NameRefClass::Definition(match it { + Either::Left(Either::Left(field)) => Definition::Field(field), + Either::Left(Either::Right(field)) => Definition::TupleField(field), + Either::Right(fun) => Definition::Function(fun), + }) }) }, ast::RecordPatField(record_pat_field) => { @@ -662,3 +799,22 @@ impl From for Definition { } } } + +impl From for Definition { + fn from(def: VariantDef) -> Self { + ModuleDef::from(def).into() + } +} + +impl TryFrom for Definition { + type Error = (); + fn try_from(def: DefWithBody) -> Result { + match def { + DefWithBody::Function(it) => Ok(it.into()), + DefWithBody::Static(it) => Ok(it.into()), + DefWithBody::Const(it) => Ok(it.into()), + DefWithBody::Variant(it) => Ok(it.into()), + DefWithBody::InTypeConst(_) => Err(()), + } + } +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs index a4f0a6df7813..652968d808fa 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs @@ -207,7 +207,7 @@ impl ImportAssets { prefix_kind: PrefixKind, prefer_no_std: bool, prefer_prelude: bool, - ) -> Vec { + ) -> impl Iterator { let _p = profile::span("import_assets::search_for_imports"); self.search_for(sema, Some(prefix_kind), prefer_no_std, prefer_prelude) } @@ -218,7 +218,7 @@ impl ImportAssets { sema: &Semantics<'_, RootDatabase>, prefer_no_std: bool, prefer_prelude: bool, - ) -> Vec { + ) -> impl Iterator { let _p = profile::span("import_assets::search_for_relative_paths"); self.search_for(sema, None, prefer_no_std, prefer_prelude) } @@ -259,9 +259,15 @@ impl ImportAssets { prefixed: Option, prefer_no_std: bool, prefer_prelude: bool, - ) -> Vec { + ) -> impl Iterator { let _p = profile::span("import_assets::search_for"); + let scope = match sema.scope(&self.candidate_node) { + Some(it) => it, + None => return >::default().into_iter(), + }; + + let krate = self.module_with_candidate.krate(); let scope_definitions = self.scope_definitions(sema); let mod_path = |item| { get_mod_path( @@ -272,30 +278,30 @@ impl ImportAssets { prefer_no_std, prefer_prelude, ) - }; - - let krate = self.module_with_candidate.krate(); - let scope = match sema.scope(&self.candidate_node) { - Some(it) => it, - None => return Vec::new(), + .filter(|path| path.len() > 1) }; match &self.import_candidate { ImportCandidate::Path(path_candidate) => { - path_applicable_imports(sema, krate, path_candidate, mod_path) - } - ImportCandidate::TraitAssocItem(trait_candidate) => { - trait_applicable_items(sema, krate, &scope, trait_candidate, true, mod_path) - } - ImportCandidate::TraitMethod(trait_candidate) => { - trait_applicable_items(sema, krate, &scope, trait_candidate, false, mod_path) + path_applicable_imports(sema, krate, path_candidate, mod_path, |item_to_import| { + !scope_definitions.contains(&ScopeDef::from(item_to_import)) + }) } + ImportCandidate::TraitAssocItem(trait_candidate) + | ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items( + sema, + krate, + &scope, + trait_candidate, + matches!(self.import_candidate, ImportCandidate::TraitAssocItem(_)), + mod_path, + |trait_to_import| { + !scope_definitions + .contains(&ScopeDef::ModuleDef(ModuleDef::Trait(trait_to_import))) + }, + ), } .into_iter() - .filter(|import| import.import_path.len() > 1) - .filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import))) - .sorted_by(|a, b| a.import_path.cmp(&b.import_path)) - .collect() } fn scope_definitions(&self, sema: &Semantics<'_, RootDatabase>) -> FxHashSet { @@ -315,6 +321,7 @@ fn path_applicable_imports( current_crate: Crate, path_candidate: &PathImportCandidate, mod_path: impl Fn(ItemInNs) -> Option + Copy, + scope_filter: impl Fn(ItemInNs) -> bool + Copy, ) -> FxHashSet { let _p = profile::span("import_assets::path_applicable_imports"); @@ -333,12 +340,15 @@ fn path_applicable_imports( // // see also an ignored test under FIXME comment in the qualify_path.rs module AssocSearchMode::Exclude, - Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()), ) .filter_map(|item| { + if !scope_filter(item) { + return None; + } let mod_path = mod_path(item)?; Some(LocatedImport::new(mod_path, item, item)) }) + .take(DEFAULT_QUERY_SEARCH_LIMIT.inner()) .collect() } Some(qualifier) => items_locator::items_with_name( @@ -346,9 +356,9 @@ fn path_applicable_imports( current_crate, path_candidate.name.clone(), AssocSearchMode::Include, - Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()), ) - .filter_map(|item| import_for_item(sema.db, mod_path, &qualifier, item)) + .filter_map(|item| import_for_item(sema.db, mod_path, &qualifier, item, scope_filter)) + .take(DEFAULT_QUERY_SEARCH_LIMIT.inner()) .collect(), } } @@ -358,6 +368,7 @@ fn import_for_item( mod_path: impl Fn(ItemInNs) -> Option, unresolved_qualifier: &[SmolStr], original_item: ItemInNs, + scope_filter: impl Fn(ItemInNs) -> bool, ) -> Option { let _p = profile::span("import_assets::import_for_item"); let [first_segment, ..] = unresolved_qualifier else { return None }; @@ -413,15 +424,16 @@ fn import_for_item( // especially in case of lazy completion edit resolutions. return None; } - (false, Some(trait_to_import)) => { + (false, Some(trait_to_import)) if scope_filter(trait_to_import) => { LocatedImport::new(mod_path(trait_to_import)?, trait_to_import, original_item) } - (true, None) => { + (true, None) if scope_filter(original_item_candidate) => { LocatedImport::new(import_path_candidate, original_item_candidate, original_item) } - (false, None) => { + (false, None) if scope_filter(segment_import) => { LocatedImport::new(mod_path(segment_import)?, segment_import, original_item) } + _ => return None, }) } @@ -490,6 +502,7 @@ fn trait_applicable_items( trait_candidate: &TraitImportCandidate, trait_assoc_item: bool, mod_path: impl Fn(ItemInNs) -> Option, + scope_filter: impl Fn(hir::Trait) -> bool, ) -> FxHashSet { let _p = profile::span("import_assets::trait_applicable_items"); @@ -500,22 +513,24 @@ fn trait_applicable_items( let related_traits = inherent_traits.chain(env_traits).collect::>(); let mut required_assoc_items = FxHashSet::default(); - let trait_candidates = items_locator::items_with_name( + let trait_candidates: FxHashSet<_> = items_locator::items_with_name( sema, current_crate, trait_candidate.assoc_item_name.clone(), AssocSearchMode::AssocItemsOnly, - Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()), ) .filter_map(|input| item_as_assoc(db, input)) .filter_map(|assoc| { + if !trait_assoc_item && matches!(assoc, AssocItem::Const(_) | AssocItem::TypeAlias(_)) { + return None; + } + let assoc_item_trait = assoc.containing_trait(db)?; if related_traits.contains(&assoc_item_trait) { - None - } else { - required_assoc_items.insert(assoc); - Some(assoc_item_trait.into()) + return None; } + required_assoc_items.insert(assoc); + Some(assoc_item_trait.into()) }) .collect(); @@ -531,12 +546,8 @@ fn trait_applicable_items( None, |assoc| { if required_assoc_items.contains(&assoc) { - if let AssocItem::Function(f) = assoc { - if f.self_param(db).is_some() { - return None; - } - } - let located_trait = assoc.containing_trait(db)?; + let located_trait = + assoc.containing_trait(db).filter(|&it| scope_filter(it))?; let trait_item = ItemInNs::from(ModuleDef::from(located_trait)); let import_path = trait_import_paths .entry(trait_item) @@ -561,7 +572,8 @@ fn trait_applicable_items( |function| { let assoc = function.as_assoc_item(db)?; if required_assoc_items.contains(&assoc) { - let located_trait = assoc.containing_trait(db)?; + let located_trait = + assoc.containing_trait(db).filter(|&it| scope_filter(it))?; let trait_item = ItemInNs::from(ModuleDef::from(located_trait)); let import_path = trait_import_paths .entry(trait_item) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs index 4a5d234f73d2..432f1d745d20 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs @@ -19,26 +19,24 @@ pub fn items_with_name<'a>( krate: Crate, name: NameToImport, assoc_item_search: AssocSearchMode, - limit: Option, ) -> impl Iterator + 'a { let _p = profile::span("items_with_name").detail(|| { format!( - "Name: {}, crate: {:?}, assoc items: {:?}, limit: {:?}", + "Name: {}, crate: {:?}, assoc items: {:?}", name.text(), assoc_item_search, krate.display_name(sema.db).map(|name| name.to_string()), - limit, ) }); let prefix = matches!(name, NameToImport::Prefix(..)); - let (mut local_query, mut external_query) = match name { + let (local_query, external_query) = match name { NameToImport::Prefix(exact_name, case_sensitive) | NameToImport::Exact(exact_name, case_sensitive) => { let mut local_query = symbol_index::Query::new(exact_name.clone()); + local_query.assoc_search_mode(assoc_item_search); let mut external_query = - // import_map::Query::new(exact_name).assoc_search_mode(assoc_item_search); - import_map::Query::new(exact_name); + import_map::Query::new(exact_name).assoc_search_mode(assoc_item_search); if prefix { local_query.prefix(); external_query = external_query.prefix(); @@ -55,8 +53,9 @@ pub fn items_with_name<'a>( NameToImport::Fuzzy(fuzzy_search_string, case_sensitive) => { let mut local_query = symbol_index::Query::new(fuzzy_search_string.clone()); local_query.fuzzy(); + local_query.assoc_search_mode(assoc_item_search); - let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) + let mut external_query = import_map::Query::new(fuzzy_search_string) .fuzzy() .assoc_search_mode(assoc_item_search); @@ -69,18 +68,12 @@ pub fn items_with_name<'a>( } }; - if let Some(limit) = limit { - external_query = external_query.limit(limit); - local_query.limit(limit); - } - - find_items(sema, krate, assoc_item_search, local_query, external_query) + find_items(sema, krate, local_query, external_query) } fn find_items<'a>( sema: &'a Semantics<'_, RootDatabase>, krate: Crate, - assoc_item_search: AssocSearchMode, local_query: symbol_index::Query, external_query: import_map::Query, ) -> impl Iterator + 'a { @@ -98,18 +91,12 @@ fn find_items<'a>( }); // Query the local crate using the symbol index. - let local_results = local_query - .search(&symbol_index::crate_symbols(db, krate)) - .into_iter() - .filter(move |candidate| match assoc_item_search { - AssocSearchMode::Include => true, - AssocSearchMode::Exclude => !candidate.is_assoc, - AssocSearchMode::AssocItemsOnly => candidate.is_assoc, - }) - .map(|local_candidate| match local_candidate.def { + let mut local_results = Vec::new(); + local_query.search(&symbol_index::crate_symbols(db, krate), |local_candidate| { + local_results.push(match local_candidate.def { hir::ModuleDef::Macro(macro_def) => ItemInNs::Macros(macro_def), def => ItemInNs::from(def), - }); - - external_importables.chain(local_results) + }) + }); + local_results.into_iter().chain(external_importables) } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index 8c1a6e6e40b8..edfeddc1bc9c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -159,7 +159,7 @@ impl<'a> PathTransform<'a> { .for_each(|(k, v)| match (k.split(db), v) { (Either::Right(k), Some(TypeOrConst::Either(v))) => { if let Some(ty) = v.ty() { - type_substs.insert(k, ty.clone()); + type_substs.insert(k, ty); } } (Either::Right(k), None) => { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index 7f28965885ad..f694f7160dea 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -198,6 +198,7 @@ impl Definition { Definition::SelfType(_) => return None, Definition::BuiltinAttr(_) => return None, Definition::ToolModule(_) => return None, + Definition::TupleField(_) => return None, // FIXME: This should be doable in theory Definition::DeriveHelper(_) => return None, }; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index dbef36026822..a40dd2692cfd 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -539,7 +539,7 @@ impl<'a> FindUsages<'a> { tree.token_at_offset(offset).into_iter().for_each(|token| { let Some(str_token) = ast::String::cast(token.clone()) else { return }; if let Some((range, nameres)) = - sema.check_for_format_args_template(token.clone(), offset) + sema.check_for_format_args_template(token, offset) { if self.found_format_args_ref(file_id, range, str_token, nameres, sink) { return; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs index c7188f1f7943..73be6a4071e4 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs @@ -341,13 +341,13 @@ impl SourceChangeBuilder { /// Adds a tabstop snippet to place the cursor before `token` pub fn add_tabstop_before_token(&mut self, _cap: SnippetCap, token: SyntaxToken) { assert!(token.parent().is_some()); - self.add_snippet(PlaceSnippet::Before(token.clone().into())); + self.add_snippet(PlaceSnippet::Before(token.into())); } /// Adds a tabstop snippet to place the cursor after `token` pub fn add_tabstop_after_token(&mut self, _cap: SnippetCap, token: SyntaxToken) { assert!(token.parent().is_some()); - self.add_snippet(PlaceSnippet::After(token.clone().into())); + self.add_snippet(PlaceSnippet::After(token.into())); } /// Adds a snippet to move the cursor selected over `node` diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs index f5f0f0576f22..c2e95ca860ca 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs @@ -31,9 +31,10 @@ use base_db::{ salsa::{self, ParallelDatabase}, SourceDatabaseExt, SourceRootId, Upcast, }; -use fst::{self, Streamer}; +use fst::{self, raw::IndexedValue, Automaton, Streamer}; use hir::{ db::HirDatabase, + import_map::{AssocSearchMode, SearchMode}, symbols::{FileSymbol, SymbolCollector}, Crate, Module, }; @@ -43,22 +44,15 @@ use triomphe::Arc; use crate::RootDatabase; -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -enum SearchMode { - Fuzzy, - Exact, - Prefix, -} - #[derive(Debug, Clone)] pub struct Query { query: String, lowercased: String, + mode: SearchMode, + assoc_mode: AssocSearchMode, + case_sensitive: bool, only_types: bool, libs: bool, - mode: SearchMode, - case_sensitive: bool, - limit: usize, } impl Query { @@ -70,8 +64,8 @@ impl Query { only_types: false, libs: false, mode: SearchMode::Fuzzy, + assoc_mode: AssocSearchMode::Include, case_sensitive: false, - limit: usize::max_value(), } } @@ -95,12 +89,13 @@ impl Query { self.mode = SearchMode::Prefix; } - pub fn case_sensitive(&mut self) { - self.case_sensitive = true; + /// Specifies whether we want to include associated items in the result. + pub fn assoc_search_mode(&mut self, assoc_mode: AssocSearchMode) { + self.assoc_mode = assoc_mode; } - pub fn limit(&mut self, limit: usize) { - self.limit = limit + pub fn case_sensitive(&mut self) { + self.case_sensitive = true; } } @@ -225,7 +220,9 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec { indices.iter().flat_map(|indices| indices.iter().cloned()).collect() }; - query.search(&indices) + let mut res = vec![]; + query.search(&indices, |f| res.push(f.clone())); + res } #[derive(Default)] @@ -285,6 +282,7 @@ impl SymbolIndex { builder.insert(key, value).unwrap(); } + // FIXME: fst::Map should ideally have a way to shrink the backing buffer without the unwrap dance let map = fst::Map::new({ let mut buf = builder.into_inner().unwrap(); buf.shrink_to_fit(); @@ -317,22 +315,54 @@ impl SymbolIndex { } impl Query { - pub(crate) fn search(self, indices: &[Arc]) -> Vec { + pub(crate) fn search<'sym>( + self, + indices: &'sym [Arc], + cb: impl FnMut(&'sym FileSymbol), + ) { let _p = profile::span("symbol_index::Query::search"); let mut op = fst::map::OpBuilder::new(); - for file_symbols in indices.iter() { - let automaton = fst::automaton::Subsequence::new(&self.lowercased); - op = op.add(file_symbols.map.search(automaton)) + match self.mode { + SearchMode::Exact => { + let automaton = fst::automaton::Str::new(&self.lowercased); + + for index in indices.iter() { + op = op.add(index.map.search(&automaton)); + } + self.search_maps(&indices, op.union(), cb) + } + SearchMode::Fuzzy => { + let automaton = fst::automaton::Subsequence::new(&self.lowercased); + + for index in indices.iter() { + op = op.add(index.map.search(&automaton)); + } + self.search_maps(&indices, op.union(), cb) + } + SearchMode::Prefix => { + let automaton = fst::automaton::Str::new(&self.lowercased).starts_with(); + + for index in indices.iter() { + op = op.add(index.map.search(&automaton)); + } + self.search_maps(&indices, op.union(), cb) + } } - let mut stream = op.union(); - let mut res = Vec::new(); + } + + fn search_maps<'sym>( + &self, + indices: &'sym [Arc], + mut stream: fst::map::Union<'_>, + mut cb: impl FnMut(&'sym FileSymbol), + ) { while let Some((_, indexed_values)) = stream.next() { - for indexed_value in indexed_values { - let symbol_index = &indices[indexed_value.index]; - let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value); + for &IndexedValue { index, value } in indexed_values { + let symbol_index = &indices[index]; + let (start, end) = SymbolIndex::map_value_to_range(value); for symbol in &symbol_index.symbols[start..end] { - if self.only_types + let non_type_for_type_only_query = self.only_types && !matches!( symbol.def, hir::ModuleDef::Adt(..) @@ -340,38 +370,23 @@ impl Query { | hir::ModuleDef::BuiltinType(..) | hir::ModuleDef::TraitAlias(..) | hir::ModuleDef::Trait(..) - ) - { + ); + if non_type_for_type_only_query || !self.matches_assoc_mode(symbol.is_assoc) { continue; } - let skip = match self.mode { - SearchMode::Fuzzy => { - self.case_sensitive - && self.query.chars().any(|c| !symbol.name.contains(c)) - } - SearchMode::Exact => symbol.name != self.query, - SearchMode::Prefix if self.case_sensitive => { - !symbol.name.starts_with(&self.query) - } - SearchMode::Prefix => symbol - .name - .chars() - .zip(self.lowercased.chars()) - .all(|(n, q)| n.to_lowercase().next() == Some(q)), - }; - - if skip { - continue; - } - - res.push(symbol.clone()); - if res.len() >= self.limit { - return res; + if self.mode.check(&self.query, self.case_sensitive, &symbol.name) { + cb(symbol); } } } } - res + } + + fn matches_assoc_mode(&self, is_trait_assoc_item: bool) -> bool { + match (is_trait_assoc_item, self.assoc_mode) { + (true, AssocSearchMode::Exclude) | (false, AssocSearchMode::AssocItemsOnly) => false, + _ => true, + } } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs index c202264bb566..6ecfd55ea024 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs @@ -1,5 +1,10 @@ -use hir::{Const, Function, HasSource, TypeAlias}; -use ide_db::base_db::FileRange; +use hir::{db::ExpandDatabase, Const, Function, HasSource, HirDisplay, TypeAlias}; +use ide_db::{ + assists::{Assist, AssistId, AssistKind}, + label::Label, + source_change::SourceChangeBuilder, +}; +use text_edit::TextRange; use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; @@ -10,47 +15,195 @@ pub(crate) fn trait_impl_redundant_assoc_item( ctx: &DiagnosticsContext<'_>, d: &hir::TraitImplRedundantAssocItems, ) -> Diagnostic { - let name = d.assoc_item.0.clone(); - let assoc_item = d.assoc_item.1; let db = ctx.sema.db; + let name = d.assoc_item.0.clone(); + let redundant_assoc_item_name = name.display(db); + let assoc_item = d.assoc_item.1; let default_range = d.impl_.syntax_node_ptr().text_range(); let trait_name = d.trait_.name(db).to_smol_str(); - let (redundant_item_name, diagnostic_range) = match assoc_item { - hir::AssocItem::Function(id) => ( - format!("`fn {}`", name.display(db)), - Function::from(id) - .source(db) - .map(|it| it.syntax().value.text_range()) - .unwrap_or(default_range), - ), - hir::AssocItem::Const(id) => ( - format!("`const {}`", name.display(db)), - Const::from(id) - .source(db) - .map(|it| it.syntax().value.text_range()) - .unwrap_or(default_range), - ), - hir::AssocItem::TypeAlias(id) => ( - format!("`type {}`", name.display(db)), - TypeAlias::from(id) - .source(db) - .map(|it| it.syntax().value.text_range()) - .unwrap_or(default_range), - ), + let (redundant_item_name, diagnostic_range, redundant_item_def) = match assoc_item { + hir::AssocItem::Function(id) => { + let function = Function::from(id); + ( + format!("`fn {}`", redundant_assoc_item_name), + function + .source(db) + .map(|it| it.syntax().value.text_range()) + .unwrap_or(default_range), + format!("\n {};", function.display(db)), + ) + } + hir::AssocItem::Const(id) => { + let constant = Const::from(id); + ( + format!("`const {}`", redundant_assoc_item_name), + constant + .source(db) + .map(|it| it.syntax().value.text_range()) + .unwrap_or(default_range), + format!("\n {};", constant.display(db)), + ) + } + hir::AssocItem::TypeAlias(id) => { + let type_alias = TypeAlias::from(id); + ( + format!("`type {}`", redundant_assoc_item_name), + type_alias + .source(db) + .map(|it| it.syntax().value.text_range()) + .unwrap_or(default_range), + format!("\n type {};", type_alias.name(ctx.sema.db).to_smol_str()), + ) + } }; Diagnostic::new( DiagnosticCode::RustcHardError("E0407"), format!("{redundant_item_name} is not a member of trait `{trait_name}`"), - FileRange { file_id: d.file_id.file_id().unwrap(), range: diagnostic_range }, + hir::InFile::new(d.file_id, diagnostic_range).original_node_file_range_rooted(db), ) + .with_fixes(quickfix_for_redundant_assoc_item( + ctx, + d, + redundant_item_def, + diagnostic_range, + )) +} + +/// add assoc item into the trait def body +fn quickfix_for_redundant_assoc_item( + ctx: &DiagnosticsContext<'_>, + d: &hir::TraitImplRedundantAssocItems, + redundant_item_def: String, + range: TextRange, +) -> Option> { + let add_assoc_item_def = |builder: &mut SourceChangeBuilder| -> Option<()> { + let db = ctx.sema.db; + let root = db.parse_or_expand(d.file_id); + // don't modify trait def in outer crate + let current_crate = ctx.sema.scope(&d.impl_.syntax_node_ptr().to_node(&root))?.krate(); + let trait_def_crate = d.trait_.module(db).krate(); + if trait_def_crate != current_crate { + return None; + } + + let trait_def = d.trait_.source(db)?.value; + let l_curly = trait_def.assoc_item_list()?.l_curly_token()?.text_range(); + let where_to_insert = + hir::InFile::new(d.file_id, l_curly).original_node_file_range_rooted(db).range; + + Some(builder.insert(where_to_insert.end(), redundant_item_def)) + }; + let file_id = d.file_id.file_id()?; + let mut source_change_builder = SourceChangeBuilder::new(file_id); + add_assoc_item_def(&mut source_change_builder)?; + + Some(vec![Assist { + id: AssistId("add assoc item def into trait def", AssistKind::QuickFix), + label: Label::new("Add assoc item def into trait def".to_string()), + group: None, + target: range, + source_change: Some(source_change_builder.finish()), + trigger_signature_help: false, + }]) } #[cfg(test)] mod tests { - use crate::tests::check_diagnostics; + use crate::tests::{check_diagnostics, check_fix, check_no_fix}; + + #[test] + fn quickfix_for_assoc_func() { + check_fix( + r#" +trait Marker { + fn boo(); +} +struct Foo; +impl Marker for Foo { + fn$0 bar(_a: i32, _b: String) -> String {} + fn boo() {} +} + "#, + r#" +trait Marker { + fn bar(_a: i32, _b: String) -> String; + fn boo(); +} +struct Foo; +impl Marker for Foo { + fn bar(_a: i32, _b: String) -> String {} + fn boo() {} +} + "#, + ) + } + + #[test] + fn quickfix_for_assoc_const() { + check_fix( + r#" +trait Marker { + fn foo () {} +} +struct Foo; +impl Marker for Foo { + const FLAG: bool$0 = false; +} + "#, + r#" +trait Marker { + const FLAG: bool; + fn foo () {} +} +struct Foo; +impl Marker for Foo { + const FLAG: bool = false; +} + "#, + ) + } + + #[test] + fn quickfix_for_assoc_type() { + check_fix( + r#" +trait Marker { +} +struct Foo; +impl Marker for Foo { + type T = i32;$0 +} + "#, + r#" +trait Marker { + type T; +} +struct Foo; +impl Marker for Foo { + type T = i32; +} + "#, + ) + } + + #[test] + fn quickfix_dont_work() { + check_no_fix( + r#" + //- /dep.rs crate:dep + trait Marker { + } + //- /main.rs crate:main deps:dep + struct Foo; + impl dep::Marker for Foo { + type T = i32;$0 + } + "#, + ) + } #[test] fn trait_with_default_value() { @@ -64,12 +217,12 @@ trait Marker { struct Foo; impl Marker for Foo { type T = i32; - //^^^^^^^^^^^^^ error: `type T` is not a member of trait `Marker` + //^^^^^^^^^^^^^ 💡 error: `type T` is not a member of trait `Marker` const FLAG: bool = true; fn bar() {} - //^^^^^^^^^^^ error: `fn bar` is not a member of trait `Marker` + //^^^^^^^^^^^ 💡 error: `fn bar` is not a member of trait `Marker` fn boo() {} } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 60a45a05a4a1..41fb67290852 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -160,7 +160,7 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) - // if receiver should be pass as first arg in the assoc func, // we could omit generic parameters cause compiler can deduce it automatically if !need_to_take_receiver_as_first_arg && !generic_parameters.is_empty() { - let generic_parameters = generic_parameters.join(", ").to_string(); + let generic_parameters = generic_parameters.join(", "); receiver_type_adt_name = format!("{}::<{}>", receiver_type_adt_name, generic_parameters); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs index e90d385bab8c..4d7d425bab34 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs @@ -58,9 +58,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedModule) -> Option Option { let mod_path = definition_mod_path(db, &def); - let (label, docs) = match def { - Definition::Macro(it) => label_and_docs(db, it), - Definition::Field(it) => label_and_layout_info_and_docs( - db, - it, - config, - |&it| it.layout(db), - |_| { - let var_def = it.parent_def(db); - match var_def { - hir::VariantDef::Struct(s) => { - Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(it)) + let label = def.label(db)?; + let docs = def.docs(db, famous_defs); + + let value = match def { + Definition::Variant(it) => { + if !it.parent_enum(db).is_data_carrying(db) { + match it.eval(db) { + Ok(it) => { + Some(if it >= 10 { format!("{it} ({it:#X})") } else { format!("{it}") }) } - _ => None, + Err(_) => it.value(db).map(|it| format!("{it:?}")), } - }, - ), - Definition::Module(it) => label_and_docs(db, it), - Definition::Function(it) => label_and_docs(db, it), - Definition::Adt(it) => { - label_and_layout_info_and_docs(db, it, config, |&it| it.layout(db), |_| None) + } else { + None + } } - Definition::Variant(it) => label_value_and_layout_info_and_docs( - db, - it, - config, - |&it| { - if !it.parent_enum(db).is_data_carrying(db) { - match it.eval(db) { - Ok(it) => { - Some(if it >= 10 { format!("{it} ({it:#X})") } else { format!("{it}") }) - } - Err(_) => it.value(db).map(|it| format!("{it:?}")), - } - } else { - None - } - }, - |it| it.layout(db), - |layout| layout.enum_tag_size(), - ), - Definition::Const(it) => label_value_and_docs(db, it, |it| { + Definition::Const(it) => { let body = it.render_eval(db); match body { Ok(it) => Some(it), @@ -447,53 +417,59 @@ pub(super) fn definition( Some(body.to_string()) } } - }), - Definition::Static(it) => label_value_and_docs(db, it, |it| { + } + Definition::Static(it) => { let source = it.source(db)?; let mut body = source.value.body()?.syntax().clone(); if source.file_id.is_macro() { body = insert_whitespace_into_node::insert_ws_into(body); } Some(body.to_string()) - }), - Definition::Trait(it) => label_and_docs(db, it), - Definition::TraitAlias(it) => label_and_docs(db, it), - Definition::TypeAlias(it) => { - label_and_layout_info_and_docs(db, it, config, |&it| it.ty(db).layout(db), |_| None) - } - Definition::BuiltinType(it) => { - return famous_defs - .and_then(|fd| builtin(fd, it)) - .or_else(|| Some(Markup::fenced_block(&it.name().display(db)))) - } - Definition::Local(it) => return local(db, it, config), - Definition::SelfType(impl_def) => { - impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))? - } - Definition::GenericParam(it) => (it.display(db).to_string(), None), - Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db).display(db))), - Definition::ExternCrateDecl(it) => label_and_docs(db, it), - // FIXME: We should be able to show more info about these - Definition::BuiltinAttr(it) => return render_builtin_attr(db, it), - Definition::ToolModule(it) => return Some(Markup::fenced_block(&it.name(db))), - Definition::DeriveHelper(it) => { - (format!("derive_helper {}", it.name(db).display(db)), None) } + _ => None, }; - let docs = docs - .filter(|_| config.documentation) - .or_else(|| { - // docs are missing, for assoc items of trait impls try to fall back to the docs of the - // original item of the trait - let assoc = def.as_assoc_item(db)?; - let trait_ = assoc.containing_trait_impl(db)?; - let name = Some(assoc.name(db)?); - let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?; - item.docs(db) - }) - .map(Into::into); - markup(docs, label, mod_path) + let layout_info = match def { + Definition::Field(it) => render_memory_layout( + config.memory_layout, + || it.layout(db), + |_| { + let var_def = it.parent_def(db); + match var_def { + hir::VariantDef::Struct(s) => { + Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(it)) + } + _ => None, + } + }, + |_| None, + ), + Definition::Adt(it) => { + render_memory_layout(config.memory_layout, || it.layout(db), |_| None, |_| None) + } + Definition::Variant(it) => render_memory_layout( + config.memory_layout, + || it.layout(db), + |_| None, + |layout| layout.enum_tag_size(), + ), + Definition::TypeAlias(it) => { + render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None) + } + Definition::Local(it) => { + render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None) + } + _ => None, + }; + + let label = match (value, layout_info) { + (Some(value), Some(layout_info)) => format!("{label} = {value}{layout_info}"), + (Some(value), None) => format!("{label} = {value}"), + (None, Some(layout_info)) => format!("{label}{layout_info}"), + (None, None) => label, + }; + + markup(docs.map(Into::into), label, mod_path) } fn type_info( @@ -595,114 +571,16 @@ fn closure_ty( Some(res) } -fn render_builtin_attr(db: &RootDatabase, attr: hir::BuiltinAttr) -> Option { - let name = attr.name(db); - let desc = format!("#[{name}]"); - - let AttributeTemplate { word, list, name_value_str } = match attr.template(db) { - Some(template) => template, - None => return Some(Markup::fenced_block(&attr.name(db))), - }; - let mut docs = "Valid forms are:".to_owned(); - if word { - format_to!(docs, "\n - #\\[{}]", name); - } - if let Some(list) = list { - format_to!(docs, "\n - #\\[{}({})]", name, list); - } - if let Some(name_value_str) = name_value_str { - format_to!(docs, "\n - #\\[{} = {}]", name, name_value_str); - } - markup(Some(docs.replace('*', "\\*")), desc, None) -} - -fn label_and_docs(db: &RootDatabase, def: D) -> (String, Option) -where - D: HasDocs + HirDisplay, -{ - let label = def.display(db).to_string(); - let docs = def.docs(db); - (label, docs) -} - -fn label_and_layout_info_and_docs( - db: &RootDatabase, - def: D, - config: &HoverConfig, - layout_extractor: E, - layout_offset_extractor: E2, -) -> (String, Option) -where - D: HasDocs + HirDisplay, - E: Fn(&D) -> Result, - E2: Fn(&Layout) -> Option, -{ - let mut label = def.display(db).to_string(); - if let Some(layout) = render_memory_layout( - config.memory_layout, - || layout_extractor(&def), - layout_offset_extractor, - |_| None, - ) { - format_to!(label, "{layout}"); - } - let docs = def.docs(db); - (label, docs) -} - -fn label_value_and_layout_info_and_docs( - db: &RootDatabase, - def: D, - config: &HoverConfig, - value_extractor: E, - layout_extractor: E2, - layout_tag_extractor: E3, -) -> (String, Option) -where - D: HasDocs + HirDisplay, - E: Fn(&D) -> Option, - E2: Fn(&D) -> Result, - E3: Fn(&Layout) -> Option, - V: Display, -{ - let value = value_extractor(&def); - let mut label = match value { - Some(value) => format!("{} = {value}", def.display(db)), - None => def.display(db).to_string(), - }; - if let Some(layout) = render_memory_layout( - config.memory_layout, - || layout_extractor(&def), - |_| None, - layout_tag_extractor, - ) { - format_to!(label, "{layout}"); - } - let docs = def.docs(db); - (label, docs) -} - -fn label_value_and_docs( - db: &RootDatabase, - def: D, - value_extractor: E, -) -> (String, Option) -where - D: HasDocs + HirDisplay, - E: Fn(&D) -> Option, - V: Display, -{ - let label = if let Some(value) = value_extractor(&def) { - format!("{} = {value}", def.display(db)) - } else { - def.display(db).to_string() - }; - let docs = def.docs(db); - (label, docs) -} - fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option { - if let Definition::GenericParam(_) = def { + if matches!( + def, + Definition::GenericParam(_) + | Definition::BuiltinType(_) + | Definition::Local(_) + | Definition::Label(_) + | Definition::BuiltinAttr(_) + | Definition::ToolModule(_) + ) { return None; } def.module(db).map(|module| path(db, module, definition_owner_name(db, def))) @@ -724,14 +602,6 @@ fn markup(docs: Option, desc: String, mod_path: Option) -> Optio Some(buf.into()) } -fn builtin(famous_defs: &FamousDefs<'_, '_>, builtin: hir::BuiltinType) -> Option { - // std exposes prim_{} modules with docstrings on the root to document the builtins - let primitive_mod = format!("prim_{}", builtin.name().display(famous_defs.0.db)); - let doc_owner = find_std_module(famous_defs, &primitive_mod)?; - let docs = doc_owner.docs(famous_defs.0.db)?; - markup(Some(docs.into()), builtin.name().display(famous_defs.0.db).to_string(), None) -} - fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option { let db = famous_defs.0.db; let std_crate = famous_defs.std()?; @@ -741,34 +611,6 @@ fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option Option { - let ty = it.ty(db); - let ty = ty.display_truncated(db, None); - let is_mut = if it.is_mut(db) { "mut " } else { "" }; - let mut desc = match it.primary_source(db).into_ident_pat() { - Some(ident) => { - let name = it.name(db); - let let_kw = if ident - .syntax() - .parent() - .map_or(false, |p| p.kind() == LET_STMT || p.kind() == LET_EXPR) - { - "let " - } else { - "" - }; - format!("{let_kw}{is_mut}{}: {ty}", name.display(db)) - } - None => format!("{is_mut}self: {ty}"), - }; - if let Some(layout) = - render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None) - { - format_to!(desc, "{layout}"); - } - markup(None, desc, None) -} - fn render_memory_layout( config: Option, layout: impl FnOnce() -> Result, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index e82d730e4a36..f466b8e938f9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -32,6 +32,7 @@ mod fn_lifetime_fn; mod implicit_static; mod param_name; mod implicit_drop; +mod range_exclusive; #[derive(Clone, Debug, PartialEq, Eq)] pub struct InlayHintsConfig { @@ -51,6 +52,7 @@ pub struct InlayHintsConfig { pub param_names_for_lifetime_elision_hints: bool, pub hide_named_constructor_hints: bool, pub hide_closure_initialization_hints: bool, + pub range_exclusive_hints: bool, pub closure_style: ClosureStyle, pub max_length: Option, pub closing_brace_hints_min_lines: Option, @@ -127,6 +129,7 @@ pub enum InlayKind { Parameter, Type, Drop, + RangeExclusive, } #[derive(Debug)] @@ -517,13 +520,20 @@ fn hints( closure_captures::hints(hints, famous_defs, config, file_id, it.clone()); closure_ret::hints(hints, famous_defs, config, file_id, it) }, + ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, config, it), _ => None, } }, ast::Pat(it) => { binding_mode::hints(hints, sema, config, &it); - if let ast::Pat::IdentPat(it) = it { - bind_pat::hints(hints, famous_defs, config, file_id, &it); + match it { + ast::Pat::IdentPat(it) => { + bind_pat::hints(hints, famous_defs, config, file_id, &it); + } + ast::Pat::RangePat(it) => { + range_exclusive::hints(hints, config, it); + } + _ => {} } Some(()) }, @@ -593,7 +603,6 @@ mod tests { use hir::ClosureStyle; use itertools::Itertools; use test_utils::extract_annotations; - use text_edit::{TextRange, TextSize}; use crate::inlay_hints::{AdjustmentHints, AdjustmentHintsMode}; use crate::DiscriminantHints; @@ -622,6 +631,7 @@ mod tests { closing_brace_hints_min_lines: None, fields_to_resolve: InlayFieldsToResolve::empty(), implicit_drop_hints: false, + range_exclusive_hints: false, }; pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig { type_hints: true, @@ -654,29 +664,6 @@ mod tests { assert_eq!(expected, actual, "\nExpected:\n{expected:#?}\n\nActual:\n{actual:#?}"); } - #[track_caller] - pub(super) fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { - let (analysis, file_id) = fixture::file(ra_fixture); - let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); - expect.assert_debug_eq(&inlay_hints) - } - - #[track_caller] - pub(super) fn check_expect_clear_loc( - config: InlayHintsConfig, - ra_fixture: &str, - expect: Expect, - ) { - let (analysis, file_id) = fixture::file(ra_fixture); - let mut inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); - inlay_hints.iter_mut().flat_map(|hint| &mut hint.label.parts).for_each(|hint| { - if let Some(loc) = &mut hint.linked_location { - loc.range = TextRange::empty(TextSize::from(0)); - } - }); - expect.assert_debug_eq(&inlay_hints) - } - /// Computes inlay hints for the fixture, applies all the provided text edits and then runs /// expect test. #[track_caller] diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs index c9e9a2237867..b6063978e923 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs @@ -75,12 +75,12 @@ pub(super) fn hints( #[cfg(test)] mod tests { - use expect_test::expect; + use expect_test::{expect, Expect}; + use text_edit::{TextRange, TextSize}; use crate::{ - inlay_hints::tests::{ - check_expect, check_expect_clear_loc, check_with_config, DISABLED_CONFIG, TEST_CONFIG, - }, + fixture, + inlay_hints::tests::{check_with_config, DISABLED_CONFIG, TEST_CONFIG}, InlayHintsConfig, }; @@ -89,6 +89,33 @@ mod tests { check_with_config(InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, ra_fixture); } + #[track_caller] + pub(super) fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { + let (analysis, file_id) = fixture::file(ra_fixture); + let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); + let filtered = + inlay_hints.into_iter().map(|hint| (hint.range, hint.label)).collect::>(); + expect.assert_debug_eq(&filtered) + } + + #[track_caller] + pub(super) fn check_expect_clear_loc( + config: InlayHintsConfig, + ra_fixture: &str, + expect: Expect, + ) { + let (analysis, file_id) = fixture::file(ra_fixture); + let mut inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); + inlay_hints.iter_mut().flat_map(|hint| &mut hint.label.parts).for_each(|hint| { + if let Some(loc) = &mut hint.linked_location { + loc.range = TextRange::empty(TextSize::from(0)); + } + }); + let filtered = + inlay_hints.into_iter().map(|hint| (hint.range, hint.label)).collect::>(); + expect.assert_debug_eq(&filtered) + } + #[test] fn chaining_hints_ignore_comments() { check_expect( @@ -109,13 +136,9 @@ fn main() { "#, expect![[r#" [ - InlayHint { - range: 147..172, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ( + 147..172, + [ "", InlayHintLabelPart { text: "B", @@ -131,16 +154,10 @@ fn main() { }, "", ], - text_edit: None, - needs_resolve: true, - }, - InlayHint { - range: 147..154, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ), + ( + 147..154, + [ "", InlayHintLabelPart { text: "A", @@ -156,9 +173,7 @@ fn main() { }, "", ], - text_edit: None, - needs_resolve: true, - }, + ), ] "#]], ); @@ -204,13 +219,9 @@ fn main() { }"#, expect![[r#" [ - InlayHint { - range: 143..190, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ( + 143..190, + [ "", InlayHintLabelPart { text: "C", @@ -226,16 +237,10 @@ fn main() { }, "", ], - text_edit: None, - needs_resolve: true, - }, - InlayHint { - range: 143..179, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ), + ( + 143..179, + [ "", InlayHintLabelPart { text: "B", @@ -251,9 +256,7 @@ fn main() { }, "", ], - text_edit: None, - needs_resolve: true, - }, + ), ] "#]], ); @@ -283,13 +286,9 @@ fn main() { }"#, expect![[r#" [ - InlayHint { - range: 143..190, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ( + 143..190, + [ "", InlayHintLabelPart { text: "C", @@ -305,16 +304,10 @@ fn main() { }, "", ], - text_edit: None, - needs_resolve: true, - }, - InlayHint { - range: 143..179, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ), + ( + 143..179, + [ "", InlayHintLabelPart { text: "B", @@ -330,9 +323,7 @@ fn main() { }, "", ], - text_edit: None, - needs_resolve: true, - }, + ), ] "#]], ); @@ -363,13 +354,9 @@ fn main() { "#, expect![[r#" [ - InlayHint { - range: 246..283, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ( + 246..283, + [ "", InlayHintLabelPart { text: "B", @@ -398,16 +385,10 @@ fn main() { }, ">", ], - text_edit: None, - needs_resolve: true, - }, - InlayHint { - range: 246..265, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ), + ( + 246..265, + [ "", InlayHintLabelPart { text: "A", @@ -436,9 +417,7 @@ fn main() { }, ">", ], - text_edit: None, - needs_resolve: true, - }, + ), ] "#]], ); @@ -471,13 +450,9 @@ fn main() { "#, expect![[r#" [ - InlayHint { - range: 174..241, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ( + 174..241, + [ "impl ", InlayHintLabelPart { text: "Iterator", @@ -506,16 +481,10 @@ fn main() { }, " = ()>", ], - text_edit: None, - needs_resolve: true, - }, - InlayHint { - range: 174..224, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ), + ( + 174..224, + [ "impl ", InlayHintLabelPart { text: "Iterator", @@ -544,16 +513,10 @@ fn main() { }, " = ()>", ], - text_edit: None, - needs_resolve: true, - }, - InlayHint { - range: 174..206, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ), + ( + 174..206, + [ "impl ", InlayHintLabelPart { text: "Iterator", @@ -582,16 +545,10 @@ fn main() { }, " = ()>", ], - text_edit: None, - needs_resolve: true, - }, - InlayHint { - range: 174..189, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ), + ( + 174..189, + [ "&mut ", InlayHintLabelPart { text: "MyIter", @@ -607,9 +564,7 @@ fn main() { }, "", ], - text_edit: None, - needs_resolve: true, - }, + ), ] "#]], ); @@ -639,13 +594,9 @@ fn main() { "#, expect![[r#" [ - InlayHint { - range: 124..130, - position: After, - pad_left: true, - pad_right: false, - kind: Type, - label: [ + ( + 124..130, + [ "", InlayHintLabelPart { text: "Struct", @@ -661,25 +612,10 @@ fn main() { }, "", ], - text_edit: Some( - TextEdit { - indels: [ - Indel { - insert: ": Struct", - delete: 130..130, - }, - ], - }, - ), - needs_resolve: true, - }, - InlayHint { - range: 145..185, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ), + ( + 145..185, + [ "", InlayHintLabelPart { text: "Struct", @@ -695,16 +631,10 @@ fn main() { }, "", ], - text_edit: None, - needs_resolve: true, - }, - InlayHint { - range: 145..168, - position: After, - pad_left: true, - pad_right: false, - kind: Chaining, - label: [ + ), + ( + 145..168, + [ "", InlayHintLabelPart { text: "Struct", @@ -720,16 +650,10 @@ fn main() { }, "", ], - text_edit: None, - needs_resolve: true, - }, - InlayHint { - range: 222..228, - position: Before, - pad_left: false, - pad_right: true, - kind: Parameter, - label: [ + ), + ( + 222..228, + [ InlayHintLabelPart { text: "self", linked_location: Some( @@ -743,9 +667,7 @@ fn main() { tooltip: "", }, ], - text_edit: None, - needs_resolve: true, - }, + ), ] "#]], ); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs new file mode 100644 index 000000000000..50ab15c504f6 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs @@ -0,0 +1,121 @@ +//! Implementation of "range exclusive" inlay hints: +//! ```no_run +//! for i in 0../* < */10 {} +//! if let ../* < */100 = 50 {} +//! ``` +use syntax::{ast, SyntaxToken, T}; + +use crate::{InlayHint, InlayHintsConfig}; + +pub(super) fn hints( + acc: &mut Vec, + config: &InlayHintsConfig, + range: impl ast::RangeItem, +) -> Option<()> { + (config.range_exclusive_hints && range.end().is_some()) + .then(|| { + range.op_token().filter(|token| token.kind() == T![..]).map(|token| { + acc.push(inlay_hint(token)); + }) + }) + .flatten() +} + +fn inlay_hint(token: SyntaxToken) -> InlayHint { + InlayHint { + range: token.text_range(), + position: crate::InlayHintPosition::After, + pad_left: false, + pad_right: false, + kind: crate::InlayKind::RangeExclusive, + label: crate::InlayHintLabel::from("<"), + text_edit: None, + needs_resolve: false, + } +} + +#[cfg(test)] +mod tests { + use crate::{ + inlay_hints::tests::{check_with_config, DISABLED_CONFIG}, + InlayHintsConfig, + }; + + #[test] + fn range_exclusive_expression_bounded_above_hints() { + check_with_config( + InlayHintsConfig { range_exclusive_hints: true, ..DISABLED_CONFIG }, + r#" +fn main() { + let a = 0..10; + //^^< + let b = ..100; + //^^< + let c = (2 - 1)..(7 * 8) + //^^< +}"#, + ); + } + + #[test] + fn range_exclusive_expression_unbounded_above_no_hints() { + check_with_config( + InlayHintsConfig { range_exclusive_hints: true, ..DISABLED_CONFIG }, + r#" +fn main() { + let a = 0..; + let b = ..; +}"#, + ); + } + + #[test] + fn range_inclusive_expression_no_hints() { + check_with_config( + InlayHintsConfig { range_exclusive_hints: true, ..DISABLED_CONFIG }, + r#" +fn main() { + let a = 0..=10; + let b = ..=100; +}"#, + ); + } + + #[test] + fn range_exclusive_pattern_bounded_above_hints() { + check_with_config( + InlayHintsConfig { range_exclusive_hints: true, ..DISABLED_CONFIG }, + r#" +fn main() { + if let 0..10 = 0 {} + //^^< + if let ..100 = 0 {} + //^^< +}"#, + ); + } + + #[test] + fn range_exclusive_pattern_unbounded_above_no_hints() { + check_with_config( + InlayHintsConfig { range_exclusive_hints: true, ..DISABLED_CONFIG }, + r#" +fn main() { + if let 0.. = 0 {} + if let .. = 0 {} +}"#, + ); + } + + #[test] + fn range_inclusive_pattern_no_hints() { + check_with_config( + InlayHintsConfig { range_exclusive_hints: true, ..DISABLED_CONFIG }, + r#" +fn main() { + if let 0..=10 = 0 {} + if let ..=100 = 0 {} +}"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 6ff16b9e2f71..c98e9fba120a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -99,7 +99,10 @@ pub use crate::{ }, join_lines::JoinLinesConfig, markup::Markup, - moniker::{MonikerDescriptorKind, MonikerKind, MonikerResult, PackageInformation}, + moniker::{ + MonikerDescriptorKind, MonikerKind, MonikerResult, PackageInformation, + SymbolInformationKind, + }, move_item::Direction, navigation_target::{NavigationTarget, UpmappingResult}, prime_caches::ParallelPrimeCachesProgress, @@ -411,11 +414,12 @@ impl Analysis { } /// Fuzzy searches for a symbol. - pub fn symbol_search(&self, query: Query) -> Cancellable> { + pub fn symbol_search(&self, query: Query, limit: usize) -> Cancellable> { self.with_db(|db| { symbol_index::world_symbols(db, query) .into_iter() // xx: should we make this a par iter? .filter_map(|s| s.try_to_nav(db)) + .take(limit) .map(UpmappingResult::call_site) .collect::>() }) diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index 8e8bb5e0139e..486329dadeda 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -1,7 +1,7 @@ //! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports) //! for LSIF and LSP. -use hir::{AsAssocItem, AssocItemContainer, Crate, DescendPreference, Semantics}; +use hir::{Adt, AsAssocItem, AssocItemContainer, Crate, DescendPreference, MacroKind, Semantics}; use ide_db::{ base_db::{CrateOrigin, FilePosition, LangCrateOrigin}, defs::{Definition, IdentClass}, @@ -25,6 +25,62 @@ pub enum MonikerDescriptorKind { Meta, } +// Subset of scip_types::SymbolInformation::Kind +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum SymbolInformationKind { + AssociatedType, + Attribute, + Constant, + Enum, + EnumMember, + Field, + Function, + Macro, + Method, + Module, + Parameter, + SelfParameter, + StaticMethod, + StaticVariable, + Struct, + Trait, + TraitMethod, + Type, + TypeAlias, + TypeParameter, + Union, + Variable, +} + +impl From for MonikerDescriptorKind { + fn from(value: SymbolInformationKind) -> Self { + match value { + SymbolInformationKind::AssociatedType => Self::TypeParameter, + SymbolInformationKind::Attribute => Self::Macro, + SymbolInformationKind::Constant => Self::Term, + SymbolInformationKind::Enum => Self::Type, + SymbolInformationKind::EnumMember => Self::Type, + SymbolInformationKind::Field => Self::Term, + SymbolInformationKind::Function => Self::Method, + SymbolInformationKind::Macro => Self::Macro, + SymbolInformationKind::Method => Self::Method, + SymbolInformationKind::Module => Self::Namespace, + SymbolInformationKind::Parameter => Self::Parameter, + SymbolInformationKind::SelfParameter => Self::Parameter, + SymbolInformationKind::StaticMethod => Self::Method, + SymbolInformationKind::StaticVariable => Self::Meta, + SymbolInformationKind::Struct => Self::Type, + SymbolInformationKind::Trait => Self::Type, + SymbolInformationKind::TraitMethod => Self::Method, + SymbolInformationKind::Type => Self::Type, + SymbolInformationKind::TypeAlias => Self::Type, + SymbolInformationKind::TypeParameter => Self::TypeParameter, + SymbolInformationKind::Union => Self::Type, + SymbolInformationKind::Variable => Self::Term, + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MonikerDescriptor { pub name: String, @@ -112,6 +168,69 @@ pub(crate) fn moniker( Some(RangeInfo::new(original_token.text_range(), navs)) } +pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformationKind { + use SymbolInformationKind::*; + + match def { + Definition::Macro(it) => match it.kind(db) { + MacroKind::Declarative => Macro, + MacroKind::Derive => Attribute, + MacroKind::BuiltIn => Macro, + MacroKind::Attr => Attribute, + MacroKind::ProcMacro => Macro, + }, + Definition::Field(..) | Definition::TupleField(..) => Field, + Definition::Module(..) => Module, + Definition::Function(it) => { + if it.as_assoc_item(db).is_some() { + if it.has_self_param(db) { + if it.has_body(db) { + Method + } else { + TraitMethod + } + } else { + StaticMethod + } + } else { + Function + } + } + Definition::Adt(Adt::Struct(..)) => Struct, + Definition::Adt(Adt::Union(..)) => Union, + Definition::Adt(Adt::Enum(..)) => Enum, + Definition::Variant(..) => EnumMember, + Definition::Const(..) => Constant, + Definition::Static(..) => StaticVariable, + Definition::Trait(..) => Trait, + Definition::TraitAlias(..) => Trait, + Definition::TypeAlias(it) => { + if it.as_assoc_item(db).is_some() { + AssociatedType + } else { + TypeAlias + } + } + Definition::BuiltinType(..) => Type, + Definition::SelfType(..) => TypeAlias, + Definition::GenericParam(..) => TypeParameter, + Definition::Local(it) => { + if it.is_self(db) { + SelfParameter + } else if it.is_param(db) { + Parameter + } else { + Variable + } + } + Definition::Label(..) => Variable, // For lack of a better variant + Definition::DeriveHelper(..) => Attribute, + Definition::BuiltinAttr(..) => Attribute, + Definition::ToolModule(..) => Module, + Definition::ExternCrateDecl(..) => Module, + } +} + pub(crate) fn def_to_moniker( db: &RootDatabase, def: Definition, @@ -134,7 +253,7 @@ pub(crate) fn def_to_moniker( description.extend(module.path_to_root(db).into_iter().filter_map(|x| { Some(MonikerDescriptor { name: x.name(db)?.display(db).to_string(), - desc: MonikerDescriptorKind::Namespace, + desc: def_to_kind(db, x.into()).into(), }) })); @@ -147,7 +266,7 @@ pub(crate) fn def_to_moniker( // we have to include the trait name as part of the moniker for uniqueness. description.push(MonikerDescriptor { name: trait_.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, + desc: def_to_kind(db, trait_.into()).into(), }); } AssocItemContainer::Impl(impl_) => { @@ -156,14 +275,14 @@ pub(crate) fn def_to_moniker( if let Some(adt) = impl_.self_ty(db).as_adt() { description.push(MonikerDescriptor { name: adt.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, + desc: def_to_kind(db, adt.into()).into(), }); } if let Some(trait_) = impl_.trait_(db) { description.push(MonikerDescriptor { name: trait_.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, + desc: def_to_kind(db, trait_.into()).into(), }); } } @@ -173,21 +292,26 @@ pub(crate) fn def_to_moniker( if let Definition::Field(it) = def { description.push(MonikerDescriptor { name: it.parent_def(db).name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, + desc: def_to_kind(db, it.parent_def(db).into()).into(), }); } // Qualify locals/parameters by their parent definition name. if let Definition::Local(it) = def { - let parent_name = it.parent(db).name(db); - if let Some(name) = parent_name { - description.push(MonikerDescriptor { - name: name.display(db).to_string(), - desc: MonikerDescriptorKind::Method, - }); + let parent = Definition::try_from(it.parent(db)).ok(); + if let Some(parent) = parent { + let parent_name = parent.name(db); + if let Some(name) = parent_name { + description.push(MonikerDescriptor { + name: name.display(db).to_string(), + desc: def_to_kind(db, parent).into(), + }); + } } } + let desc = def_to_kind(db, def).into(); + let name_desc = match def { // These are handled by top-level guard (for performance). Definition::GenericParam(_) @@ -201,67 +325,54 @@ pub(crate) fn def_to_moniker( return None; } - MonikerDescriptor { - name: local.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Parameter, - } + MonikerDescriptor { name: local.name(db).display(db).to_string(), desc } + } + Definition::Macro(m) => { + MonikerDescriptor { name: m.name(db).display(db).to_string(), desc } + } + Definition::Function(f) => { + MonikerDescriptor { name: f.name(db).display(db).to_string(), desc } + } + Definition::Variant(v) => { + MonikerDescriptor { name: v.name(db).display(db).to_string(), desc } + } + Definition::Const(c) => { + MonikerDescriptor { name: c.name(db)?.display(db).to_string(), desc } + } + Definition::Trait(trait_) => { + MonikerDescriptor { name: trait_.name(db).display(db).to_string(), desc } + } + Definition::TraitAlias(ta) => { + MonikerDescriptor { name: ta.name(db).display(db).to_string(), desc } + } + Definition::TypeAlias(ta) => { + MonikerDescriptor { name: ta.name(db).display(db).to_string(), desc } + } + Definition::Module(m) => { + MonikerDescriptor { name: m.name(db)?.display(db).to_string(), desc } + } + Definition::BuiltinType(b) => { + MonikerDescriptor { name: b.name().display(db).to_string(), desc } } - Definition::Macro(m) => MonikerDescriptor { - name: m.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Macro, - }, - Definition::Function(f) => MonikerDescriptor { - name: f.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Method, - }, - Definition::Variant(v) => MonikerDescriptor { - name: v.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, - }, - Definition::Const(c) => MonikerDescriptor { - name: c.name(db)?.display(db).to_string(), - desc: MonikerDescriptorKind::Term, - }, - Definition::Trait(trait_) => MonikerDescriptor { - name: trait_.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, - }, - Definition::TraitAlias(ta) => MonikerDescriptor { - name: ta.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, - }, - Definition::TypeAlias(ta) => MonikerDescriptor { - name: ta.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::TypeParameter, - }, - Definition::Module(m) => MonikerDescriptor { - name: m.name(db)?.display(db).to_string(), - desc: MonikerDescriptorKind::Namespace, - }, - Definition::BuiltinType(b) => MonikerDescriptor { - name: b.name().display(db).to_string(), - desc: MonikerDescriptorKind::Type, - }, Definition::SelfType(imp) => MonikerDescriptor { name: imp.self_ty(db).as_adt()?.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, - }, - Definition::Field(it) => MonikerDescriptor { - name: it.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Term, - }, - Definition::Adt(adt) => MonikerDescriptor { - name: adt.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, - }, - Definition::Static(s) => MonikerDescriptor { - name: s.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Meta, - }, - Definition::ExternCrateDecl(m) => MonikerDescriptor { - name: m.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Namespace, + desc, }, + Definition::Field(it) => { + MonikerDescriptor { name: it.name(db).display(db).to_string(), desc } + } + Definition::TupleField(it) => { + MonikerDescriptor { name: it.name().display(db).to_string(), desc } + } + Definition::Adt(adt) => { + MonikerDescriptor { name: adt.name(db).display(db).to_string(), desc } + } + Definition::Static(s) => { + MonikerDescriptor { name: s.name(db).display(db).to_string(), desc } + } + Definition::ExternCrateDecl(m) => { + MonikerDescriptor { name: m.name(db).display(db).to_string(), desc } + } }; description.push(name_desc); diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index 6cb7d7724d5f..bc0574ca86ed 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -237,7 +237,7 @@ impl TryToNav for Definition { Definition::TraitAlias(it) => it.try_to_nav(db), Definition::TypeAlias(it) => it.try_to_nav(db), Definition::ExternCrateDecl(it) => Some(it.try_to_nav(db)?), - Definition::BuiltinType(_) => None, + Definition::BuiltinType(_) | Definition::TupleField(_) => None, Definition::ToolModule(_) => None, Definition::BuiltinAttr(_) => None, // FIXME: The focus range should be set to the helper declaration @@ -724,11 +724,8 @@ fn orig_range_with_focus( ) -> UpmappingResult<(FileRange, Option)> { let Some(name) = name else { return orig_range(db, hir_file, value) }; - let call_range = || { - db.lookup_intern_macro_call(hir_file.macro_file().unwrap().macro_call_id) - .kind - .original_call_range(db) - }; + let call_kind = + || db.lookup_intern_macro_call(hir_file.macro_file().unwrap().macro_call_id).kind; let def_range = || { db.lookup_intern_macro_call(hir_file.macro_file().unwrap().macro_call_id) @@ -755,7 +752,22 @@ fn orig_range_with_focus( } // name lies outside the node, so instead point to the macro call which // *should* contain the name - _ => call_range(), + _ => { + let kind = call_kind(); + let range = kind.clone().original_call_range_with_body(db); + //If the focus range is in the attribute/derive body, we + // need to point the call site to the entire body, if not, fall back + // to the name range of the attribute/derive call + // FIXME: Do this differently, this is very inflexible the caller + // should choose this behavior + if range.file_id == focus_range.file_id + && range.range.contains_range(focus_range.range) + { + range + } else { + kind.original_call_range(db) + } + } }, Some(focus_range), ), @@ -784,7 +796,7 @@ fn orig_range_with_focus( // node is in macro def, just show the focus _ => ( // show the macro call - (call_range(), None), + (call_kind().original_call_range(db), None), Some((focus_range, Some(focus_range))), ), } @@ -848,7 +860,7 @@ fn foo() { enum FooInner { } } "#, ); - let navs = analysis.symbol_search(Query::new("FooInner".to_string())).unwrap(); + let navs = analysis.symbol_search(Query::new("FooInner".to_string()), !0).unwrap(); expect![[r#" [ NavigationTarget { @@ -886,7 +898,7 @@ struct Foo; "#, ); - let navs = analysis.symbol_search(Query::new("foo".to_string())).unwrap(); + let navs = analysis.symbol_search(Query::new("foo".to_string()), !0).unwrap(); assert_eq!(navs.len(), 2) } } diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index 1febfabfcb7f..3bf41defe343 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -366,6 +366,7 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt #[cfg(test)] mod tests { use expect_test::{expect, Expect}; + use ide_db::source_change::SourceChange; use stdx::trim_indent; use test_utils::assert_eq_text; use text_edit::TextEdit; @@ -418,7 +419,7 @@ mod tests { let (analysis, position) = fixture::position(ra_fixture); let source_change = analysis.rename(position, new_name).unwrap().expect("Expect returned a RenameError"); - expect.assert_debug_eq(&source_change) + expect.assert_eq(&filter_expect(source_change)) } fn check_expect_will_rename_file(new_name: &str, ra_fixture: &str, expect: Expect) { @@ -427,7 +428,7 @@ mod tests { .will_rename_file(position.file_id, new_name) .unwrap() .expect("Expect returned a RenameError"); - expect.assert_debug_eq(&source_change) + expect.assert_eq(&filter_expect(source_change)) } fn check_prepare(ra_fixture: &str, expect: Expect) { @@ -444,6 +445,19 @@ mod tests { }; } + fn filter_expect(source_change: SourceChange) -> String { + let source_file_edits = source_change + .source_file_edits + .into_iter() + .map(|(id, (text_edit, _))| (id, text_edit.into_iter().collect::>())) + .collect::>(); + + format!( + "source_file_edits: {:#?}\nfile_system_edits: {:#?}\n", + source_file_edits, source_change.file_system_edits + ) + } + #[test] fn test_prepare_rename_namelikes() { check_prepare(r"fn name$0<'lifetime>() {}", expect![[r#"3..7: name"#]]); @@ -916,37 +930,32 @@ mod foo$0; // empty "#, expect![[r#" - SourceChange { - source_file_edits: { + source_file_edits: [ + ( FileId( 1, - ): ( - TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 4..7, - }, - ], - }, - None, ), - }, - file_system_edits: [ - MoveFile { - src: FileId( + [ + Indel { + insert: "foo2", + delete: 4..7, + }, + ], + ), + ] + file_system_edits: [ + MoveFile { + src: FileId( + 2, + ), + dst: AnchoredPathBuf { + anchor: FileId( 2, ), - dst: AnchoredPathBuf { - anchor: FileId( - 2, - ), - path: "foo2.rs", - }, + path: "foo2.rs", }, - ], - is_snippet: false, - } + }, + ] "#]], ); } @@ -968,50 +977,43 @@ pub struct FooContent; use crate::foo$0::FooContent; "#, expect![[r#" - SourceChange { - source_file_edits: { + source_file_edits: [ + ( FileId( 0, - ): ( - TextEdit { - indels: [ - Indel { - insert: "quux", - delete: 8..11, - }, - ], - }, - None, ), + [ + Indel { + insert: "quux", + delete: 8..11, + }, + ], + ), + ( FileId( 2, - ): ( - TextEdit { - indels: [ - Indel { - insert: "quux", - delete: 11..14, - }, - ], - }, - None, ), - }, - file_system_edits: [ - MoveFile { - src: FileId( + [ + Indel { + insert: "quux", + delete: 11..14, + }, + ], + ), + ] + file_system_edits: [ + MoveFile { + src: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( 1, ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "quux.rs", - }, + path: "quux.rs", }, - ], - is_snippet: false, - } + }, + ] "#]], ); } @@ -1027,43 +1029,38 @@ mod fo$0o; // empty "#, expect![[r#" - SourceChange { - source_file_edits: { + source_file_edits: [ + ( FileId( 0, - ): ( - TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 4..7, - }, - ], - }, - None, ), - }, - file_system_edits: [ - MoveDir { - src: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "../foo", + [ + Indel { + insert: "foo2", + delete: 4..7, }, - src_id: FileId( + ], + ), + ] + file_system_edits: [ + MoveDir { + src: AnchoredPathBuf { + anchor: FileId( 1, ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "../foo2", - }, + path: "../foo", }, - ], - is_snippet: false, - } + src_id: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( + 1, + ), + path: "../foo2", + }, + }, + ] "#]], ); } @@ -1080,37 +1077,32 @@ mod outer { mod fo$0o; } // empty "#, expect![[r#" - SourceChange { - source_file_edits: { + source_file_edits: [ + ( FileId( 0, - ): ( - TextEdit { - indels: [ - Indel { - insert: "bar", - delete: 16..19, - }, - ], - }, - None, ), - }, - file_system_edits: [ - MoveFile { - src: FileId( + [ + Indel { + insert: "bar", + delete: 16..19, + }, + ], + ), + ] + file_system_edits: [ + MoveFile { + src: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( 1, ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "bar.rs", - }, + path: "bar.rs", }, - ], - is_snippet: false, - } + }, + ] "#]], ); } @@ -1156,50 +1148,43 @@ pub mod foo$0; // pub fn fun() {} "#, expect![[r#" - SourceChange { - source_file_edits: { + source_file_edits: [ + ( FileId( 0, - ): ( - TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 27..30, - }, - ], - }, - None, ), + [ + Indel { + insert: "foo2", + delete: 27..30, + }, + ], + ), + ( FileId( 1, - ): ( - TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 8..11, - }, - ], - }, - None, ), - }, - file_system_edits: [ - MoveFile { - src: FileId( + [ + Indel { + insert: "foo2", + delete: 8..11, + }, + ], + ), + ] + file_system_edits: [ + MoveFile { + src: FileId( + 2, + ), + dst: AnchoredPathBuf { + anchor: FileId( 2, ), - dst: AnchoredPathBuf { - anchor: FileId( - 2, - ), - path: "foo2.rs", - }, + path: "foo2.rs", }, - ], - is_snippet: false, - } + }, + ] "#]], ); } @@ -1229,54 +1214,49 @@ mod quux; // empty "#, expect![[r#" - SourceChange { - source_file_edits: { + source_file_edits: [ + ( FileId( 0, - ): ( - TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 4..7, - }, - ], - }, - None, ), + [ + Indel { + insert: "foo2", + delete: 4..7, + }, + ], + ), + ] + file_system_edits: [ + MoveFile { + src: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( + 1, + ), + path: "foo2.rs", + }, }, - file_system_edits: [ - MoveFile { - src: FileId( + MoveDir { + src: AnchoredPathBuf { + anchor: FileId( 1, ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "foo2.rs", - }, + path: "foo", }, - MoveDir { - src: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "foo", - }, - src_id: FileId( + src_id: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( 1, ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "foo2", - }, + path: "foo2", }, - ], - is_snippet: false, - } + }, + ] "#]], ) } @@ -1344,12 +1324,9 @@ fn foo() {} mod bar$0; "#, expect![[r#" - SourceChange { - source_file_edits: {}, - file_system_edits: [], - is_snippet: false, - } - "#]], + source_file_edits: [] + file_system_edits: [] + "#]], ) } @@ -1370,58 +1347,53 @@ pub mod bar; pub fn baz() {} "#, expect![[r#" - SourceChange { - source_file_edits: { + source_file_edits: [ + ( FileId( 0, - ): ( - TextEdit { - indels: [ - Indel { - insert: "r#fn", - delete: 4..7, - }, - Indel { - insert: "r#fn", - delete: 22..25, - }, - ], - }, - None, ), + [ + Indel { + insert: "r#fn", + delete: 4..7, + }, + Indel { + insert: "r#fn", + delete: 22..25, + }, + ], + ), + ] + file_system_edits: [ + MoveFile { + src: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( + 1, + ), + path: "fn.rs", + }, }, - file_system_edits: [ - MoveFile { - src: FileId( + MoveDir { + src: AnchoredPathBuf { + anchor: FileId( 1, ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "fn.rs", - }, + path: "foo", }, - MoveDir { - src: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "foo", - }, - src_id: FileId( + src_id: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( 1, ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "fn", - }, + path: "fn", }, - ], - is_snippet: false, - } + }, + ] "#]], ); } @@ -1443,58 +1415,53 @@ pub mod bar; pub fn baz() {} "#, expect![[r#" - SourceChange { - source_file_edits: { + source_file_edits: [ + ( FileId( 0, - ): ( - TextEdit { - indels: [ - Indel { - insert: "foo", - delete: 4..8, - }, - Indel { - insert: "foo", - delete: 23..27, - }, - ], - }, - None, ), + [ + Indel { + insert: "foo", + delete: 4..8, + }, + Indel { + insert: "foo", + delete: 23..27, + }, + ], + ), + ] + file_system_edits: [ + MoveFile { + src: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( + 1, + ), + path: "foo.rs", + }, }, - file_system_edits: [ - MoveFile { - src: FileId( + MoveDir { + src: AnchoredPathBuf { + anchor: FileId( 1, ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "foo.rs", - }, + path: "fn", }, - MoveDir { - src: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "fn", - }, - src_id: FileId( + src_id: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( 1, ), - dst: AnchoredPathBuf { - anchor: FileId( - 1, - ), - path: "foo", - }, + path: "foo", }, - ], - is_snippet: false, - } + }, + ] "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index d334e66d3dd6..352ce89820de 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -555,28 +555,33 @@ mod tests { use crate::fixture; - use super::{RunnableTestKind::*, *}; - - fn check( - ra_fixture: &str, - // FIXME: fold this into `expect` as well - actions: &[RunnableTestKind], - expect: Expect, - ) { + fn check(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let mut runnables = analysis.runnables(position.file_id).unwrap(); runnables.sort_by_key(|it| (it.nav.full_range.start(), it.nav.name.clone())); - expect.assert_debug_eq(&runnables); - assert_eq!( - actions, - runnables.into_iter().map(|it| it.test_kind()).collect::>().as_slice() - ); + + let result = runnables + .into_iter() + .map(|runnable| { + let mut a = format!("({:?}, {:?}", runnable.test_kind(), runnable.nav); + if runnable.use_name_in_title { + a.push_str(", true"); + } + if let Some(cfg) = runnable.cfg { + a.push_str(&format!(", {cfg:?}")); + } + a.push_str(")"); + a + }) + .collect::>(); + expect.assert_debug_eq(&result); } fn check_tests(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let tests = analysis.related_tests(position, None).unwrap(); - expect.assert_debug_eq(&tests); + let navigation_targets = tests.into_iter().map(|runnable| runnable.nav).collect::>(); + expect.assert_debug_eq(&navigation_targets); } #[test] @@ -607,133 +612,15 @@ mod not_a_root { fn main() {} } "#, - &[TestMod, Bin, Bin, Test, Test, Test, Bench], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..253, - name: "", - kind: Module, - }, - kind: TestMod { - path: "", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..13, - focus_range: 4..8, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 15..76, - focus_range: 42..71, - name: "__cortex_m_rt_main_trampoline", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 78..102, - focus_range: 89..97, - name: "test_foo", - kind: Function, - }, - kind: Test { - test_id: Path( - "test_foo", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 104..155, - focus_range: 136..150, - name: "test_full_path", - kind: Function, - }, - kind: Test { - test_id: Path( - "test_full_path", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 157..191, - focus_range: 178..186, - name: "test_foo", - kind: Function, - }, - kind: Test { - test_id: Path( - "test_foo", - ), - attr: TestAttr { - ignore: true, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 193..215, - focus_range: 205..210, - name: "bench", - kind: Function, - }, - kind: Bench { - test_id: Path( - "bench", - ), - }, - cfg: None, - }, + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..253, name: \"\", kind: Module })", + "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(Bin, NavigationTarget { file_id: FileId(0), full_range: 15..76, focus_range: 42..71, name: \"__cortex_m_rt_main_trampoline\", kind: Function })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 78..102, focus_range: 89..97, name: \"test_foo\", kind: Function })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 104..155, focus_range: 136..150, name: \"test_full_path\", kind: Function })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 157..191, focus_range: 178..186, name: \"test_foo\", kind: Function })", + "(Bench, NavigationTarget { file_id: FileId(0), full_range: 193..215, focus_range: 205..210, name: \"bench\", kind: Function })", ] "#]], ); @@ -835,155 +722,17 @@ trait Test { /// ``` impl Test for StructWithRunnable {} "#, - &[Bin, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..13, - focus_range: 4..8, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 15..74, - name: "should_have_runnable", - }, - kind: DocTest { - test_id: Path( - "should_have_runnable", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 76..148, - name: "should_have_runnable_1", - }, - kind: DocTest { - test_id: Path( - "should_have_runnable_1", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 150..254, - name: "should_have_runnable_2", - }, - kind: DocTest { - test_id: Path( - "should_have_runnable_2", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 256..320, - name: "should_have_no_runnable_3", - }, - kind: DocTest { - test_id: Path( - "should_have_no_runnable_3", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 322..398, - name: "should_have_no_runnable_4", - }, - kind: DocTest { - test_id: Path( - "should_have_no_runnable_4", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 900..965, - name: "StructWithRunnable", - }, - kind: DocTest { - test_id: Path( - "StructWithRunnable", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 967..1024, - focus_range: 1003..1021, - name: "impl", - kind: Impl, - }, - kind: DocTest { - test_id: Path( - "StructWithRunnable", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1088..1154, - focus_range: 1133..1151, - name: "impl", - kind: Impl, - }, - kind: DocTest { - test_id: Path( - "StructWithRunnable", - ), - }, - cfg: None, - }, + "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 15..74, name: \"should_have_runnable\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 76..148, name: \"should_have_runnable_1\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 150..254, name: \"should_have_runnable_2\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 256..320, name: \"should_have_no_runnable_3\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 322..398, name: \"should_have_no_runnable_4\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 900..965, name: \"StructWithRunnable\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 967..1024, focus_range: 1003..1021, name: \"impl\", kind: Impl })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 1088..1154, focus_range: 1133..1151, name: \"impl\", kind: Impl })", ] "#]], ); @@ -1005,39 +754,10 @@ impl Data { fn foo() {} } "#, - &[Bin, DocTest], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..13, - focus_range: 4..8, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 44..98, - name: "foo", - }, - kind: DocTest { - test_id: Path( - "Data::foo", - ), - }, - cfg: None, - }, + "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 44..98, name: \"foo\" })", ] "#]], ); @@ -1059,39 +779,10 @@ impl Data<'a> { fn foo() {} } "#, - &[Bin, DocTest], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..13, - focus_range: 4..8, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 52..106, - name: "foo", - }, - kind: DocTest { - test_id: Path( - "Data<'a>::foo", - ), - }, - cfg: None, - }, + "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 52..106, name: \"foo\" })", ] "#]], ); @@ -1113,39 +804,10 @@ impl Data<'a, T, U> { fn foo() {} } "#, - &[Bin, DocTest], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..13, - focus_range: 4..8, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 70..124, - name: "foo", - }, - kind: DocTest { - test_id: Path( - "Data<'a,T,U>::foo", - ), - }, - cfg: None, - }, + "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 70..124, name: \"foo\" })", ] "#]], ); @@ -1167,39 +829,10 @@ impl Data { fn foo() {} } "#, - &[Bin, DocTest], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..13, - focus_range: 4..8, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 79..133, - name: "foo", - }, - kind: DocTest { - test_id: Path( - "Data::foo", - ), - }, - cfg: None, - }, + "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 79..133, name: \"foo\" })", ] "#]], ); @@ -1221,39 +854,10 @@ impl<'a, T, const N: usize> Data<'a, T, N> { fn foo() {} } "#, - &[Bin, DocTest], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..13, - focus_range: 4..8, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 100..154, - name: "foo", - }, - kind: DocTest { - test_id: Path( - "Data<'a,T,N>::foo", - ), - }, - cfg: None, - }, + "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 100..154, name: \"foo\" })", ] "#]], ); @@ -1269,47 +873,10 @@ mod test_mod { fn test_foo1() {} } "#, - &[TestMod, Test], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..51, - focus_range: 5..13, - name: "test_mod", - kind: Module, - description: "mod test_mod", - }, - kind: TestMod { - path: "test_mod", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 20..49, - focus_range: 35..44, - name: "test_foo1", - kind: Function, - }, - kind: Test { - test_id: Path( - "test_mod::test_foo1", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 1..51, focus_range: 5..13, name: \"test_mod\", kind: Module, description: \"mod test_mod\" })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 20..49, focus_range: 35..44, name: \"test_foo1\", kind: Function })", ] "#]], ); @@ -1342,123 +909,14 @@ mod root_tests { mod nested_tests_4 {} } "#, - &[TestMod, TestMod, Test, Test, TestMod, Test], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 22..323, - focus_range: 26..40, - name: "nested_tests_0", - kind: Module, - description: "mod nested_tests_0", - }, - kind: TestMod { - path: "root_tests::nested_tests_0", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 51..192, - focus_range: 55..69, - name: "nested_tests_1", - kind: Module, - description: "mod nested_tests_1", - }, - kind: TestMod { - path: "root_tests::nested_tests_0::nested_tests_1", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 84..126, - focus_range: 107..121, - name: "nested_test_11", - kind: Function, - }, - kind: Test { - test_id: Path( - "root_tests::nested_tests_0::nested_tests_1::nested_test_11", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 140..182, - focus_range: 163..177, - name: "nested_test_12", - kind: Function, - }, - kind: Test { - test_id: Path( - "root_tests::nested_tests_0::nested_tests_1::nested_test_12", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 202..286, - focus_range: 206..220, - name: "nested_tests_2", - kind: Module, - description: "mod nested_tests_2", - }, - kind: TestMod { - path: "root_tests::nested_tests_0::nested_tests_2", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 235..276, - focus_range: 258..271, - name: "nested_test_2", - kind: Function, - }, - kind: Test { - test_id: Path( - "root_tests::nested_tests_0::nested_tests_2::nested_test_2", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 22..323, focus_range: 26..40, name: \"nested_tests_0\", kind: Module, description: \"mod nested_tests_0\" })", + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 51..192, focus_range: 55..69, name: \"nested_tests_1\", kind: Module, description: \"mod nested_tests_1\" })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 84..126, focus_range: 107..121, name: \"nested_test_11\", kind: Function })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 140..182, focus_range: 163..177, name: \"nested_test_12\", kind: Function })", + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 202..286, focus_range: 206..220, name: \"nested_tests_2\", kind: Module, description: \"mod nested_tests_2\" })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 235..276, focus_range: 258..271, name: \"nested_test_2\", kind: Function })", ] "#]], ); @@ -1474,52 +932,10 @@ $0 #[cfg(feature = "foo")] fn test_foo1() {} "#, - &[TestMod, Test], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..51, - name: "", - kind: Module, - }, - kind: TestMod { - path: "", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..50, - focus_range: 36..45, - name: "test_foo1", - kind: Function, - }, - kind: Test { - test_id: Path( - "test_foo1", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: Some( - Atom( - KeyValue { - key: "feature", - value: "foo", - }, - ), - ), - }, + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..51, name: \"\", kind: Module })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 1..50, focus_range: 36..45, name: \"test_foo1\", kind: Function }, Atom(KeyValue { key: \"feature\", value: \"foo\" }))", ] "#]], ); @@ -1535,62 +951,10 @@ $0 #[cfg(all(feature = "foo", feature = "bar"))] fn test_foo1() {} "#, - &[TestMod, Test], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..73, - name: "", - kind: Module, - }, - kind: TestMod { - path: "", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..72, - focus_range: 58..67, - name: "test_foo1", - kind: Function, - }, - kind: Test { - test_id: Path( - "test_foo1", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: Some( - All( - [ - Atom( - KeyValue { - key: "feature", - value: "foo", - }, - ), - Atom( - KeyValue { - key: "feature", - value: "bar", - }, - ), - ], - ), - ), - }, + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..73, name: \"\", kind: Module })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 1..72, focus_range: 58..67, name: \"test_foo1\", kind: Function }, All([Atom(KeyValue { key: \"feature\", value: \"foo\" }), Atom(KeyValue { key: \"feature\", value: \"bar\" })]))", ] "#]], ); @@ -1606,7 +970,6 @@ mod test_mod { fn foo1() {} } "#, - &[], expect![[r#" [] "#]], @@ -1628,25 +991,9 @@ impl Foo { fn foo() {} } "#, - &[DocTest], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 1, - ), - full_range: 27..81, - name: "foo", - }, - kind: DocTest { - test_id: Path( - "foo::Foo::foo", - ), - }, - cfg: None, - }, + "(DocTest, NavigationTarget { file_id: FileId(1), full_range: 27..81, name: \"foo\" })", ] "#]], ); @@ -1683,110 +1030,14 @@ mod tests { gen2!(); gen_main!(); "#, - &[TestMod, TestMod, Test, Test, TestMod, Bin], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..315, - name: "", - kind: Module, - }, - kind: TestMod { - path: "", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 267..292, - focus_range: 271..276, - name: "tests", - kind: Module, - description: "mod tests", - }, - kind: TestMod { - path: "tests", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 283..290, - name: "foo_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests::foo_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 293..301, - name: "foo_test2", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests2::foo_test2", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 293..301, - name: "tests2", - kind: Module, - description: "mod tests2", - }, - kind: TestMod { - path: "tests2", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 302..314, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..315, name: \"\", kind: Module })", + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 267..292, focus_range: 271..276, name: \"tests\", kind: Module, description: \"mod tests\" })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 283..290, name: \"foo_test\", kind: Function })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 293..301, name: \"foo_test2\", kind: Function }, true)", + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 293..301, name: \"tests2\", kind: Module, description: \"mod tests2\" }, true)", + "(Bin, NavigationTarget { file_id: FileId(0), full_range: 302..314, name: \"main\", kind: Function })", ] "#]], ); @@ -1812,85 +1063,12 @@ macro_rules! foo { } foo!(); "#, - &[Test, Test, Test, TestMod], expect![[r#" [ - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 210..217, - name: "foo0", - kind: Function, - }, - kind: Test { - test_id: Path( - "foo_tests::foo0", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 210..217, - name: "foo1", - kind: Function, - }, - kind: Test { - test_id: Path( - "foo_tests::foo1", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 210..217, - name: "foo2", - kind: Function, - }, - kind: Test { - test_id: Path( - "foo_tests::foo2", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 210..217, - name: "foo_tests", - kind: Module, - description: "mod foo_tests", - }, - kind: TestMod { - path: "foo_tests", - }, - cfg: None, - }, + "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo0\", kind: Function }, true)", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo1\", kind: Function }, true)", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo2\", kind: Function }, true)", + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo_tests\", kind: Module, description: \"mod foo_tests\" }, true)", ] "#]], ); @@ -1909,7 +1087,6 @@ mod tests { fn t() {} } "#, - &[], expect![[r#" [] "#]], @@ -1929,26 +1106,9 @@ fn t0() {} #[test] fn t1() {} "#, - &[TestMod], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..7, - focus_range: 5..6, - name: "m", - kind: Module, - description: "mod m", - }, - kind: TestMod { - path: "m", - }, - cfg: None, - }, + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 1..7, focus_range: 5..6, name: \"m\", kind: Module, description: \"mod m\" })", ] "#]], ); @@ -1967,66 +1127,11 @@ fn t0() {} #[test] fn t1() {} "#, - &[TestMod, Test, Test], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 1, - ), - full_range: 0..39, - name: "m", - kind: Module, - }, - kind: TestMod { - path: "m", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 1, - ), - full_range: 1..19, - focus_range: 12..14, - name: "t0", - kind: Function, - }, - kind: Test { - test_id: Path( - "m::t0", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 1, - ), - full_range: 20..38, - focus_range: 31..33, - name: "t1", - kind: Function, - }, - kind: Test { - test_id: Path( - "m::t1", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, + "(TestMod, NavigationTarget { file_id: FileId(1), full_range: 0..39, name: \"m\", kind: Module })", + "(Test, NavigationTarget { file_id: FileId(1), full_range: 1..19, focus_range: 12..14, name: \"t0\", kind: Function })", + "(Test, NavigationTarget { file_id: FileId(1), full_range: 20..38, focus_range: 31..33, name: \"t1\", kind: Function })", ] "#]], ); @@ -2047,68 +1152,11 @@ mod module { fn t1() {} } "#, - &[TestMod, Test, Test], expect![[r#" [ - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 26..94, - focus_range: 30..36, - name: "module", - kind: Module, - description: "mod module", - }, - kind: TestMod { - path: "module", - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 43..65, - focus_range: 58..60, - name: "t0", - kind: Function, - }, - kind: Test { - test_id: Path( - "module::t0", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: true, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 70..92, - focus_range: 85..87, - name: "t1", - kind: Function, - }, - kind: Test { - test_id: Path( - "module::t1", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 26..94, focus_range: 30..36, name: \"module\", kind: Module, description: \"mod module\" }, true)", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 43..65, focus_range: 58..60, name: \"t0\", kind: Function }, true)", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 70..92, focus_range: 85..87, name: \"t1\", kind: Function }, true)", ] "#]], ); @@ -2143,26 +1191,14 @@ mod tests { "#, expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 31..85, - focus_range: 46..54, - name: "foo_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests::foo_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, + NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 31..85, + focus_range: 46..54, + name: "foo_test", + kind: Function, }, ] "#]], @@ -2188,26 +1224,14 @@ mod tests { "#, expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 71..122, - focus_range: 86..94, - name: "foo_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests::foo_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, + NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 71..122, + focus_range: 86..94, + name: "foo_test", + kind: Function, }, ] "#]], @@ -2240,26 +1264,14 @@ mod tests { "#, expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 133..183, - focus_range: 148..156, - name: "foo_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests::foo_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, + NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 133..183, + focus_range: 148..156, + name: "foo_test", + kind: Function, }, ] "#]], @@ -2292,47 +1304,23 @@ mod tests { "#, expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 121..185, - focus_range: 136..145, - name: "foo2_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests::foo2_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, + NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 121..185, + focus_range: 136..145, + name: "foo2_test", + kind: Function, }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 52..115, - focus_range: 67..75, - name: "foo_test", - kind: Function, - }, - kind: Test { - test_id: Path( - "tests::foo_test", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, + NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 52..115, + focus_range: 67..75, + name: "foo_test", + kind: Function, }, ] "#]], @@ -2354,39 +1342,10 @@ impl Data<'a, A, 12, C, D> { fn foo() {} } "#, - &[Bin, DocTest], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..13, - focus_range: 4..8, - name: "main", - kind: Function, - }, - kind: Bin, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 121..156, - name: "foo", - }, - kind: DocTest { - test_id: Path( - "Data<'a,A,12,C,D>::foo", - ), - }, - cfg: None, - }, + "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 121..156, name: \"foo\" })", ] "#]], ); @@ -2416,77 +1375,12 @@ impl Foo, ()> { fn t() {} } "#, - &[DocTest, DocTest, DocTest, DocTest], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 20..103, - focus_range: 47..56, - name: "impl", - kind: Impl, - }, - kind: DocTest { - test_id: Path( - "Foo", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 63..101, - name: "t", - }, - kind: DocTest { - test_id: Path( - "Foo::t", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 105..188, - focus_range: 126..146, - name: "impl", - kind: Impl, - }, - kind: DocTest { - test_id: Path( - "Foo,()>", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 153..186, - name: "t", - }, - kind: DocTest { - test_id: Path( - "Foo,()>::t", - ), - }, - cfg: None, - }, + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 20..103, focus_range: 47..56, name: \"impl\", kind: Impl })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 63..101, name: \"t\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 105..188, focus_range: 126..146, name: \"impl\", kind: Impl })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 153..186, name: \"t\" })", ] "#]], ); @@ -2512,7 +1406,6 @@ macro_rules! foo { }; } "#, - &[], expect![[r#" [] "#]], @@ -2532,25 +1425,9 @@ macro_rules! foo { }; } "#, - &[DocTest], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..94, - name: "foo", - }, - kind: DocTest { - test_id: Path( - "foo", - ), - }, - cfg: None, - }, + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 1..94, name: \"foo\" })", ] "#]], ); @@ -2596,149 +1473,16 @@ mod r#mod { impl r#trait for r#struct {} } "#, - &[TestMod, Test, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest], expect![[r#" [ - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 1..461, - focus_range: 5..10, - name: "r#mod", - kind: Module, - description: "mod r#mod", - }, - kind: TestMod { - path: "r#mod", - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 17..41, - focus_range: 32..36, - name: "r#fn", - kind: Function, - }, - kind: Test { - test_id: Path( - "r#mod::r#fn", - ), - attr: TestAttr { - ignore: false, - }, - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 47..84, - name: "r#for", - container_name: "r#mod", - }, - kind: DocTest { - test_id: Path( - "r#mod::r#for", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 90..146, - name: "r#struct", - container_name: "r#mod", - }, - kind: DocTest { - test_id: Path( - "r#mod::r#struct", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 152..266, - focus_range: 189..205, - name: "impl", - kind: Impl, - }, - kind: DocTest { - test_id: Path( - "r#struct", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 216..260, - name: "r#fn", - }, - kind: DocTest { - test_id: Path( - "r#mod::r#struct::r#fn", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 323..367, - name: "r#fn", - }, - kind: DocTest { - test_id: Path( - "r#mod::r#struct::r#fn", - ), - }, - cfg: None, - }, - Runnable { - use_name_in_title: false, - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 401..459, - focus_range: 445..456, - name: "impl", - kind: Impl, - }, - kind: DocTest { - test_id: Path( - "r#struct", - ), - }, - cfg: None, - }, + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 1..461, focus_range: 5..10, name: \"r#mod\", kind: Module, description: \"mod r#mod\" })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 17..41, focus_range: 32..36, name: \"r#fn\", kind: Function })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 47..84, name: \"r#for\", container_name: \"r#mod\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 90..146, name: \"r#struct\", container_name: \"r#mod\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 152..266, focus_range: 189..205, name: \"impl\", kind: Impl })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 216..260, name: \"r#fn\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 323..367, name: \"r#fn\" })", + "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 401..459, focus_range: 445..456, name: \"impl\", kind: Impl })", ] "#]], ) diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index 3724dc282211..5b7094e6bcc0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -17,7 +17,7 @@ use crate::navigation_target::UpmappingResult; use crate::{ hover::hover_for_definition, inlay_hints::AdjustmentHintsMode, - moniker::{def_to_moniker, MonikerResult}, + moniker::{def_to_kind, def_to_moniker, MonikerResult, SymbolInformationKind}, parent_module::crates_for, Analysis, Fold, HoverConfig, HoverResult, InlayHint, InlayHintsConfig, TryToNav, }; @@ -46,6 +46,10 @@ pub struct TokenStaticData { pub definition: Option, pub references: Vec, pub moniker: Option, + pub display_name: Option, + pub enclosing_moniker: Option, + pub signature: Option, + pub kind: SymbolInformationKind, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -129,6 +133,7 @@ impl StaticIndex<'_> { closure_capture_hints: false, closing_brace_hints_min_lines: Some(25), fields_to_resolve: InlayFieldsToResolve::empty(), + range_exclusive_hints: false, }, file_id, None, @@ -172,6 +177,12 @@ impl StaticIndex<'_> { }), references: vec![], moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)), + display_name: def.name(self.db).map(|name| name.display(self.db).to_string()), + enclosing_moniker: current_crate + .zip(def.enclosing_definition(self.db)) + .and_then(|(cc, enclosing_def)| def_to_moniker(self.db, enclosing_def, cc)), + signature: def.label(self.db), + kind: def_to_kind(self.db, def), }); self.def_map.insert(def, it); it diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index 0558f658fd19..d686652bb3ec 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -1,5 +1,6 @@ //! Computes color for a single element. +use either::Either; use hir::{AsAssocItem, HasVisibility, MacroFileIdExt, Semantics}; use ide_db::{ defs::{Definition, IdentClass, NameClass, NameRefClass}, @@ -359,7 +360,9 @@ pub(super) fn highlight_def( let db = sema.db; let mut h = match def { Definition::Macro(m) => Highlight::new(HlTag::Symbol(m.kind(sema.db).into())), - Definition::Field(_) => Highlight::new(HlTag::Symbol(SymbolKind::Field)), + Definition::Field(_) | Definition::TupleField(_) => { + Highlight::new(HlTag::Symbol(SymbolKind::Field)) + } Definition::Module(module) => { let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Module)); if module.is_crate_root() { @@ -647,8 +650,11 @@ fn highlight_name_ref_by_syntax( let h = HlTag::Symbol(SymbolKind::Field); let is_union = ast::FieldExpr::cast(parent) .and_then(|field_expr| sema.resolve_field(&field_expr)) - .map_or(false, |field| { - matches!(field.parent_def(sema.db), hir::VariantDef::Union(_)) + .map_or(false, |field| match field { + Either::Left(field) => { + matches!(field.parent_def(sema.db), hir::VariantDef::Union(_)) + } + Either::Right(_) => false, }); if is_union { h | HlMod::Unsafe diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs index 71f4d07245d2..6bf13ffd06fc 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs @@ -301,7 +301,7 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag { Definition::TypeAlias(_) => SymbolKind::TypeAlias, Definition::BuiltinType(_) => return HlTag::BuiltinType, Definition::Macro(_) => SymbolKind::Macro, - Definition::Field(_) => SymbolKind::Field, + Definition::Field(_) | Definition::TupleField(_) => SymbolKind::Field, Definition::SelfType(_) => SymbolKind::Impl, Definition::Local(_) => SymbolKind::Local, Definition::GenericParam(gp) => match gp { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html index e8b3a38c9e0f..4063cf9f7570 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html @@ -96,7 +96,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd include!(concat!("foo/", "foo.rs")); fn main() { - format_args!("Hello, {}!", 92); + format_args!("Hello, {}!", (92,).0); dont_color_me_braces!(); noop!(noop!(1)); } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs index afb6c555b4af..864c6d1cad79 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs @@ -103,7 +103,7 @@ macro without_args { include!(concat!("foo/", "foo.rs")); fn main() { - format_args!("Hello, {}!", 92); + format_args!("Hello, {}!", (92,).0); dont_color_me_braces!(); noop!(noop!(1)); } diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs index 3802978f4941..53f998e5457d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs @@ -69,7 +69,7 @@ impl FieldOrTupleIdx { .as_str() .map(|s| s.to_owned()) .unwrap_or_else(|| format!(".{}", f.name(db).as_tuple_index().unwrap())), - FieldOrTupleIdx::TupleIdx(i) => format!(".{i}").to_owned(), + FieldOrTupleIdx::TupleIdx(i) => format!(".{i}"), } } } @@ -203,7 +203,7 @@ pub(crate) fn view_memory_layout( let mut nodes = vec![MemoryLayoutNode { item_name, - typename: typename.clone(), + typename, size: layout.size(), offset: 0, alignment: layout.align(), diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml index 55be6bc23bbb..90545bb5130c 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml @@ -13,7 +13,7 @@ doctest = false cargo_metadata = "0.18.1" # local deps -toolchain = { path = "../../toolchain", version = "0.0.0" } +toolchain.workspace = true [features] sysroot-abi = [] diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index d89c4598afc7..bc1fcd08e20c 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -274,7 +274,7 @@ impl CargoWorkspace { other_options.append( &mut targets .into_iter() - .flat_map(|target| ["--filter-platform".to_owned().to_string(), target]) + .flat_map(|target| ["--filter-platform".to_owned(), target]) .collect(), ); } diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs index fe046dd14630..d52e448d7470 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs @@ -6,7 +6,7 @@ use std::{env, fs, iter, ops, path::PathBuf, process::Command}; -use anyhow::{format_err, Result}; +use anyhow::{format_err, Context, Result}; use base_db::CrateName; use la_arena::{Arena, Idx}; use paths::{AbsPath, AbsPathBuf}; @@ -119,12 +119,15 @@ impl Sysroot { get_rustc_src(&self.root) } - pub fn discover_rustc(&self) -> Result { + pub fn discover_rustc(&self) -> anyhow::Result { let rustc = self.root.join("bin/rustc"); tracing::debug!(?rustc, "checking for rustc binary at location"); match fs::metadata(&rustc) { Ok(_) => Ok(rustc), - Err(e) => Err(e), + Err(e) => Err(e).context(format!( + "failed to discover rustc in sysroot: {:?}", + AsRef::::as_ref(&self.root) + )), } } diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index 4057493fa3a6..00cc7c30ee3e 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -1277,7 +1277,7 @@ fn add_target_crate_root( inject_cargo_env(pkg, &mut env); if let Ok(cname) = String::from_str(cargo_name) { // CARGO_CRATE_NAME is the name of the Cargo target with - converted to _, such as the name of the library, binary, example, integration test, or benchmark. - env.set("CARGO_CRATE_NAME", cname.replace("-", "_")); + env.set("CARGO_CRATE_NAME", cname.replace('-', "_")); } if let Some(envs) = build_data.map(|it| &it.envs) { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 1908c73b3b46..e69302dbaccf 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -792,6 +792,7 @@ impl flags::AnalysisStats { max_length: Some(25), closing_brace_hints_min_lines: Some(20), fields_to_resolve: InlayFieldsToResolve::empty(), + range_exclusive_hints: true, }, file_id, None, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs index 95c8798d43c8..c86b2c0ba405 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs @@ -7,8 +7,8 @@ use std::{ }; use ide::{ - LineCol, MonikerDescriptorKind, StaticIndex, StaticIndexedFile, TextRange, TokenId, - TokenStaticData, + LineCol, MonikerDescriptorKind, MonikerResult, StaticIndex, StaticIndexedFile, + SymbolInformationKind, TextRange, TokenId, }; use ide_db::LineIndexDatabase; use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice}; @@ -78,6 +78,7 @@ impl flags::Scip { let mut symbols_emitted: HashSet = HashSet::default(); let mut tokens_to_symbol: HashMap = HashMap::new(); + let mut tokens_to_enclosing_symbol: HashMap> = HashMap::new(); for StaticIndexedFile { file_id, tokens, .. } in si.files { let mut local_count = 0; @@ -109,10 +110,24 @@ impl flags::Scip { let symbol = tokens_to_symbol .entry(id) .or_insert_with(|| { - let symbol = token_to_symbol(token).unwrap_or_else(&mut new_local_symbol); + let symbol = token + .moniker + .as_ref() + .map(moniker_to_symbol) + .unwrap_or_else(&mut new_local_symbol); scip::symbol::format_symbol(symbol) }) .clone(); + let enclosing_symbol = tokens_to_enclosing_symbol + .entry(id) + .or_insert_with(|| { + token + .enclosing_moniker + .as_ref() + .map(moniker_to_symbol) + .map(scip::symbol::format_symbol) + }) + .clone(); let mut symbol_roles = Default::default(); @@ -128,15 +143,22 @@ impl flags::Scip { .map(|hover| hover.markup.as_str()) .filter(|it| !it.is_empty()) .map(|it| vec![it.to_owned()]); + let signature_documentation = + token.signature.clone().map(|text| scip_types::Document { + relative_path: relative_path.clone(), + language: "rust".to_string(), + text, + ..Default::default() + }); let symbol_info = scip_types::SymbolInformation { symbol: symbol.clone(), documentation: documentation.unwrap_or_default(), relationships: Vec::new(), special_fields: Default::default(), - kind: Default::default(), - display_name: String::new(), - signature_documentation: Default::default(), - enclosing_symbol: String::new(), + kind: symbol_kind(token.kind).into(), + display_name: token.display_name.clone().unwrap_or_default(), + signature_documentation: signature_documentation.into(), + enclosing_symbol: enclosing_symbol.unwrap_or_default(), }; symbols.push(symbol_info) @@ -228,14 +250,36 @@ fn new_descriptor(name: &str, suffix: scip_types::descriptor::Suffix) -> scip_ty } } -/// Loosely based on `def_to_moniker` -/// -/// Only returns a Symbol when it's a non-local symbol. -/// So if the visibility isn't outside of a document, then it will return None -fn token_to_symbol(token: &TokenStaticData) -> Option { - use scip_types::descriptor::Suffix::*; +fn symbol_kind(kind: SymbolInformationKind) -> scip_types::symbol_information::Kind { + use scip_types::symbol_information::Kind as ScipKind; + match kind { + SymbolInformationKind::AssociatedType => ScipKind::AssociatedType, + SymbolInformationKind::Attribute => ScipKind::Attribute, + SymbolInformationKind::Constant => ScipKind::Constant, + SymbolInformationKind::Enum => ScipKind::Enum, + SymbolInformationKind::EnumMember => ScipKind::EnumMember, + SymbolInformationKind::Field => ScipKind::Field, + SymbolInformationKind::Function => ScipKind::Function, + SymbolInformationKind::Macro => ScipKind::Macro, + SymbolInformationKind::Method => ScipKind::Method, + SymbolInformationKind::Module => ScipKind::Module, + SymbolInformationKind::Parameter => ScipKind::Parameter, + SymbolInformationKind::SelfParameter => ScipKind::SelfParameter, + SymbolInformationKind::StaticMethod => ScipKind::StaticMethod, + SymbolInformationKind::StaticVariable => ScipKind::StaticVariable, + SymbolInformationKind::Struct => ScipKind::Struct, + SymbolInformationKind::Trait => ScipKind::Trait, + SymbolInformationKind::TraitMethod => ScipKind::TraitMethod, + SymbolInformationKind::Type => ScipKind::Type, + SymbolInformationKind::TypeAlias => ScipKind::TypeAlias, + SymbolInformationKind::TypeParameter => ScipKind::TypeParameter, + SymbolInformationKind::Union => ScipKind::Union, + SymbolInformationKind::Variable => ScipKind::Variable, + } +} - let moniker = token.moniker.as_ref()?; +fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol { + use scip_types::descriptor::Suffix::*; let package_name = moniker.package_information.name.clone(); let version = moniker.package_information.version.clone(); @@ -260,7 +304,7 @@ fn token_to_symbol(token: &TokenStaticData) -> Option { }) .collect(); - Some(scip_types::Symbol { + scip_types::Symbol { scheme: "rust-analyzer".into(), package: Some(scip_types::Package { manager: "cargo".to_string(), @@ -271,7 +315,7 @@ fn token_to_symbol(token: &TokenStaticData) -> Option { .into(), descriptors, special_fields: Default::default(), - }) + } } #[cfg(test)] @@ -309,7 +353,7 @@ mod test { for &(range, id) in &file.tokens { if range.contains(offset - TextSize::from(1)) { let token = si.tokens.get(id).unwrap(); - found_symbol = token_to_symbol(token); + found_symbol = token.moniker.as_ref().map(moniker_to_symbol); break; } } @@ -359,6 +403,21 @@ pub mod module { ); } + #[test] + fn symbol_for_trait_alias() { + check_symbol( + r#" +//- /foo/lib.rs crate:foo@0.1.0,https://a.b/foo.git library +#![feature(trait_alias)] +pub mod module { + pub trait MyTrait {} + pub trait MyTraitAlias$0 = MyTrait; +} +"#, + "rust-analyzer cargo foo 0.1.0 module/MyTraitAlias#", + ); + } + #[test] fn symbol_for_trait_constant() { check_symbol( @@ -525,4 +584,15 @@ pub mod example_mod { "rust-analyzer cargo main . foo/Bar#", ); } + + #[test] + fn symbol_for_for_type_alias() { + check_symbol( + r#" + //- /lib.rs crate:main + pub type MyTypeAlias$0 = u8; + "#, + "rust-analyzer cargo main . MyTypeAlias#", + ); + } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 88fb3708449f..fe009f82a71f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -399,6 +399,8 @@ config_data! { /// Whether to show function parameter name inlay hints at the call /// site. inlayHints_parameterHints_enable: bool = "true", + /// Whether to show exclusive range inlay hints. + inlayHints_rangeExclusiveHints_enable: bool = "false", /// Whether to show inlay hints for compiler inserted reborrows. /// This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#. inlayHints_reborrowHints_enable: ReborrowHintsDef = "\"never\"", @@ -1464,6 +1466,7 @@ impl Config { } else { None }, + range_exclusive_hints: self.data.inlayHints_rangeExclusiveHints_enable, fields_to_resolve: InlayFieldsToResolve { resolve_text_edits: client_capability_fields.contains("textEdits"), resolve_hint_tooltip: client_capability_fields.contains("tooltip"), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index f1317ce2b401..13544558c50c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -458,7 +458,6 @@ pub(crate) fn handle_workspace_symbol( let config = snap.config.workspace_symbol(); let (all_symbols, libs) = decide_search_scope_and_kind(¶ms, &config); - let limit = config.search_limit; let query = { let query: String = params.query.chars().filter(|&c| c != '#' && c != '*').collect(); @@ -469,14 +468,11 @@ pub(crate) fn handle_workspace_symbol( if libs { q.libs(); } - q.limit(limit); q }; - let mut res = exec_query(&snap, query)?; + let mut res = exec_query(&snap, query, config.search_limit)?; if res.is_empty() && !all_symbols { - let mut query = Query::new(params.query); - query.limit(limit); - res = exec_query(&snap, query)?; + res = exec_query(&snap, Query::new(params.query), config.search_limit)?; } return Ok(Some(lsp_types::WorkspaceSymbolResponse::Nested(res))); @@ -519,9 +515,10 @@ pub(crate) fn handle_workspace_symbol( fn exec_query( snap: &GlobalStateSnapshot, query: Query, + limit: usize, ) -> anyhow::Result> { let mut res = Vec::new(); - for nav in snap.analysis.symbol_search(query)? { + for nav in snap.analysis.symbol_search(query, limit)? { let container_name = nav.container_name.as_ref().map(|v| v.to_string()); let info = lsp_types::WorkspaceSymbol { diff --git a/src/tools/rust-analyzer/crates/span/Cargo.toml b/src/tools/rust-analyzer/crates/span/Cargo.toml index 69b88b5a17b5..a4abba29bb97 100644 --- a/src/tools/rust-analyzer/crates/span/Cargo.toml +++ b/src/tools/rust-analyzer/crates/span/Cargo.toml @@ -1,6 +1,8 @@ [package] name = "span" version = "0.0.0" +description = "TBD" + rust-version.workspace = true edition.workspace = true license.workspace = true @@ -18,4 +20,4 @@ syntax.workspace = true stdx.workspace = true [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs index 71e269f74bc7..43909fff02cb 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs @@ -59,6 +59,17 @@ impl TupleExt for (T, U) { } } +impl TupleExt for (T, U, V) { + type Head = T; + type Tail = V; + fn head(self) -> Self::Head { + self.0 + } + fn tail(self) -> Self::Tail { + self.2 + } +} + pub fn to_lower_snake_case(s: &str) -> String { to_snake_case(s, char::to_lowercase) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast.rs b/src/tools/rust-analyzer/crates/syntax/src/ast.rs index 1e691befff62..cc90d2dd1d55 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast.rs @@ -136,6 +136,16 @@ where { } +/// Trait to describe operations common to both `RangeExpr` and `RangePat`. +pub trait RangeItem { + type Bound; + + fn start(&self) -> Option; + fn end(&self) -> Option; + fn op_kind(&self) -> Option; + fn op_token(&self) -> Option; +} + mod support { use super::{AstChildren, AstNode, SyntaxKind, SyntaxNode, SyntaxToken}; diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 4c2878f49f0e..aa56f10d6095 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -293,13 +293,12 @@ impl ast::GenericParamList { } /// Removes the corresponding generic arg - pub fn remove_generic_arg(&self, generic_arg: &ast::GenericArg) -> Option { + pub fn remove_generic_arg(&self, generic_arg: &ast::GenericArg) { let param_to_remove = self.find_generic_arg(generic_arg); if let Some(param) = ¶m_to_remove { self.remove_generic_param(param.clone()); } - param_to_remove } /// Constructs a matching [`ast::GenericArgList`] diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs index 36980b146ef5..18a56e2823ab 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs @@ -13,6 +13,8 @@ use crate::{ SyntaxNode, SyntaxToken, T, }; +use super::RangeItem; + impl ast::HasAttrs for ast::Expr {} impl ast::Expr { @@ -227,16 +229,12 @@ impl ast::RangeExpr { Some((ix, token, bin_op)) }) } +} - pub fn op_kind(&self) -> Option { - self.op_details().map(|t| t.2) - } +impl RangeItem for ast::RangeExpr { + type Bound = ast::Expr; - pub fn op_token(&self) -> Option { - self.op_details().map(|t| t.1) - } - - pub fn start(&self) -> Option { + fn start(&self) -> Option { let op_ix = self.op_details()?.0; self.syntax() .children_with_tokens() @@ -244,13 +242,21 @@ impl ast::RangeExpr { .find_map(|it| ast::Expr::cast(it.into_node()?)) } - pub fn end(&self) -> Option { + fn end(&self) -> Option { let op_ix = self.op_details()?.0; self.syntax() .children_with_tokens() .skip(op_ix + 1) .find_map(|it| ast::Expr::cast(it.into_node()?)) } + + fn op_token(&self) -> Option { + self.op_details().map(|t| t.1) + } + + fn op_kind(&self) -> Option { + self.op_details().map(|t| t.2) + } } impl ast::IndexExpr { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 2abbfc81f675..b1dd1fe8c829 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -263,9 +263,6 @@ pub fn impl_( ast_from_text(&format!("impl{gen_params} {path_type}{tr_gen_args}{where_clause}{{{}}}", body)) } -// FIXME : We must make *_gen_args' type ast::GenericArgList but in order to do so we must implement in `edit_in_place.rs` -// `add_generic_arg()` just like `add_generic_param()` -// is implemented for `ast::GenericParamList` pub fn impl_trait( is_unsafe: bool, trait_gen_params: Option, diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs index a7e4899fb7ee..8618018c0b6a 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs @@ -14,6 +14,8 @@ use crate::{ ted, NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T, }; +use super::{RangeItem, RangeOp}; + impl ast::Lifetime { pub fn text(&self) -> TokenText<'_> { text_of_first_token(self.syntax()) @@ -875,8 +877,10 @@ impl ast::Module { } } -impl ast::RangePat { - pub fn start(&self) -> Option { +impl RangeItem for ast::RangePat { + type Bound = ast::Pat; + + fn start(&self) -> Option { self.syntax() .children_with_tokens() .take_while(|it| !(it.kind() == T![..] || it.kind() == T![..=])) @@ -884,13 +888,37 @@ impl ast::RangePat { .find_map(ast::Pat::cast) } - pub fn end(&self) -> Option { + fn end(&self) -> Option { self.syntax() .children_with_tokens() .skip_while(|it| !(it.kind() == T![..] || it.kind() == T![..=])) .filter_map(|it| it.into_node()) .find_map(ast::Pat::cast) } + + fn op_token(&self) -> Option { + self.syntax().children_with_tokens().find_map(|it| { + let token = it.into_token()?; + + match token.kind() { + T![..] => Some(token), + T![..=] => Some(token), + _ => None, + } + }) + } + + fn op_kind(&self) -> Option { + self.syntax().children_with_tokens().find_map(|it| { + let token = it.into_token()?; + + match token.kind() { + T![..] => Some(RangeOp::Exclusive), + T![..=] => Some(RangeOp::Inclusive), + _ => None, + } + }) + } } impl ast::TokenTree { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs index 8e04ab8bedcb..9ddf5a0a9804 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs @@ -1,7 +1,7 @@ //! Precedence representation. use crate::{ - ast::{self, BinaryOp, Expr, HasArgList}, + ast::{self, BinaryOp, Expr, HasArgList, RangeItem}, match_ast, AstNode, SyntaxNode, }; diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation.rs b/src/tools/rust-analyzer/crates/syntax/src/validation.rs index 2b1bbac08e52..eabbda2c3983 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/validation.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/validation.rs @@ -9,7 +9,7 @@ use rustc_dependencies::lexer::unescape::{self, unescape_literal, Mode}; use crate::{ algo, - ast::{self, HasAttrs, HasVisibility, IsString}, + ast::{self, HasAttrs, HasVisibility, IsString, RangeItem}, match_ast, AstNode, SyntaxError, SyntaxKind::{CONST, FN, INT_NUMBER, TYPE_ALIAS}, SyntaxNode, SyntaxToken, TextSize, T, diff --git a/src/tools/rust-analyzer/docs/dev/guide.md b/src/tools/rust-analyzer/docs/dev/guide.md index a5f1811bf24a..bb77aa0eaaef 100644 --- a/src/tools/rust-analyzer/docs/dev/guide.md +++ b/src/tools/rust-analyzer/docs/dev/guide.md @@ -2,13 +2,15 @@ ## About the guide -This guide describes the current state of rust-analyzer as of 2019-01-20 (git -tag [guide-2019-01]). Its purpose is to document various problems and +This guide describes the current state of rust-analyzer as of the 2024-01-01 release +(git tag [2024-01-01]). Its purpose is to document various problems and architectural solutions related to the problem of building IDE-first compiler -for Rust. There is a video version of this guide as well: +for Rust. There is a video version of this guide as well - +however, it's based on an older 2019-01-20 release (git tag [guide-2019-01]): https://youtu.be/ANKBNiSWyfc. [guide-2019-01]: https://github.com/rust-lang/rust-analyzer/tree/guide-2019-01 +[2024-01-01]: https://github.com/rust-lang/rust-analyzer/tree/2024-01-01 ## The big picture @@ -40,8 +42,8 @@ terms of files and offsets, and **not** in terms of Rust concepts like structs, traits, etc. The "typed" API with Rust specific types is slightly lower in the stack, we'll talk about it later. -[`AnalysisHost`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L265-L284 -[`Analysis`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L291-L478 +[`AnalysisHost`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/ide/src/lib.rs#L161-L213 +[`Analysis`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/ide/src/lib.rs#L220-L761 The reason for this separation of `Analysis` and `AnalysisHost` is that we want to apply changes "uniquely", but we might also want to fork an `Analysis` and send it to @@ -65,18 +67,23 @@ Next, let's talk about what the inputs to the `Analysis` are, precisely. rust-analyzer never does any I/O itself, all inputs get passed explicitly via the `AnalysisHost::apply_change` method, which accepts a single argument, a -`Change`. [`Change`] is a builder for a single change -"transaction", so it suffices to study its methods to understand all of the -input data. +`Change`. [`Change`] is a wrapper for `FileChange` that adds proc-macro knowledge. +[`FileChange`] is a builder for a single change "transaction", so it suffices +to study its methods to understand all the input data. -[`Change`]: https://github.com/rust-lang/rust-analyzer/blob/master/crates/base_db/src/change.rs#L14-L89 +[`Change`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-expand/src/change.rs#L10-L42 +[`FileChange`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/base-db/src/change.rs#L14-L78 -The `(add|change|remove)_file` methods control the set of the input files, where -each file has an integer id (`FileId`, picked by the client), text (`String`) -and a filesystem path. Paths are tricky; they'll be explained below, in source roots -section, together with the `add_root` method. The `add_library` method allows us to add a -group of files which are assumed to rarely change. It's mostly an optimization -and does not change the fundamental picture. +The `change_file` method controls the set of the input files, where each file +has an integer id (`FileId`, picked by the client) and text (`Option>`). +Paths are tricky; they'll be explained below, in source roots section, +together with the `set_roots` method. The "source root" [`is_library`] flag +along with the concept of [`durability`] allows us to add a group of files which +are assumed to rarely change. It's mostly an optimization and does not change +the fundamental picture. + +[`is_library`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/base-db/src/input.rs#L38 +[`durability`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/base-db/src/change.rs#L80-L86 The `set_crate_graph` method allows us to control how the input files are partitioned into compilation units -- crates. It also controls (in theory, not implemented @@ -118,7 +125,7 @@ can have `#[path="/dev/random"] mod foo;`. To solve (or explicitly refuse to solve) these problems rust-analyzer uses the concept of a "source root". Roughly speaking, source roots are the contents of a -directory on a file systems, like `/home/matklad/projects/rustraytracer/**.rs`. +directory on a file system, like `/home/matklad/projects/rustraytracer/**.rs`. More precisely, all files (`FileId`s) are partitioned into disjoint `SourceRoot`s. Each file has a relative UTF-8 path within the `SourceRoot`. @@ -134,49 +141,53 @@ the source root, even `/dev/random`. ## Language Server Protocol -Now let's see how the `Analysis` API is exposed via the JSON RPC based language server protocol. The -hard part here is managing changes (which can come either from the file system +Now let's see how the `Analysis` API is exposed via the JSON RPC based language server protocol. +The hard part here is managing changes (which can come either from the file system or from the editor) and concurrency (we want to spawn background jobs for things like syntax highlighting). We use the event loop pattern to manage the zoo, and -the loop is the [`main_loop_inner`] function. The [`main_loop`] does a one-time -initialization and tearing down of the resources. +the loop is the [`GlobalState::run`] function initiated by [`main_loop`] after +[`GlobalState::new`] does a one-time initialization and tearing down of the resources. -[`main_loop`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L51-L110 -[`main_loop_inner`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L156-L258 +[`main_loop`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/main_loop.rs#L31-L54 +[`GlobalState::new`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/global_state.rs#L148-L215 +[`GlobalState::run`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/main_loop.rs#L114-L140 Let's walk through a typical analyzer session! First, we need to figure out what to analyze. To do this, we run `cargo metadata` to learn about Cargo packages for current workspace and dependencies, -and we run `rustc --print sysroot` and scan the "sysroot" (the directory containing the current Rust toolchain's files) to learn about crates like -`std`. Currently we load this configuration once at the start of the server, but -it should be possible to dynamically reconfigure it later without restart. +and we run `rustc --print sysroot` and scan the "sysroot" +(the directory containing the current Rust toolchain's files) to learn about crates +like `std`. This happens in the [`GlobalState::fetch_workspaces`] method. +We load this configuration at the start of the server in [`GlobalState::new`], +but it's also triggered by workspace change events and requests to reload the +workspace from the client. -[main_loop.rs#L62-L70](https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L62-L70) +[`GlobalState::fetch_workspaces`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/reload.rs#L186-L257 The [`ProjectModel`] we get after this step is very Cargo and sysroot specific, -it needs to be lowered to get the input in the form of `Change`. This -happens in [`ServerWorldState::new`] method. Specifically +it needs to be lowered to get the input in the form of `Change`. This happens +in [`GlobalState::process_changes`] method. Specifically -* Create a `SourceRoot` for each Cargo package and sysroot. +* Create `SourceRoot`s for each Cargo package(s) and sysroot. * Schedule a filesystem scan of the roots. * Create an analyzer's `Crate` for each Cargo **target** and sysroot crate. * Setup dependencies between the crates. -[`ProjectModel`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/project_model.rs#L16-L20 -[`ServerWorldState::new`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/server_world.rs#L38-L160 +[`ProjectModel`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/project-model/src/workspace.rs#L57-L100 +[`GlobalState::process_changes`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/global_state.rs#L217-L356 The results of the scan (which may take a while) will be processed in the body of the main loop, just like any other change. Here's where we handle: -* [File system changes](https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L194) -* [Changes from the editor](https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L377) +* [File system changes](https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/main_loop.rs#L273) +* [Changes from the editor](https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/main_loop.rs#L801-L803) After a single loop's turn, we group the changes into one `Change` and [apply] it. This always happens on the main thread and blocks the loop. -[apply]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/server_world.rs#L216 +[apply]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/global_state.rs#L333 To handle requests, like ["goto definition"], we create an instance of the `Analysis` and [`schedule`] the task (which consumes `Analysis`) on the @@ -186,9 +197,9 @@ executing "goto definition" on the threadpool and a new change comes in, the task will be canceled as soon as the main loop calls `apply_change` on the `AnalysisHost`. -["goto definition"]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/server_world.rs#L216 -[`schedule`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L426-L455 -[The task]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop/handlers.rs#L205-L223 +["goto definition"]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/main_loop.rs#L767 +[`schedule`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/dispatch.rs#L138 +[The task]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/handlers/request.rs#L610-L623 This concludes the overview of the analyzer's programing *interface*. Next, let's dig into the implementation! @@ -247,16 +258,17 @@ confusing. This illustration by @killercup might help: ## Salsa Input Queries All analyzer information is stored in a salsa database. `Analysis` and -`AnalysisHost` types are newtype wrappers for [`RootDatabase`] -- a salsa -database. +`AnalysisHost` types are essentially newtype wrappers for [`RootDatabase`] +-- a salsa database. -[`RootDatabase`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/db.rs#L88-L134 +[`RootDatabase`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/ide-db/src/lib.rs#L69-L324 -Salsa input queries are defined in [`FilesDatabase`] (which is a part of -`RootDatabase`). They closely mirror the familiar `Change` structure: -indeed, what `apply_change` does is it sets the values of input queries. +Salsa input queries are defined in [`SourceDatabase`] and [`SourceDatabaseExt`] +(which are a part of `RootDatabase`). They closely mirror the familiar `Change` +structure: indeed, what `apply_change` does is it sets the values of input queries. -[`FilesDatabase`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/base_db/src/input.rs#L150-L174 +[`SourceDatabase`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/base-db/src/lib.rs#L58-L65 +[`SourceDatabaseExt`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/base-db/src/lib.rs#L76-L88 ## From text to semantic model @@ -270,18 +282,18 @@ functions: for example, the same source file might get included as a module in several crates or a single crate might be present in the compilation DAG several times, with different sets of `cfg`s enabled. The IDE-specific task of mapping source code into a semantic model is inherently imprecise for -this reason and gets handled by the [`source_binder`]. +this reason and gets handled by the [`source_analyzer`]. -[`source_binder`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/source_binder.rs +[`source_analyzer`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir/src/source_analyzer.rs -The semantic interface is declared in the [`code_model_api`] module. Each entity is +The semantic interface is declared in the [`semantics`] module. Each entity is identified by an integer ID and has a bunch of methods which take a salsa database as an argument and returns other entities (which are also IDs). Internally, these methods invoke various queries on the database to build the model on demand. Here's [the list of queries]. -[`code_model_api`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/code_model_api.rs -[the list of queries]: https://github.com/rust-lang/rust-analyzer/blob/7e84440e25e19529e4ff8a66e521d1b06349c6ec/crates/ra_hir/src/db.rs#L20-L106 +[`semantics`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir/src/semantics.rs +[the list of queries]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-ty/src/db.rs#L29-L275 The first step of building the model is parsing the source code. @@ -327,7 +339,7 @@ The implementation is based on the generic [rowan] crate on top of which a [libsyntax]: https://github.com/apple/swift/tree/5e2c815edfd758f9b1309ce07bfc01c4bc20ec23/lib/Syntax [rowan]: https://github.com/rust-analyzer/rowan/tree/100a36dc820eb393b74abe0d20ddf99077b61f88 -[rust-specific]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_syntax/src/ast/generated.rs +[rust-specific]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/syntax/src/ast/generated.rs The next step in constructing the semantic model is ... @@ -336,9 +348,9 @@ The next step in constructing the semantic model is ... The algorithm for building a tree of modules is to start with a crate root (remember, each `Crate` from a `CrateGraph` has a `FileId`), collect all `mod` declarations and recursively process child modules. This is handled by the -[`module_tree_query`], with two slight variations. +[`crate_def_map_query`], with two slight variations. -[`module_tree_query`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/module_tree.rs#L115-L133 +[`crate_def_map_query`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-def/src/nameres.rs#L307-L324 First, rust-analyzer builds a module tree for all crates in a source root simultaneously. The main reason for this is historical (`module_tree` predates @@ -347,21 +359,21 @@ part of any crate. That is, if you create a file but do not include it as a submodule anywhere, you still get semantic completion, and you get a warning about a free-floating module (the actual warning is not implemented yet). -The second difference is that `module_tree_query` does not *directly* depend on -the "parse" query (which is confusingly called `source_file`). Why would calling -the parse directly be bad? Suppose the user changes the file slightly, by adding -an insignificant whitespace. Adding whitespace changes the parse tree (because -it includes whitespace), and that means recomputing the whole module tree. +The second difference is that `crate_def_map_query` does not *directly* depend on +the `SourceDatabase::parse` query. Why would calling the parse directly be bad? +Suppose the user changes the file slightly, by adding an insignificant whitespace. +Adding whitespace changes the parse tree (because it includes whitespace), +and that means recomputing the whole module tree. -We deal with this problem by introducing an intermediate [`submodules_query`]. +We deal with this problem by introducing an intermediate [`block_def_map_query`]. This query processes the syntax tree and extracts a set of declared submodule -names. Now, changing the whitespace results in `submodules_query` being +names. Now, changing the whitespace results in `block_def_map_query` being re-executed for a *single* module, but because the result of this query stays -the same, we don't have to re-execute [`module_tree_query`]. In fact, we only +the same, we don't have to re-execute [`crate_def_map_query`]. In fact, we only need to re-execute it when we add/remove new files or when we change mod declarations. -[`submodules_query`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/module_tree.rs#L41 +[`block_def_map_query`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-def/src/nameres.rs#L326-L354 We store the resulting modules in a `Vec`-based indexed arena. The indices in the arena becomes module IDs. And this brings us to the next topic: @@ -383,20 +395,23 @@ change the location. However, such "ID" types ceases to be a `Copy`able integer general can become pretty large if we account for nesting (for example: "third parameter of the `foo` function of the `bar` `impl` in the `baz` module"). -[`LocationInterner`] allows us to combine the benefits of positional and numeric -IDs. It is a bidirectional append-only map between locations and consecutive -integers which can "intern" a location and return an integer ID back. The salsa -database we use includes a couple of [interners]. How to "garbage collect" -unused locations is an open question. +[`Intern` and `Lookup`] traits allows us to combine the benefits of positional and numeric +IDs. Implementing both traits effectively creates a bidirectional append-only map +between locations and integer IDs (typically newtype wrappers for [`salsa::InternId`]) +which can "intern" a location and return an integer ID back. The salsa database we use +includes a couple of [interners]. How to "garbage collect" unused locations +is an open question. -[`LocationInterner`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_db/src/loc2id.rs#L65-L71 -[interners]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/db.rs#L22-L23 +[`Intern` and `Lookup`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-expand/src/lib.rs#L96-L106 +[interners]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-expand/src/lib.rs#L108-L122 +[`salsa::InternId`]: https://docs.rs/salsa/0.16.1/salsa/struct.InternId.html -For example, we use `LocationInterner` to assign IDs to definitions of functions, -structs, enums, etc. The location, [`DefLoc`] contains two bits of information: +For example, we use `Intern` and `Lookup` implementations to assign IDs to +definitions of functions, structs, enums, etc. The location, [`ItemLoc`] contains +two bits of information: * the ID of the module which contains the definition, -* the ID of the specific item in the modules source code. +* the ID of the specific item in the module's source code. We "could" use a text offset for the location of a particular item, but that would play badly with salsa: offsets change after edits. So, as a rule of thumb, we avoid @@ -404,7 +419,7 @@ using offsets, text ranges or syntax trees as keys and values for queries. What we do instead is we store "index" of the item among all of the items of a file (so, a positional based ID, but localized to a single file). -[`DefLoc`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ids.rs#L129-L139 +[`ItemLoc`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-def/src/lib.rs#L209-L212 One thing we've glossed over for the time being is support for macros. We have only proof of concept handling of macros at the moment, but they are extremely @@ -424,20 +439,21 @@ enum HirFileId { } ``` -`MacroCallId` is an interned ID that specifies a particular macro invocation. -Its `MacroCallLoc` contains: +`MacroCallId` is an interned ID that identifies a particular macro invocation. +Simplifying, it's a `HirFileId` of a file containing the call plus the offset +of the macro call in the file. -* `ModuleId` of the containing module -* `HirFileId` of the containing file or pseudo file -* an index of this particular macro invocation in this file (positional id - again). - -Note how `HirFileId` is defined in terms of `MacroCallLoc` which is defined in +Note how `HirFileId` is defined in terms of `MacroCallId` which is defined in terms of `HirFileId`! This does not recur infinitely though: any chain of `HirFileId`s bottoms out in `HirFileId::FileId`, that is, some source file actually written by the user. -[`HirFileId`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ids.rs#L31-L93 +Note also that in the actual implementation, the two variants are encoded in +a single `u32`, which are differentiated by the MSB (most significant bit). +If the MSB is 0, the value represents a `FileId`, otherwise the remaining +31 bits represent a `MacroCallId`. + +[`HirFileId`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/span/src/lib.rs#L148-L160 Now that we understand how to identify a definition, in a source or in a macro-generated file, we can discuss name resolution a bit. @@ -451,13 +467,13 @@ each module into a position-independent representation which does not change if we modify bodies of the items. After that we [loop] resolving all imports until we've reached a fixed point. -[lower]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L113-L147 -[loop]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres.rs#L186-L196 +[lower]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-def/src/item_tree.rs#L110-L154 +[loop]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-def/src/nameres/collector.rs#L404-L437 And, given all our preparation with IDs and a position-independent representation, it is satisfying to [test] that typing inside function body does not invalidate name resolution results. -[test]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/tests.rs#L376 +[test]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-def/src/nameres/tests/incremental.rs#L31 An interesting fact about name resolution is that it "erases" all of the intermediate paths from the imports: in the end, we know which items are defined @@ -481,21 +497,18 @@ store the syntax node as a part of name resolution: this will break incrementality, due to the fact that syntax changes after every file modification. -We solve this problem during the lowering step of name resolution. The lowering -query actually produces a *pair* of outputs: `LoweredModule` and [`SourceMap`]. -The `LoweredModule` module contains [imports], but in a position-independent form. -The `SourceMap` contains a mapping from position-independent imports to -(position-dependent) syntax nodes. +We solve this problem during the lowering step of name resolution. Along with +the [`ItemTree`] output, the lowering query additionally produces an [`AstIdMap`] +via an [`ast_id_map`] query. The `ItemTree` contains [imports], but in a +position-independent form based on [`AstId`]. The `AstIdMap` contains a mapping +from position-independent `AstId`s to (position-dependent) syntax nodes. -The result of this basic lowering query changes after every modification. But -there's an intermediate [projection query] which returns only the first -position-independent part of the lowering. The result of this query is stable. -Naturally, name resolution [uses] this stable projection query. +[`ItemTree`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-def/src/item_tree.rs +[`AstIdMap`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-expand/src/ast_id_map.rs#L136-L142 +[`ast_id_map`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-def/src/item_tree/lower.rs#L32 +[imports]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-def/src/item_tree.rs#L559-L563 +[`AstId`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-expand/src/ast_id_map.rs#L29 -[imports]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L52-L59 -[`SourceMap`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L52-L59 -[projection query]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L97-L103 -[uses]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/query_definitions.rs#L49 ## Type inference @@ -517,10 +530,10 @@ construct a mapping from `ExprId`s to types. [@flodiebold]: https://github.com/flodiebold [#327]: https://github.com/rust-lang/rust-analyzer/pull/327 -[lower the AST]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs -[positional ID]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs#L13-L15 -[a source map]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs#L41-L44 -[type inference]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ty.rs#L1208-L1223 +[lower the AST]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-def/src/body.rs +[positional ID]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-def/src/hir.rs#L37 +[a source map]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-def/src/body.rs#L84-L88 +[type inference]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/hir-ty/src/infer.rs#L76-L131 ## Tying it all together: completion @@ -537,36 +550,38 @@ types (by converting a file url into a numeric `FileId`), [ask analysis for completion] and serialize results into the LSP. The [completion implementation] is finally the place where we start doing the actual -work. The first step is to collect the `CompletionContext` -- a struct which +work. The first step is to collect the [`CompletionContext`] -- a struct which describes the cursor position in terms of Rust syntax and semantics. For -example, `function_syntax: Option<&'a ast::FnDef>` stores a reference to -the enclosing function *syntax*, while `function: Option` is the -`Def` for this function. +example, `expected_name: Option` is the syntactic representation +for the expected name of what we're completing (usually the parameter name of +a function argument), while `expected_type: Option` is the semantic model +for the expected type of what we're completing. To construct the context, we first do an ["IntelliJ Trick"]: we insert a dummy identifier at the cursor's position and parse this modified file, to get a reasonably looking syntax tree. Then we do a bunch of "classification" routines -to figure out the context. For example, we [find an ancestor `fn` node] and we get a -[semantic model] for it (using the lossy `source_binder` infrastructure). +to figure out the context. For example, we [find an parent `fn` node], get a +[semantic model] for it (using the lossy `source_analyzer` infrastructure) +and use it to determine the [expected type at the cursor position]. The second step is to run a [series of independent completion routines]. Let's take a closer look at [`complete_dot`], which completes fields and methods in -`foo.bar|`. First we extract a semantic function and a syntactic receiver -expression out of the `Context`. Then we run type-inference for this single -function and map our syntactic expression to `ExprId`. Using the ID, we figure -out the type of the receiver expression. Then we add all fields & methods from -the type to completion. +`foo.bar|`. First we extract a semantic receiver type out of the `DotAccess` +argument. Then, using the semantic model for the type, we determine if the +receiver implements the `Future` trait, and add a `.await` completion item in +the affirmative case. Finally, we add all fields & methods from the type to +completion. -[receiving a message]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L203 -[schedule it on the threadpool]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L428 -[catch]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L436-L442 -[the handler]: https://salsa.zulipchat.com/#narrow/stream/181542-rfcs.2Fsalsa-query-group/topic/design.20next.20steps -[ask analysis for completion]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/lib.rs#L439-L444 -[ask analysis for completion]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L439-L444 -[completion implementation]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion.rs#L46-L62 -[`CompletionContext`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/completion_context.rs#L14-L37 -["IntelliJ Trick"]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/completion_context.rs#L72-L75 -[find an ancestor `fn` node]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/completion_context.rs#L116-L120 -[semantic model]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/completion_context.rs#L123 -[series of independent completion routines]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion.rs#L52-L59 -[`complete_dot`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/completion/complete_dot.rs#L6-L22 +[receiving a message]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/main_loop.rs#L213 +[schedule it on the threadpool]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/dispatch.rs#L197-L211 +[catch]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/dispatch.rs#L292 +[the handler]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/handlers/request.rs#L850-L876 +[ask analysis for completion]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/ide/src/lib.rs#L605-L615 +[completion implementation]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/ide-completion/src/lib.rs#L148-L229 +[`CompletionContext`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/ide-completion/src/context.rs#L407-L441 +["IntelliJ Trick"]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/ide-completion/src/context.rs#L644-L648 +[find an parent `fn` node]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/ide-completion/src/context/analysis.rs#L463 +[semantic model]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/ide-completion/src/context/analysis.rs#L466 +[expected type at the cursor position]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/ide-completion/src/context/analysis.rs#L467 +[series of independent completion routines]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/ide-completion/src/lib.rs#L157-L226 +[`complete_dot`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/ide-completion/src/completions/dot.rs#L11-L41 diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index c3f249e0ce2c..ecc90abff135 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -596,6 +596,11 @@ Maximum length for inlay hints. Set to null to have an unlimited length. Whether to show function parameter name inlay hints at the call site. -- +[[rust-analyzer.inlayHints.rangeExclusiveHints.enable]]rust-analyzer.inlayHints.rangeExclusiveHints.enable (default: `false`):: ++ +-- +Whether to show exclusive range inlay hints. +-- [[rust-analyzer.inlayHints.reborrowHints.enable]]rust-analyzer.inlayHints.reborrowHints.enable (default: `"never"`):: + -- diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc index 9fc19a7d0745..fa8413c19ae0 100644 --- a/src/tools/rust-analyzer/docs/user/manual.adoc +++ b/src/tools/rust-analyzer/docs/user/manual.adoc @@ -186,18 +186,13 @@ $ pacman -S rust-analyzer ==== Gentoo Linux -`rust-analyzer` is available in the GURU repository: +There are two ways to install `rust-analyzer` under Gentoo: -- https://gitweb.gentoo.org/repo/proj/guru.git/tree/dev-util/rust-analyzer?id=9895cea62602cfe599bd48e0fb02127411ca6e81[`dev-util/rust-analyzer`] builds from source -- https://gitweb.gentoo.org/repo/proj/guru.git/tree/dev-util/rust-analyzer-bin?id=9895cea62602cfe599bd48e0fb02127411ca6e81[`dev-util/rust-analyzer-bin`] installs an official binary release +- when installing `dev-lang/rust` or `dev-lang/rust-bin`, enable the `rust-analyzer` and `rust-src` USE flags +- use the `rust-analyzer` component in `rustup` (see instructions above) -If not already, GURU must be enabled (e.g. using `app-eselect/eselect-repository`) and sync'd before running `emerge`: - -[source,bash] ----- -$ eselect repository enable guru && emaint sync -r guru -$ emerge rust-analyzer-bin ----- +Note that in both cases, the version installed lags for a couple of months behind the official releases on GitHub. +To obtain a newer one, you can download a binary from GitHub Releases or building from source. ==== macOS diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 27ed8ac502b5..8307f6833e6f 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -1308,6 +1308,11 @@ "default": true, "type": "boolean" }, + "rust-analyzer.inlayHints.rangeExclusiveHints.enable": { + "markdownDescription": "Whether to show exclusive range inlay hints.", + "default": false, + "type": "boolean" + }, "rust-analyzer.inlayHints.reborrowHints.enable": { "markdownDescription": "Whether to show inlay hints for compiler inserted reborrows.\nThis setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.", "default": "never", diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index 987d936943a1..51a0aece820e 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -5,6 +5,7 @@ import * as vscode from "vscode"; import type { Env } from "./client"; import { log } from "./util"; import { expectNotUndefined, unwrapUndefinable } from "./undefinable"; +import type { JsonProject } from "./rust_project"; export type RunnableEnvCfgItem = { mask?: string; diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts index 63ae386c8ad1..55163241c2ac 100644 --- a/src/tools/rust-analyzer/editors/code/src/ctx.ts +++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts @@ -23,6 +23,7 @@ import { execRevealDependency } from "./commands"; import { PersistentState } from "./persistent_state"; import { bootstrap } from "./bootstrap"; import type { RustAnalyzerExtensionApi } from "./main"; +import type { JsonProject } from "./rust_project"; // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if // only those are in use. We use "Empty" to represent these scenarios diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts index 3073353674ce..599cfb4ff77a 100644 --- a/src/tools/rust-analyzer/editors/code/src/main.ts +++ b/src/tools/rust-analyzer/editors/code/src/main.ts @@ -6,6 +6,7 @@ import { type CommandFactory, Ctx, fetchWorkspace } from "./ctx"; import * as diagnostics from "./diagnostics"; import { activateTaskProvider } from "./tasks"; import { setContextValue } from "./util"; +import type { JsonProject } from "./rust_project"; const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; diff --git a/src/tools/rust-analyzer/editors/code/src/rust_project.ts b/src/tools/rust-analyzer/editors/code/src/rust_project.ts index 187a1a96c10c..bf65ad43ba59 100644 --- a/src/tools/rust-analyzer/editors/code/src/rust_project.ts +++ b/src/tools/rust-analyzer/editors/code/src/rust_project.ts @@ -1,4 +1,4 @@ -interface JsonProject { +export interface JsonProject { /// Path to the directory with *source code* of /// sysroot crates. /// @@ -21,7 +21,7 @@ interface JsonProject { crates: Crate[]; } -interface Crate { +export interface Crate { /// Optional crate name used for display purposes, /// without affecting semantics. See the `deps` /// key for semantically-significant crate names. @@ -82,7 +82,7 @@ interface Crate { proc_macro_dylib_path?: string; } -interface Dep { +export interface Dep { /// Index of a crate in the `crates` array. crate: number; /// Name as should appear in the (implicit) diff --git a/src/tools/rust-analyzer/editors/code/tsconfig.json b/src/tools/rust-analyzer/editors/code/tsconfig.json index c74284a00d96..87cfd1b2ee11 100644 --- a/src/tools/rust-analyzer/editors/code/tsconfig.json +++ b/src/tools/rust-analyzer/editors/code/tsconfig.json @@ -2,7 +2,7 @@ "extends": "@tsconfig/strictest/tsconfig.json", "compilerOptions": { "esModuleInterop": false, - "module": "CommonJS", + "module": "Node16", "moduleResolution": "Node16", "target": "ES2021", "outDir": "out", diff --git a/src/tools/rust-analyzer/lib/line-index/README.md b/src/tools/rust-analyzer/lib/line-index/README.md new file mode 100644 index 000000000000..93ac03696a0d --- /dev/null +++ b/src/tools/rust-analyzer/lib/line-index/README.md @@ -0,0 +1,30 @@ +# line-index + +This crate is developed as part of `rust-analyzer`. + +line-index is a library to convert between text offsets and corresponding line/column coordinates. + +## Installation + +To add this crate to a project simply run `cargo add line-index`. + +## Usage + +The main structure is `LineIndex`. + +It is constructed with an UTF-8 string, but also supports UTF-16 and UTF-32 offsets. + +### Example + +```rust +use line_index::LineIndex; + +let line_index = LineIndex::new("This is a\nmulti-line\ntext."); +line_index.line_col(3.into()); // LineCol { line: 0, col: 3 } +line_index.line_col(13.into()); // LineCol { line: 1, col: 3 } +line_index.offset(LineCol { line: 2, col: 3 }); // Some (24) +``` + +## SemVer + +This crate uses [semver](https://semver.org/) versioning. diff --git a/src/tools/rustfmt/src/parse/parser.rs b/src/tools/rustfmt/src/parse/parser.rs index 6bc53159b38b..7045a7dd9ce3 100644 --- a/src/tools/rustfmt/src/parse/parser.rs +++ b/src/tools/rustfmt/src/parse/parser.rs @@ -114,7 +114,7 @@ impl<'a> Parser<'a> { let mut parser = new_parser_from_file(sess.inner(), path, Some(span)); match parser.parse_mod(&TokenKind::Eof) { Ok((a, i, spans)) => Some((a, i, spans.inner_span)), - Err(mut e) => { + Err(e) => { e.emit(); if sess.can_reset_errors() { sess.reset_errors(); @@ -165,7 +165,7 @@ impl<'a> Parser<'a> { match catch_unwind(move || parser.parse_crate_mod()) { Ok(Ok(k)) => Ok(k), - Ok(Err(mut db)) => { + Ok(Err(db)) => { db.emit(); Err(ParserError::ParseError) } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 3c00027b9fdc..62d48315d434 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -325,6 +325,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "sha1", "sha2", "sharded-slab", + "shlex", "smallvec", "snap", "stable_deref_trait", diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index b4745d4883c5..32e271d4a565 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -11,7 +11,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: usize = 1849; -const ROOT_ENTRY_LIMIT: usize = 867; +const ROOT_ENTRY_LIMIT: usize = 868; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files @@ -33,9 +33,12 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ "tests/ui/macros/macro-expanded-include/file.txt", // testing including data with the include macros "tests/ui/macros/not-utf8.bin", // testing including data with the include macros "tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include - "tests/ui/unused-crate-deps/test.mk", // why would you use make "tests/ui/proc-macro/auxiliary/included-file.txt", // more include "tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer + "tests/ui/shell-argfiles/shell-argfiles.args", // passing args via a file + "tests/ui/shell-argfiles/shell-argfiles-badquotes.args", // passing args via a file + "tests/ui/shell-argfiles/shell-argfiles-via-argfile-shell.args", // passing args via a file + "tests/ui/shell-argfiles/shell-argfiles-via-argfile.args", // passing args via a file ]; fn check_entries(tests_path: &Path, bad: &mut bool) { diff --git a/tests/codegen/vec-iter.rs b/tests/codegen/vec-iter.rs new file mode 100644 index 000000000000..0282791e9d16 --- /dev/null +++ b/tests/codegen/vec-iter.rs @@ -0,0 +1,46 @@ +// ignore-debug: the debug assertions get in the way +// compile-flags: -O +#![crate_type = "lib"] +#![feature(exact_size_is_empty)] + +use std::vec; + +// CHECK-LABEL: @vec_iter_len_nonnull +#[no_mangle] +pub fn vec_iter_len_nonnull(it: &vec::IntoIter) -> usize { + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: sub nuw + // CHECK: ret + it.len() +} + +// CHECK-LABEL: @vec_iter_is_empty_nonnull +#[no_mangle] +pub fn vec_iter_is_empty_nonnull(it: &vec::IntoIter) -> bool { + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: ret + it.is_empty() +} + +// CHECK-LABEL: @vec_iter_next +#[no_mangle] +pub fn vec_iter_next(it: &mut vec::IntoIter) -> Option { + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: ret + it.next() +} diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index 522c1e73afe3..c5ac17600cd2 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -81,21 +81,18 @@ Number of file 0 mappings: 1 - Code(Zero) at (prev + 171, 13) to (start + 2, 14) Function name: closure::main::{closure#14} -Raw bytes (36): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 05, 03, b2, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 01, 0d, 00, 0e] +Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, b2, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 07, 01, 0d, 00, 0e] Number of files: 1 - file 0 => global file 1 -Number of expressions: 3 -- expression 0 operands: lhs = Counter(1), rhs = Expression(2, Sub) -- expression 1 operands: lhs = Counter(0), rhs = Counter(1) -- expression 2 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 5 -- Code(Expression(0, Add)) at (prev + 178, 13) to (start + 0, 21) - = (c1 + (c0 - c1)) -- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27) -- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37) -- Code(Expression(2, Sub)) at (prev + 0, 47) to (start + 0, 51) +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 178, 13) to (start + 2, 27) +- Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37) +- Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) -- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 14) +- Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 14) = (c1 + (c0 - c1)) Function name: closure::main::{closure#15} @@ -118,21 +115,18 @@ Number of file 0 mappings: 6 = (c1 + (c0 - c1)) Function name: closure::main::{closure#16} -Raw bytes (36): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 05, 03, c4, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 01, 0d, 00, 0e] +Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, c4, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 07, 01, 0d, 00, 0e] Number of files: 1 - file 0 => global file 1 -Number of expressions: 3 -- expression 0 operands: lhs = Counter(1), rhs = Expression(2, Sub) -- expression 1 operands: lhs = Counter(0), rhs = Counter(1) -- expression 2 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 5 -- Code(Expression(0, Add)) at (prev + 196, 13) to (start + 0, 21) - = (c1 + (c0 - c1)) -- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27) -- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37) -- Code(Expression(2, Sub)) at (prev + 0, 47) to (start + 0, 51) +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 196, 13) to (start + 2, 27) +- Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37) +- Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) -- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 14) +- Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 14) = (c1 + (c0 - c1)) Function name: closure::main::{closure#17} diff --git a/tests/coverage/inline-dead.cov-map b/tests/coverage/inline-dead.cov-map index 958b423f24cf..ab04e746b916 100644 --- a/tests/coverage/inline-dead.cov-map +++ b/tests/coverage/inline-dead.cov-map @@ -31,14 +31,14 @@ Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 7, 6) to (start + 2, 2) Function name: inline_dead::main::{closure#0} -Raw bytes (23): 0x[01, 01, 02, 00, 06, 01, 00, 03, 01, 07, 17, 00, 18, 00, 02, 0d, 00, 0e, 03, 02, 05, 00, 06] +Raw bytes (23): 0x[01, 01, 02, 00, 06, 01, 00, 03, 01, 07, 17, 01, 16, 00, 02, 0d, 00, 0e, 03, 02, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Zero, rhs = Expression(1, Sub) - expression 1 operands: lhs = Counter(0), rhs = Zero Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 7, 23) to (start + 0, 24) +- Code(Counter(0)) at (prev + 7, 23) to (start + 1, 22) - Code(Zero) at (prev + 2, 13) to (start + 0, 14) - Code(Expression(0, Add)) at (prev + 2, 5) to (start + 0, 6) = (Zero + (c0 - Zero)) diff --git a/tests/coverage/inline-dead.coverage b/tests/coverage/inline-dead.coverage index de96aa17acd6..7c201f482db3 100644 --- a/tests/coverage/inline-dead.coverage +++ b/tests/coverage/inline-dead.coverage @@ -5,7 +5,7 @@ LL| 1| println!("{}", live::()); LL| 1| LL| 1| let f = |x: bool| { - LL| | debug_assert!( + LL| 1| debug_assert!( LL| 0| x LL| | ); LL| 1| }; diff --git a/tests/coverage/unicode.cov-map b/tests/coverage/unicode.cov-map new file mode 100644 index 000000000000..cd40194a0831 --- /dev/null +++ b/tests/coverage/unicode.cov-map @@ -0,0 +1,53 @@ +Function name: unicode::main +Raw bytes (67): 0x[01, 01, 09, 01, 05, 03, 05, 1e, 0d, 22, 09, 03, 05, 11, 1b, 1e, 0d, 22, 09, 03, 05, 09, 01, 0e, 01, 00, 0b, 05, 01, 09, 00, 0c, 03, 00, 10, 00, 1b, 05, 00, 1c, 00, 28, 22, 02, 08, 00, 25, 09, 00, 29, 00, 46, 11, 00, 47, 02, 06, 1b, 02, 06, 00, 07, 17, 02, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 9 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(1) +- expression 2 operands: lhs = Expression(7, Sub), rhs = Counter(3) +- expression 3 operands: lhs = Expression(8, Sub), rhs = Counter(2) +- expression 4 operands: lhs = Expression(0, Add), rhs = Counter(1) +- expression 5 operands: lhs = Counter(4), rhs = Expression(6, Add) +- expression 6 operands: lhs = Expression(7, Sub), rhs = Counter(3) +- expression 7 operands: lhs = Expression(8, Sub), rhs = Counter(2) +- expression 8 operands: lhs = Expression(0, Add), rhs = Counter(1) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 11) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) +- Code(Expression(0, Add)) at (prev + 0, 16) to (start + 0, 27) + = (c0 + c1) +- Code(Counter(1)) at (prev + 0, 28) to (start + 0, 40) +- Code(Expression(8, Sub)) at (prev + 2, 8) to (start + 0, 37) + = ((c0 + c1) - c1) +- Code(Counter(2)) at (prev + 0, 41) to (start + 0, 70) +- Code(Counter(4)) at (prev + 0, 71) to (start + 2, 6) +- Code(Expression(6, Add)) at (prev + 2, 6) to (start + 0, 7) + = ((((c0 + c1) - c1) - c2) + c3) +- Code(Expression(5, Add)) at (prev + 2, 5) to (start + 1, 2) + = (c4 + ((((c0 + c1) - c1) - c2) + c3)) + +Function name: unicode::サビ +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 14, 00, 18] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 30, 20) to (start + 0, 24) + +Function name: unicode::他 (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 1e, 19, 00, 25] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 30, 25) to (start + 0, 37) + +Function name: unicode::申し訳ございません +Raw bytes (9): 0x[01, 01, 00, 01, 01, 18, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 24, 1) to (start + 2, 2) + diff --git a/tests/coverage/unicode.coverage b/tests/coverage/unicode.coverage new file mode 100644 index 000000000000..b284a557d575 --- /dev/null +++ b/tests/coverage/unicode.coverage @@ -0,0 +1,40 @@ + LL| |// edition: 2021 + LL| |// ignore-windows - we can't force `llvm-cov` to use ANSI escapes on Windows + LL| |// llvm-cov-flags: --use-color + LL| | + LL| |// Check that column numbers are denoted in bytes, so that they don't cause + LL| |// `llvm-cov` to fail or emit malformed output. + LL| |// + LL| |// Note that when `llvm-cov` prints ^ arrows on a subsequent line, it simply + LL| |// inserts one space character for each "column", with no understanding of + LL| |// Unicode or character widths. So those arrows will tend to be misaligned + LL| |// for non-ASCII source code, regardless of whether column numbers are code + LL| |// points or bytes. + LL| | + LL| 1|fn main() { + LL| 33| for _İ in 'А'..='Я' { /* Я */ } + ^32 ^32 + LL| | + LL| 1| if 申し訳ございません() && 申し訳ございません() { + ^0 + LL| 0| println!("true"); + LL| 1| } + LL| | + LL| 1| サビ(); + LL| 1|} + LL| | + LL| 1|fn 申し訳ございません() -> bool { + LL| 1| std::hint::black_box(false) + LL| 1|} + LL| | + LL| |macro_rules! macro_that_defines_a_function { + LL| | (fn $名:ident () $体:tt) => { + LL| 1| fn $名 () $体 fn 他 () {} + ^0 + LL| | } + LL| |} + LL| | + LL| |macro_that_defines_a_function! { + LL| | fn サビ() {} + LL| |} + diff --git a/tests/coverage/unicode.rs b/tests/coverage/unicode.rs new file mode 100644 index 000000000000..dfc5ea69dd23 --- /dev/null +++ b/tests/coverage/unicode.rs @@ -0,0 +1,36 @@ +// edition: 2021 +// ignore-windows - we can't force `llvm-cov` to use ANSI escapes on Windows +// llvm-cov-flags: --use-color + +// Check that column numbers are denoted in bytes, so that they don't cause +// `llvm-cov` to fail or emit malformed output. +// +// Note that when `llvm-cov` prints ^ arrows on a subsequent line, it simply +// inserts one space character for each "column", with no understanding of +// Unicode or character widths. So those arrows will tend to be misaligned +// for non-ASCII source code, regardless of whether column numbers are code +// points or bytes. + +fn main() { + for _İ in 'А'..='Я' { /* Я */ } + + if 申し訳ございません() && 申し訳ございません() { + println!("true"); + } + + サビ(); +} + +fn 申し訳ございません() -> bool { + std::hint::black_box(false) +} + +macro_rules! macro_that_defines_a_function { + (fn $名:ident () $体:tt) => { + fn $名 () $体 fn 他 () {} + } +} + +macro_that_defines_a_function! { + fn サビ() {} +} diff --git a/tests/debuginfo/collapse-debuginfo-in-non-collapse-macro.rs b/tests/debuginfo/collapse-debuginfo-in-non-collapse-macro.rs new file mode 100644 index 000000000000..d9500c3641ef --- /dev/null +++ b/tests/debuginfo/collapse-debuginfo-in-non-collapse-macro.rs @@ -0,0 +1,124 @@ +// ignore-lldb +#![feature(collapse_debuginfo)] + +// Test that statement, skipped/added/reordered by macros, is correctly processed in debuginfo. +// When nested macros instantiations are tagged with collapse_debuginfo attribute, +// debug info should be corrected to the first outer macro instantiation +// without collapse_debuginfo attribute. +// collapse_debuginfo feature enabled. + +// compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_rem_call1[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call1_pre[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_in_proxy[...] +// gdb-command:next 2 +// gdb-check:[...]#loc_rem_call3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_add_call1[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call1_pre[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_in_proxy[...] +// gdb-command:next 2 +// gdb-check:[...]#loc_add_macro[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_add_call3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_reorder_call2[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_reorder_call3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_reorder_call1[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call1_pre[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_in_proxy[...] +// gdb-command:next 2 +// gdb-command:frame +// gdb-command:continue + +#[inline(never)] +fn myprintln_impl(text: &str) { + println!("{}", text) +} + +#[collapse_debuginfo] +macro_rules! myprintln { + ($($arg:tt)*) => {{ + myprintln_impl($($arg)*); + }}; +} + +macro_rules! proxy_println { + ($($arg:tt)*) => {{ + myprintln!($($arg)*); // #loc_in_proxy + }}; +} + +// Macro accepts 3 statements and removes the 2nd statement +macro_rules! remove_second_statement { + ($s1:stmt; $s2:stmt; $s3:stmt;) => { $s1 $s3 } +} + +macro_rules! add_second_statement { + ($s1:stmt; $s3:stmt;) => { + $s1 + call2(); // #loc_add_macro + $s3 + } +} + +macro_rules! reorder_statements { + ($s1:stmt; $s2:stmt; $s3:stmt;) => { $s2 $s3 $s1 } +} + +fn call1() { + let rv = 0; // #loc_call1_pre + proxy_println!("one"); // #loc_call1 +} + +fn call2() { + proxy_println!("two"); // #loc_call2 +} + +fn call3() { + proxy_println!("three"); // #loc_call3 +} + +fn main() { + let ret = 0; // #break, step should go to call1 + remove_second_statement! { // #loc_rem_hdr + call1(); // #loc_rem_call1 + call2(); // #loc_rem_call2 + call3(); // #loc_rem_call3 + } + add_second_statement! { // #loc_add_hdr + call1(); // #loc_add_call1 + call3(); // #loc_add_call3 + } + reorder_statements! { // #loc_reorder_hdr + call1(); // #loc_reorder_call1 + call2(); // #loc_reorder_call2 + call3(); // #loc_reorder_call3 + } + std::process::exit(ret); // #loc_exit +} diff --git a/tests/debuginfo/skip_second_statement.rs b/tests/debuginfo/skip_second_statement.rs new file mode 100644 index 000000000000..535b54747631 --- /dev/null +++ b/tests/debuginfo/skip_second_statement.rs @@ -0,0 +1,168 @@ +// ignore-lldb + +// Test that statement, skipped/added/reordered by macros, is correctly processed in debuginfo. +// Performed step-over and step-into debug stepping through call statements. +// collapse_debuginfo feature disabled. + +// compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_rem1_call1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_rem1_call3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_rem2_call1[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call1[...] +// gdb-command:next 2 +// gdb-check:[...]#loc_rem2_call3[...] +// gdb-command:step 2 +// gdb-command:frame +// gdb-check:[...]#loc_call3_println[...] +// gdb-command:next 3 +// gdb-command:frame +// gdb-check:[...]#loc_after_rem[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_add1_call1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_add1_hdr[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_add1_call3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_add2_call1[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call1[...] +// gdb-command:next 2 +// gdb-check:[...]#loc_add2_hdr[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call2[...] +// gdb-command:next 2 +// gdb-command:frame +// gdb-check:[...]#loc_add2_call3[...] +// gdb-command:step 2 +// gdb-command:frame +// gdb-check:[...]#loc_call3_println[...] +// gdb-command:next 3 +// gdb-command:frame +// gdb-check:[...]#loc_reorder1_call2[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_reorder1_call3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_reorder1_call1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_reorder2_call2[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call2[...] +// gdb-command:next 2 +// gdb-command:frame +// gdb-check:[...]#loc_reorder2_call3[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call3[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call3_println[...] +// gdb-command:next 3 +// gdb-command:frame +// gdb-check:[...]#loc_reorder2_call1[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call1[...] +// gdb-command:next 2 +// gdb-command:continue + +#[inline(never)] +fn myprintln_impl(text: &str) { + println!("{}", text) +} + +macro_rules! myprintln { + ($($arg:tt)*) => {{ + myprintln_impl($($arg)*); + }}; +} + +// Macro accepts 3 statements and removes the 2nd statement +macro_rules! remove_second_statement { + ($s1:stmt; $s2:stmt; $s3:stmt;) => { $s1 $s3 } +} + +macro_rules! add_second_statement { + ($s1:stmt; $s3:stmt;) => { + $s1 + call2(); // #loc_add_macro + $s3 + } +} + +macro_rules! reorder_statements { + ($s1:stmt; $s2:stmt; $s3:stmt;) => { $s2 $s3 $s1 } +} + +fn call1() { + myprintln!("one"); // #loc_call1 +} + +fn call2() { + myprintln!("two"); // #loc_call2 +} + +fn call3() { + (||{ + myprintln!("three") // #loc_call3_println + })(); // #loc_call3 +} + +fn main() { + let ret = 0; // #break, step should go to call1 + remove_second_statement! { // #loc_rem1_hdr + call1(); // #loc_rem1_call1, breakpoint should set to call1, step should go call3 + call2(); // #loc_rem1_call2, breakpoint should set to call3 + call3(); // #loc_rem1_call3 + } + remove_second_statement! { // #loc_rem2_hdr + call1(); // #loc_rem2_call1, breakpoint should set to call1, step should go call3 + call2(); // #loc_rem2_call2, breakpoint should set to call3 + call3(); // #loc_rem2_call3, breakpoint should set to call3 + } + myprintln!("After remove_second_statement test"); // #loc_after_rem + + add_second_statement! { // #loc_add1_hdr + call1(); // #loc_add1_call1 + call3(); // #loc_add1_call3 + } + add_second_statement! { // #loc_add2_hdr + call1(); // #loc_add2_call1 + call3(); // #loc_add2_call3 + } + + reorder_statements! { // #loc_reorder1_hdr + call1(); // #loc_reorder1_call1 + call2(); // #loc_reorder1_call2 + call3(); // #loc_reorder1_call3 + } + reorder_statements! { // #loc_reorder2_hdr + call1(); // #loc_reorder2_call1 + call2(); // #loc_reorder2_call2 + call3(); // #loc_reorder2_call3 + } + + std::process::exit(ret); // #loc_exit +} diff --git a/tests/debuginfo/skip_second_statement_collapse.rs b/tests/debuginfo/skip_second_statement_collapse.rs new file mode 100644 index 000000000000..a0557ca9feec --- /dev/null +++ b/tests/debuginfo/skip_second_statement_collapse.rs @@ -0,0 +1,170 @@ +// ignore-lldb +#![feature(collapse_debuginfo)] + +// Test that statement, skipped/added/reordered by macros, is correctly processed in debuginfo +// Performed step-over and step-into debug stepping through call statements. +// collapse_debuginfo feature enabled. + +// compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_rem1_call1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_rem1_call3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_rem2_call1[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call1[...] +// gdb-command:next 2 +// gdb-check:[...]#loc_rem2_call3[...] +// gdb-command:step 2 +// gdb-command:frame +// gdb-check:[...]#loc_call3_println[...] +// gdb-command:next 3 +// gdb-command:frame +// gdb-check:[...]#loc_after_rem[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_add1_call1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_add_macro[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_add1_call3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_add2_call1[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call1[...] +// gdb-command:next 2 +// gdb-check:[...]#loc_add_macro[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call2[...] +// gdb-command:next 2 +// gdb-command:frame +// gdb-check:[...]#loc_add2_call3[...] +// gdb-command:step 2 +// gdb-command:frame +// gdb-check:[...]#loc_call3_println[...] +// gdb-command:next 3 +// gdb-command:frame +// gdb-check:[...]#loc_reorder1_call2[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_reorder1_call3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_reorder1_call1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc_reorder2_call2[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call2[...] +// gdb-command:next 2 +// gdb-command:frame +// gdb-check:[...]#loc_reorder2_call3[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call3[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call3_println[...] +// gdb-command:next 3 +// gdb-command:frame +// gdb-check:[...]#loc_reorder2_call1[...] +// gdb-command:step +// gdb-command:frame +// gdb-check:[...]#loc_call1[...] +// gdb-command:next 2 +// gdb-command:continue + +#[inline(never)] +fn myprintln_impl(text: &str) { + println!("{}", text) +} + +#[collapse_debuginfo] +macro_rules! myprintln { + ($($arg:tt)*) => {{ + myprintln_impl($($arg)*); + }}; +} + +// Macro accepts 3 statements and removes the 2nd statement +macro_rules! remove_second_statement { + ($s1:stmt; $s2:stmt; $s3:stmt;) => { $s1 $s3 } +} + +macro_rules! add_second_statement { + ($s1:stmt; $s3:stmt;) => { + $s1 + call2(); // #loc_add_macro + $s3 + } +} + +macro_rules! reorder_statements { + ($s1:stmt; $s2:stmt; $s3:stmt;) => { $s2 $s3 $s1 } +} + +fn call1() { + myprintln!("one"); // #loc_call1 +} + +fn call2() { + myprintln!("two"); // #loc_call2 +} + +fn call3() { + (||{ + myprintln!("three") // #loc_call3_println + })(); // #loc_call3 +} + +fn main() { + let ret = 0; // #break, step should go to call1 + remove_second_statement! { // #loc_rem1_hdr + call1(); // #loc_rem1_call1, breakpoint should set to call1, step should go call3 + call2(); // #loc_rem1_call2, breakpoint should set to call3 + call3(); // #loc_rem1_call3 + } + remove_second_statement! { // #loc_rem2_hdr + call1(); // #loc_rem2_call1, breakpoint should set to call1, step should go call3 + call2(); // #loc_rem2_call2, breakpoint should set to call3 + call3(); // #loc_rem2_call3, breakpoint should set to call3 + } + myprintln!("After remove_second_statement test"); // #loc_after_rem + + add_second_statement! { // #loc_add1_hdr + call1(); // #loc_add1_call1 + call3(); // #loc_add1_call3 + } + add_second_statement! { // #loc_add2_hdr + call1(); // #loc_add2_call1 + call3(); // #loc_add2_call3 + } + + reorder_statements! { // #loc_reorder1_hdr + call1(); // #loc_reorder1_call1 + call2(); // #loc_reorder1_call2 + call3(); // #loc_reorder1_call3 + } + reorder_statements! { // #loc_reorder2_hdr + call1(); // #loc_reorder2_call1 + call2(); // #loc_reorder2_call2 + call3(); // #loc_reorder2_call3 + } + + std::process::exit(ret); // #loc_exit +} diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir index 3a9c80caa1e6..3c0d4008c901 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir @@ -108,7 +108,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb0: { _39 = discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2}))); - switchInt(move _39) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb30]; + switchInt(move _39) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb9]; } bb1: { @@ -345,8 +345,4 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb29: { assert(const false, "`async fn` resumed after completion") -> [success: bb29, unwind unreachable]; } - - bb30: { - unreachable; - } } diff --git a/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.panic-abort.diff index 54875cadec5b..b461869be318 100644 --- a/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.panic-abort.diff +++ b/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.panic-abort.diff @@ -8,20 +8,20 @@ let mut _3: u8; bb0: { -- StorageLive(_2); -+ nop; - StorageLive(_3); - _3 = _1; + StorageLive(_2); +- StorageLive(_3); +- _3 = _1; - _2 = dummy(move _3) -> [return: bb1, unwind unreachable]; -+ _1 = dummy(move _3) -> [return: bb1, unwind unreachable]; ++ nop; ++ nop; ++ _2 = dummy(move _1) -> [return: bb1, unwind unreachable]; } bb1: { - StorageDead(_3); -- _1 = move _2; -- StorageDead(_2); -+ nop; +- StorageDead(_3); + nop; + _1 = move _2; + StorageDead(_2); _0 = const (); return; } diff --git a/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.panic-unwind.diff index b4c8a89278b9..d5c2e07c6c23 100644 --- a/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.panic-unwind.diff +++ b/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.panic-unwind.diff @@ -8,20 +8,20 @@ let mut _3: u8; bb0: { -- StorageLive(_2); -+ nop; - StorageLive(_3); - _3 = _1; + StorageLive(_2); +- StorageLive(_3); +- _3 = _1; - _2 = dummy(move _3) -> [return: bb1, unwind continue]; -+ _1 = dummy(move _3) -> [return: bb1, unwind continue]; ++ nop; ++ nop; ++ _2 = dummy(move _1) -> [return: bb1, unwind continue]; } bb1: { - StorageDead(_3); -- _1 = move _2; -- StorageDead(_2); -+ nop; +- StorageDead(_3); + nop; + _1 = move _2; + StorageDead(_2); _0 = const (); return; } diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff index f50603a66a56..f04ca72dd6d9 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff @@ -56,7 +56,7 @@ StorageLive(_11); StorageLive(_12); _10 = discriminant(_4); - switchInt(move _10) -> [0: bb8, 1: bb6, otherwise: bb7]; + switchInt(move _10) -> [0: bb7, 1: bb6, otherwise: bb2]; } bb1: { @@ -114,20 +114,16 @@ _3 = ControlFlow::, i32>::Break(move _13); StorageDead(_13); - goto -> bb5; -+ goto -> bb9; ++ goto -> bb8; } bb7: { - unreachable; - } - - bb8: { _11 = move ((_4 as Ok).0: i32); _3 = ControlFlow::, i32>::Continue(move _11); goto -> bb5; + } + -+ bb9: { ++ bb8: { + StorageDead(_12); + StorageDead(_11); + StorageDead(_10); diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff index f50603a66a56..f04ca72dd6d9 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff @@ -56,7 +56,7 @@ StorageLive(_11); StorageLive(_12); _10 = discriminant(_4); - switchInt(move _10) -> [0: bb8, 1: bb6, otherwise: bb7]; + switchInt(move _10) -> [0: bb7, 1: bb6, otherwise: bb2]; } bb1: { @@ -114,20 +114,16 @@ _3 = ControlFlow::, i32>::Break(move _13); StorageDead(_13); - goto -> bb5; -+ goto -> bb9; ++ goto -> bb8; } bb7: { - unreachable; - } - - bb8: { _11 = move ((_4 as Ok).0: i32); _3 = ControlFlow::, i32>::Continue(move _11); goto -> bb5; + } + -+ bb9: { ++ bb8: { + StorageDead(_12); + StorageDead(_11); + StorageDead(_10); diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index 66e5c5d3c11c..0cbdaa085bc9 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -50,7 +50,7 @@ fn identity(x: Result) -> Result { // CHECK-LABEL: fn identity( // CHECK: bb0: { // CHECK: [[x:_.*]] = _1; - // CHECK: switchInt(move {{_.*}}) -> [0: bb8, 1: bb6, otherwise: bb7]; + // CHECK: switchInt(move {{_.*}}) -> [0: bb7, 1: bb6, otherwise: bb2]; // CHECK: bb1: { // CHECK: {{_.*}} = (([[controlflow:_.*]] as Continue).0: i32); // CHECK: _0 = Result::::Ok( @@ -68,14 +68,12 @@ fn identity(x: Result) -> Result { // CHECK: bb6: { // CHECK: {{_.*}} = move (([[x]] as Err).0: i32); // CHECK: [[controlflow]] = ControlFlow::, i32>::Break( - // CHECK: goto -> bb9; + // CHECK: goto -> bb8; // CHECK: bb7: { - // CHECK: unreachable; - // CHECK: bb8: { // CHECK: {{_.*}} = move (([[x]] as Ok).0: i32); // CHECK: [[controlflow]] = ControlFlow::, i32>::Continue( // CHECK: goto -> bb5; - // CHECK: bb9: { + // CHECK: bb8: { // CHECK: goto -> bb3; Ok(x?) } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff index 5cb528c0d5f9..47e0d402347d 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff @@ -56,9 +56,9 @@ + _2 = const Option::::None; StorageLive(_10); - _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb1, 1: bb3, otherwise: bb2]; +- switchInt(move _10) -> [0: bb1, 1: bb2, otherwise: bb6]; + _10 = const 0_isize; -+ switchInt(const 0_isize) -> [0: bb1, 1: bb3, otherwise: bb2]; ++ switchInt(const 0_isize) -> [0: bb1, 1: bb2, otherwise: bb6]; } bb1: { @@ -66,10 +66,6 @@ } bb2: { - unreachable; - } - - bb3: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}; StorageDead(_10); @@ -79,18 +75,18 @@ StorageLive(_5); StorageLive(_6); _9 = const _; -- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind unreachable]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb4, unwind unreachable]; +- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb3, unwind unreachable]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb3, unwind unreachable]; } - bb4: { + bb3: { StorageLive(_12); StorageLive(_15); _12 = discriminant(_6); - switchInt(move _12) -> [0: bb6, 1: bb5, otherwise: bb2]; + switchInt(move _12) -> [0: bb5, 1: bb4, otherwise: bb6]; } - bb5: { + bb4: { _15 = const "called `Result::unwrap()` on an `Err` value"; StorageLive(_16); StorageLive(_17); @@ -100,7 +96,7 @@ _14 = result::unwrap_failed(move _15, move _16) -> unwind unreachable; } - bb6: { + bb5: { _5 = move ((_6 as Ok).0: std::ptr::NonNull<[u8]>); StorageDead(_15); StorageDead(_12); @@ -115,6 +111,10 @@ StorageDead(_3); return; } + + bb6: { + unreachable; + } } + + ALLOC0 (size: 8, align: 4) { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff index 1e1585f20aef..dee57ce6c27b 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff @@ -41,9 +41,9 @@ + _2 = const Option::::None; StorageLive(_10); - _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb2, 1: bb4, otherwise: bb3]; +- switchInt(move _10) -> [0: bb2, 1: bb3, otherwise: bb5]; + _10 = const 0_isize; -+ switchInt(const 0_isize) -> [0: bb2, 1: bb4, otherwise: bb3]; ++ switchInt(const 0_isize) -> [0: bb2, 1: bb3, otherwise: bb5]; } bb1: { @@ -64,10 +64,6 @@ } bb3: { - unreachable; - } - - bb4: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}; StorageDead(_10); @@ -77,12 +73,16 @@ StorageLive(_5); StorageLive(_6); _9 = const _; -- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb5, unwind continue]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb5, unwind continue]; +- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind continue]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb4, unwind continue]; + } + + bb4: { + _5 = Result::, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; } bb5: { - _5 = Result::, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; + unreachable; } } + diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff index e655af559a18..a255b15920cb 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff @@ -56,9 +56,9 @@ + _2 = const Option::::None; StorageLive(_10); - _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb1, 1: bb3, otherwise: bb2]; +- switchInt(move _10) -> [0: bb1, 1: bb2, otherwise: bb6]; + _10 = const 0_isize; -+ switchInt(const 0_isize) -> [0: bb1, 1: bb3, otherwise: bb2]; ++ switchInt(const 0_isize) -> [0: bb1, 1: bb2, otherwise: bb6]; } bb1: { @@ -66,10 +66,6 @@ } bb2: { - unreachable; - } - - bb3: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}; StorageDead(_10); @@ -79,18 +75,18 @@ StorageLive(_5); StorageLive(_6); _9 = const _; -- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind unreachable]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind unreachable]; +- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb3, unwind unreachable]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb3, unwind unreachable]; } - bb4: { + bb3: { StorageLive(_12); StorageLive(_15); _12 = discriminant(_6); - switchInt(move _12) -> [0: bb6, 1: bb5, otherwise: bb2]; + switchInt(move _12) -> [0: bb5, 1: bb4, otherwise: bb6]; } - bb5: { + bb4: { _15 = const "called `Result::unwrap()` on an `Err` value"; StorageLive(_16); StorageLive(_17); @@ -100,7 +96,7 @@ _14 = result::unwrap_failed(move _15, move _16) -> unwind unreachable; } - bb6: { + bb5: { _5 = move ((_6 as Ok).0: std::ptr::NonNull<[u8]>); StorageDead(_15); StorageDead(_12); @@ -115,6 +111,10 @@ StorageDead(_3); return; } + + bb6: { + unreachable; + } } + + ALLOC0 (size: 16, align: 8) { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff index a6658713a026..192ffea25915 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff @@ -41,9 +41,9 @@ + _2 = const Option::::None; StorageLive(_10); - _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb2, 1: bb4, otherwise: bb3]; +- switchInt(move _10) -> [0: bb2, 1: bb3, otherwise: bb5]; + _10 = const 0_isize; -+ switchInt(const 0_isize) -> [0: bb2, 1: bb4, otherwise: bb3]; ++ switchInt(const 0_isize) -> [0: bb2, 1: bb3, otherwise: bb5]; } bb1: { @@ -64,10 +64,6 @@ } bb3: { - unreachable; - } - - bb4: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}; StorageDead(_10); @@ -77,12 +73,16 @@ StorageLive(_5); StorageLive(_6); _9 = const _; -- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb5, unwind continue]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb5, unwind continue]; +- _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind continue]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind continue]; + } + + bb4: { + _5 = Result::, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; } bb5: { - _5 = Result::, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; + unreachable; } } + diff --git a/tests/mir-opt/remove_never_const.rs b/tests/mir-opt/remove_never_const.rs index c144edaffafb..81562058d808 100644 --- a/tests/mir-opt/remove_never_const.rs +++ b/tests/mir-opt/remove_never_const.rs @@ -3,9 +3,6 @@ // consts in codegen. We also have tests for this that catches the error, see // tests/ui/consts/const-eval/index-out-of-bounds-never-type.rs. -// Force generation of optimized mir for functions that do not reach codegen. -// compile-flags: --emit mir,link - #![feature(never_type)] struct PrintName(T); diff --git a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff index d287b20c4ead..a12db0a730c5 100644 --- a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff +++ b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff @@ -52,7 +52,7 @@ StorageLive(_10); StorageLive(_11); _9 = discriminant(_1); - switchInt(move _9) -> [0: bb6, 1: bb5, otherwise: bb2]; + switchInt(move _9) -> [0: bb5, 1: bb4, otherwise: bb6]; } bb1: { @@ -63,10 +63,6 @@ } bb2: { - unreachable; - } - - bb3: { _6 = ((_3 as Break).0: std::result::Result); _13 = ((_6 as Err).0: i32); _0 = Result::::Err(move _13); @@ -74,27 +70,31 @@ return; } - bb4: { + bb3: { StorageDead(_11); StorageDead(_10); StorageDead(_9); _5 = discriminant(_3); - switchInt(move _5) -> [0: bb1, 1: bb3, otherwise: bb2]; + switchInt(move _5) -> [0: bb1, 1: bb2, otherwise: bb6]; } - bb5: { + bb4: { _11 = ((_1 as Err).0: i32); StorageLive(_12); _12 = Result::::Err(move _11); _3 = ControlFlow::, i32>::Break(move _12); StorageDead(_12); - goto -> bb4; + goto -> bb3; + } + + bb5: { + _10 = ((_1 as Ok).0: i32); + _3 = ControlFlow::, i32>::Continue(move _10); + goto -> bb3; } bb6: { - _10 = ((_1 as Ok).0: i32); - _3 = ControlFlow::, i32>::Continue(move _10); - goto -> bb4; + unreachable; } } diff --git a/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff b/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff index e2bf33f7fbcc..80f40b86919e 100644 --- a/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff +++ b/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff @@ -30,47 +30,47 @@ bb0: { StorageLive(_2); _3 = discriminant(_1); - switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; + switchInt(move _3) -> [0: bb2, 1: bb1, otherwise: bb7]; } bb1: { _6 = ((_1 as Err).0: usize); _2 = ControlFlow::::Break(_6); - goto -> bb4; + goto -> bb3; } bb2: { - unreachable; + _4 = ((_1 as Ok).0: i32); + _2 = ControlFlow::::Continue(_4); + goto -> bb3; } bb3: { - _4 = ((_1 as Ok).0: i32); - _2 = ControlFlow::::Continue(_4); - goto -> bb4; + _8 = discriminant(_2); + switchInt(move _8) -> [0: bb5, 1: bb4, otherwise: bb7]; } bb4: { - _8 = discriminant(_2); - switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb2]; - } - - bb5: { StorageLive(_11); _11 = ((_2 as Break).0: usize); _0 = Option::::None; StorageDead(_11); - goto -> bb7; + goto -> bb6; + } + + bb5: { + _9 = ((_2 as Continue).0: i32); + _0 = Option::::Some(_9); + goto -> bb6; } bb6: { - _9 = ((_2 as Continue).0: i32); - _0 = Option::::Some(_9); - goto -> bb7; - } - - bb7: { StorageDead(_2); return; } + + bb7: { + unreachable; + } } diff --git a/tests/mir-opt/set_no_discriminant.f.JumpThreading.diff b/tests/mir-opt/set_no_discriminant.f.JumpThreading.diff new file mode 100644 index 000000000000..bc28e81c9a88 --- /dev/null +++ b/tests/mir-opt/set_no_discriminant.f.JumpThreading.diff @@ -0,0 +1,26 @@ +- // MIR for `f` before JumpThreading ++ // MIR for `f` after JumpThreading + + fn f() -> usize { + let mut _0: usize; + let mut _1: isize; + let mut _2: E; + + bb0: { + _2 = E::::A; + discriminant(_2) = 1; + _1 = discriminant(_2); + switchInt(_1) -> [0: bb1, otherwise: bb2]; + } + + bb1: { + _0 = const 0_usize; + return; + } + + bb2: { + _0 = const 1_usize; + return; + } + } + diff --git a/tests/mir-opt/set_no_discriminant.generic.JumpThreading.diff b/tests/mir-opt/set_no_discriminant.generic.JumpThreading.diff new file mode 100644 index 000000000000..78bfeef3c649 --- /dev/null +++ b/tests/mir-opt/set_no_discriminant.generic.JumpThreading.diff @@ -0,0 +1,26 @@ +- // MIR for `generic` before JumpThreading ++ // MIR for `generic` after JumpThreading + + fn generic() -> usize { + let mut _0: usize; + let mut _1: isize; + let mut _2: E; + + bb0: { + _2 = E::::A; + discriminant(_2) = 1; + _1 = discriminant(_2); + switchInt(_1) -> [0: bb1, otherwise: bb2]; + } + + bb1: { + _0 = const 0_usize; + return; + } + + bb2: { + _0 = const 1_usize; + return; + } + } + diff --git a/tests/mir-opt/set_no_discriminant.rs b/tests/mir-opt/set_no_discriminant.rs new file mode 100644 index 000000000000..8ffb9a2910ab --- /dev/null +++ b/tests/mir-opt/set_no_discriminant.rs @@ -0,0 +1,78 @@ +// `SetDiscriminant` does not actually write anything if the chosen variant is the untagged variant +// of a niche encoding. Verify that we do not thread over this case. +// unit-test: JumpThreading + +#![feature(custom_mir)] +#![feature(core_intrinsics)] + +use std::intrinsics::mir::*; + +enum E { + A, + B(T), +} + +// EMIT_MIR set_no_discriminant.f.JumpThreading.diff +#[custom_mir(dialect = "runtime")] +pub fn f() -> usize { + // CHECK-LABEL: fn f( + // CHECK-NOT: goto + // CHECK: switchInt( + // CHECK-NOT: goto + mir!( + let a: isize; + let e: E; + { + e = E::A; + SetDiscriminant(e, 1); + a = Discriminant(e); + match a { + 0 => bb0, + _ => bb1, + } + } + bb0 = { + RET = 0; + Return() + } + bb1 = { + RET = 1; + Return() + } + ) +} + +// EMIT_MIR set_no_discriminant.generic.JumpThreading.diff +#[custom_mir(dialect = "runtime")] +pub fn generic() -> usize { + // CHECK-LABEL: fn generic( + // CHECK-NOT: goto + // CHECK: switchInt( + // CHECK-NOT: goto + mir!( + let a: isize; + let e: E; + { + e = E::A; + SetDiscriminant(e, 1); + a = Discriminant(e); + match a { + 0 => bb0, + _ => bb1, + } + } + bb0 = { + RET = 0; + Return() + } + bb1 = { + RET = 1; + Return() + } + ) +} + +fn main() { + assert_eq!(f(), 0); + assert_eq!(generic::(), 0); +} diff --git a/tests/run-make/raw-dylib-c/Makefile b/tests/run-make/raw-dylib-c/Makefile index 06e7935c0264..af5c4a6edd7b 100644 --- a/tests/run-make/raw-dylib-c/Makefile +++ b/tests/run-make/raw-dylib-c/Makefile @@ -17,7 +17,7 @@ else $(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll $(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll endif - "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt + "$(TMPDIR)"/driver | tr -d '\r' > "$(TMPDIR)"/output.txt "$(TMPDIR)"/raw_dylib_test_bin > "$(TMPDIR)"/output_bin.txt ifdef RUSTC_BLESS_TEST diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/Makefile b/tests/run-make/raw-dylib-inline-cross-dylib/Makefile index 195b5fda56fd..6b44b40e253e 100644 --- a/tests/run-make/raw-dylib-inline-cross-dylib/Makefile +++ b/tests/run-make/raw-dylib-inline-cross-dylib/Makefile @@ -26,5 +26,5 @@ else $(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll $(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll endif - $(call RUN,driver) > "$(TMPDIR)"/output.txt + $(call RUN,driver) | tr -d '\r' > "$(TMPDIR)"/output.txt $(RUSTC_TEST_OP) "$(TMPDIR)"/output.txt output.txt diff --git a/tests/run-make/raw-dylib-link-ordinal/Makefile b/tests/run-make/raw-dylib-link-ordinal/Makefile index 49e959cdb5b8..3cf1300c243a 100644 --- a/tests/run-make/raw-dylib-link-ordinal/Makefile +++ b/tests/run-make/raw-dylib-link-ordinal/Makefile @@ -13,5 +13,5 @@ ifdef IS_MSVC else $(CC) "$(TMPDIR)"/exporter.obj exporter.def -shared -o "$(TMPDIR)"/exporter.dll endif - "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt + "$(TMPDIR)"/driver | tr -d '\r' > "$(TMPDIR)"/output.txt $(RUSTC_TEST_OP) "$(TMPDIR)"/output.txt output.txt diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js index f9f9c4f4de8c..16d171260dad 100644 --- a/tests/rustdoc-js-std/parser-errors.js +++ b/tests/rustdoc-js-std/parser-errors.js @@ -24,7 +24,7 @@ const PARSED = [ original: "-> *", returned: [], userQuery: "-> *", - error: "Unexpected `*`", + error: "Unexpected `*` after ` `", }, { query: 'a<"P">', @@ -107,15 +107,6 @@ const PARSED = [ userQuery: "a<::a>", error: "Unexpected `::`: paths cannot start with `::`", }, - { - query: "((a))", - elems: [], - foundElems: 0, - original: "((a))", - returned: [], - userQuery: "((a))", - error: "Unexpected `(`", - }, { query: "(p -> p", elems: [], @@ -123,7 +114,7 @@ const PARSED = [ original: "(p -> p", returned: [], userQuery: "(p -> p", - error: "Unexpected `(`", + error: "Unexpected `-` after `(`", }, { query: "::a::b", @@ -204,7 +195,7 @@ const PARSED = [ original: "a (b:", returned: [], userQuery: "a (b:", - error: "Unexpected `(`", + error: "Expected `,`, `:` or `->`, found `(`", }, { query: "_:", @@ -249,7 +240,7 @@ const PARSED = [ original: "ab'", returned: [], userQuery: "ab'", - error: "Unexpected `'`", + error: "Unexpected `'` after `b`", }, { query: "a->", diff --git a/tests/rustdoc-js-std/parser-slice-array.js b/tests/rustdoc-js-std/parser-slice-array.js index 239391bed420..1de52af94e6b 100644 --- a/tests/rustdoc-js-std/parser-slice-array.js +++ b/tests/rustdoc-js-std/parser-slice-array.js @@ -266,6 +266,24 @@ const PARSED = [ userQuery: "]", error: "Unexpected `]`", }, + { + query: '[a', + elems: [], + foundElems: 0, + original: "[a", + returned: [], + userQuery: "[a", + error: "Unclosed `[`", + }, + { + query: 'a]', + elems: [], + foundElems: 0, + original: "a]", + returned: [], + userQuery: "a]", + error: "Unexpected `]` after `>`", + }, { query: 'primitive:[u8]', elems: [ diff --git a/tests/rustdoc-js-std/parser-tuple.js b/tests/rustdoc-js-std/parser-tuple.js new file mode 100644 index 000000000000..eb16289d3c05 --- /dev/null +++ b/tests/rustdoc-js-std/parser-tuple.js @@ -0,0 +1,365 @@ +const PARSED = [ + { + query: '(((D, ()))', + elems: [], + foundElems: 0, + original: '(((D, ()))', + returned: [], + userQuery: '(((d, ()))', + error: 'Unclosed `(`', + }, + { + query: '(((D, ())))', + elems: [ + { + name: "()", + fullPath: ["()"], + pathWithoutLast: [], + pathLast: "()", + generics: [ + { + name: "d", + fullPath: ["d"], + pathWithoutLast: [], + pathLast: "d", + generics: [], + typeFilter: -1, + }, + { + name: "()", + fullPath: ["()"], + pathWithoutLast: [], + pathLast: "()", + generics: [], + typeFilter: 1, + }, + ], + typeFilter: 1, + } + ], + foundElems: 1, + original: '(((D, ())))', + returned: [], + userQuery: '(((d, ())))', + error: null, + }, + { + query: '(),u8', + elems: [ + { + name: "()", + fullPath: ["()"], + pathWithoutLast: [], + pathLast: "()", + generics: [], + typeFilter: 1, + }, + { + name: "u8", + fullPath: ["u8"], + pathWithoutLast: [], + pathLast: "u8", + generics: [], + typeFilter: -1, + }, + ], + foundElems: 2, + original: "(),u8", + returned: [], + userQuery: "(),u8", + error: null, + }, + // Parens act as grouping operators when: + // - there's no commas directly nested within + // - there's at least two child types (zero means unit) + // - it's not tagged with a type filter + // Otherwise, they represent unit and/or tuple. To search for + // unit or tuple specifically, use `primitive:unit` or `primitive:tuple<...>`. + { + query: '(u8)', + elems: [ + { + name: "u8", + fullPath: ["u8"], + pathWithoutLast: [], + pathLast: "u8", + generics: [], + typeFilter: -1, + }, + ], + foundElems: 1, + original: "(u8)", + returned: [], + userQuery: "(u8)", + error: null, + }, + { + query: '(u8,)', + elems: [ + { + name: "()", + fullPath: ["()"], + pathWithoutLast: [], + pathLast: "()", + generics: [ + { + name: "u8", + fullPath: ["u8"], + pathWithoutLast: [], + pathLast: "u8", + generics: [], + typeFilter: -1, + }, + ], + typeFilter: 1, + }, + ], + foundElems: 1, + original: "(u8,)", + returned: [], + userQuery: "(u8,)", + error: null, + }, + { + query: '(,u8)', + elems: [ + { + name: "()", + fullPath: ["()"], + pathWithoutLast: [], + pathLast: "()", + generics: [ + { + name: "u8", + fullPath: ["u8"], + pathWithoutLast: [], + pathLast: "u8", + generics: [], + typeFilter: -1, + }, + ], + typeFilter: 1, + }, + ], + foundElems: 1, + original: "(,u8)", + returned: [], + userQuery: "(,u8)", + error: null, + }, + { + query: 'primitive:(u8)', + elems: [ + { + name: "()", + fullPath: ["()"], + pathWithoutLast: [], + pathLast: "()", + generics: [ + { + name: "u8", + fullPath: ["u8"], + pathWithoutLast: [], + pathLast: "u8", + generics: [], + typeFilter: -1, + }, + ], + typeFilter: 1, + }, + ], + foundElems: 1, + original: "primitive:(u8)", + returned: [], + userQuery: "primitive:(u8)", + error: null, + }, + { + query: '(primitive:u8)', + elems: [ + { + name: "u8", + fullPath: ["u8"], + pathWithoutLast: [], + pathLast: "u8", + generics: [], + typeFilter: 1, + }, + ], + foundElems: 1, + original: "(primitive:u8)", + returned: [], + userQuery: "(primitive:u8)", + error: null, + }, + { + query: '(u8,u8)', + elems: [ + { + name: "()", + fullPath: ["()"], + pathWithoutLast: [], + pathLast: "()", + generics: [ + { + name: "u8", + fullPath: ["u8"], + pathWithoutLast: [], + pathLast: "u8", + generics: [], + typeFilter: -1, + }, + { + name: "u8", + fullPath: ["u8"], + pathWithoutLast: [], + pathLast: "u8", + generics: [], + typeFilter: -1, + }, + ], + typeFilter: 1, + }, + ], + foundElems: 1, + original: "(u8,u8)", + returned: [], + userQuery: "(u8,u8)", + error: null, + }, + { + query: '(u8)', + elems: [ + { + name: "u8", + fullPath: ["u8"], + pathWithoutLast: [], + pathLast: "u8", + generics: [ + { + name: "u8", + fullPath: ["u8"], + pathWithoutLast: [], + pathLast: "u8", + generics: [], + typeFilter: -1, + }, + ], + typeFilter: -1, + }, + ], + foundElems: 1, + original: "(u8)", + returned: [], + userQuery: "(u8)", + error: null, + }, + { + query: '()', + elems: [ + { + name: "()", + fullPath: ["()"], + pathWithoutLast: [], + pathLast: "()", + generics: [], + typeFilter: 1, + }, + ], + foundElems: 1, + original: "()", + returned: [], + userQuery: "()", + error: null, + }, + { + query: '(>', + elems: [], + foundElems: 0, + original: "(>", + returned: [], + userQuery: "(>", + error: "Unexpected `>` after `(`", + }, + { + query: '(<', + elems: [], + foundElems: 0, + original: "(<", + returned: [], + userQuery: "(<", + error: "Found generics without a path", + }, + { + query: '(a>', + elems: [], + foundElems: 0, + original: "(a>", + returned: [], + userQuery: "(a>", + error: "Unexpected `>` after `(`", + }, + { + query: '(a<', + elems: [], + foundElems: 0, + original: "(a<", + returned: [], + userQuery: "(a<", + error: "Unclosed `<`", + }, + { + query: '(a', + elems: [], + foundElems: 0, + original: "(a", + returned: [], + userQuery: "(a", + error: "Unclosed `(`", + }, + { + query: '(', + elems: [], + foundElems: 0, + original: "(", + returned: [], + userQuery: "(", + error: "Unclosed `(`", + }, + { + query: ')', + elems: [], + foundElems: 0, + original: ")", + returned: [], + userQuery: ")", + error: "Unexpected `)`", + }, + { + query: '(a', + elems: [], + foundElems: 0, + original: "(a", + returned: [], + userQuery: "(a", + error: "Unclosed `(`", + }, + { + query: 'a)', + elems: [], + foundElems: 0, + original: "a)", + returned: [], + userQuery: "a)", + error: "Unexpected `)` after `>`", + }, + { + query: 'macro:(u8)', + elems: [], + foundElems: 0, + original: "macro:(u8)", + returned: [], + userQuery: "macro:(u8)", + error: "Invalid search type: primitive `()` and `macro` both specified", + }, +]; diff --git a/tests/rustdoc-js-std/parser-weird-queries.js b/tests/rustdoc-js-std/parser-weird-queries.js index ba68c9717c51..26b8c32d6805 100644 --- a/tests/rustdoc-js-std/parser-weird-queries.js +++ b/tests/rustdoc-js-std/parser-weird-queries.js @@ -44,7 +44,7 @@ const PARSED = [ original: "a,b(c)", returned: [], userQuery: "a,b(c)", - error: "Unexpected `(`", + error: "Expected `,`, `:` or `->`, found `(`", }, { query: 'aaa,a', diff --git a/tests/rustdoc-js/tuple-unit.js b/tests/rustdoc-js/tuple-unit.js new file mode 100644 index 000000000000..d24a3da328c5 --- /dev/null +++ b/tests/rustdoc-js/tuple-unit.js @@ -0,0 +1,80 @@ +// exact-check + +const EXPECTED = [ + { + 'query': '()', + 'returned': [ + { 'path': 'tuple_unit', 'name': 'side_effect' }, + { 'path': 'tuple_unit', 'name': 'one' }, + { 'path': 'tuple_unit', 'name': 'two' }, + { 'path': 'tuple_unit', 'name': 'nest' }, + ], + 'in_args': [], + }, + { + 'query': 'primitive:unit', + 'returned': [ + { 'path': 'tuple_unit', 'name': 'side_effect' }, + ], + 'in_args': [], + }, + { + 'query': 'primitive:tuple', + 'returned': [ + { 'path': 'tuple_unit', 'name': 'one' }, + { 'path': 'tuple_unit', 'name': 'two' }, + { 'path': 'tuple_unit', 'name': 'nest' }, + ], + 'in_args': [], + }, + { + 'query': '(P)', + 'returned': [ + { 'path': 'tuple_unit', 'name': 'not_tuple' }, + { 'path': 'tuple_unit', 'name': 'one' }, + { 'path': 'tuple_unit', 'name': 'two' }, + ], + 'in_args': [], + }, + { + 'query': '(P,)', + 'returned': [ + { 'path': 'tuple_unit', 'name': 'one' }, + { 'path': 'tuple_unit', 'name': 'two' }, + ], + 'in_args': [], + }, + { + 'query': '(P, P)', + 'returned': [ + { 'path': 'tuple_unit', 'name': 'two' }, + ], + 'in_args': [], + }, + { + 'query': '(P, ())', + 'returned': [], + 'in_args': [], + }, + { + 'query': '(Q, ())', + 'returned': [ + { 'path': 'tuple_unit', 'name': 'nest' }, + ], + 'in_args': [], + }, + { + 'query': '(R)', + 'returned': [ + { 'path': 'tuple_unit', 'name': 'nest' }, + ], + 'in_args': [], + }, + { + 'query': '(u32)', + 'returned': [ + { 'path': 'tuple_unit', 'name': 'nest' }, + ], + 'in_args': [], + }, +]; diff --git a/tests/rustdoc-js/tuple-unit.rs b/tests/rustdoc-js/tuple-unit.rs new file mode 100644 index 000000000000..93f9a671cbc3 --- /dev/null +++ b/tests/rustdoc-js/tuple-unit.rs @@ -0,0 +1,18 @@ +pub struct P; +pub struct Q; +pub struct R(T); + +// Checks that tuple and unit both work +pub fn side_effect() { } + +// Check a non-tuple +pub fn not_tuple() -> P { loop {} } + +// Check a 1-tuple +pub fn one() -> (P,) { loop {} } + +// Check a 2-tuple +pub fn two() -> (P,P) { loop {} } + +// Check a nested tuple +pub fn nest() -> (Q, R<(u32,)>) { loop {} } diff --git a/tests/rustdoc/inline_cross/auxiliary/default-generic-args.rs b/tests/rustdoc/inline_cross/auxiliary/default-generic-args.rs index 1e31f18927e9..c2c94817fad3 100644 --- a/tests/rustdoc/inline_cross/auxiliary/default-generic-args.rs +++ b/tests/rustdoc/inline_cross/auxiliary/default-generic-args.rs @@ -40,6 +40,11 @@ pub struct Multi(A, B); pub type M0 = Multi; -pub trait Trait<'a, T = &'a ()> {} +pub trait Trait0<'a, T = &'a ()> {} +pub type D0 = dyn for<'a> Trait0<'a>; -pub type F = dyn for<'a> Trait<'a>; +// Regression test for issue #119529. +pub trait Trait1 {} +pub type D1 = dyn Trait1; +pub type D2 = dyn Trait1<(), K>; +pub type D3 = dyn Trait1; diff --git a/tests/rustdoc/inline_cross/auxiliary/u_default_generic_args.rs b/tests/rustdoc/inline_cross/auxiliary/u_default_generic_args.rs new file mode 100644 index 000000000000..a742dd7d865f --- /dev/null +++ b/tests/rustdoc/inline_cross/auxiliary/u_default_generic_args.rs @@ -0,0 +1 @@ +pub use default_generic_args::*; diff --git a/tests/rustdoc/inline_cross/default-generic-args.rs b/tests/rustdoc/inline_cross/default-generic-args.rs index c9a87a199018..775bf0415328 100644 --- a/tests/rustdoc/inline_cross/default-generic-args.rs +++ b/tests/rustdoc/inline_cross/default-generic-args.rs @@ -79,15 +79,14 @@ pub use default_generic_args::P1; pub use default_generic_args::P2; // @has user/type.A0.html -// Ensure that we elide generic arguments that are alpha-equivalent to their respective -// generic parameter (modulo substs) (#1): -// @has - '//*[@class="rust item-decl"]//code' "Alpha" +// @has - '//*[@class="rust item-decl"]//code' "Alpha;" pub use default_generic_args::A0; // @has user/type.A1.html -// Ensure that we elide generic arguments that are alpha-equivalent to their respective -// generic parameter (modulo substs) (#1): -// @has - '//*[@class="rust item-decl"]//code' "Alpha" +// Demonstrates that we currently don't elide generic arguments that are alpha-equivalent to their +// respective generic parameter (after instantiation) for perf reasons (it would require us to +// create an inference context). +// @has - '//*[@class="rust item-decl"]//code' "Alpha fn(_: &'arbitrary ())>" pub use default_generic_args::A1; // @has user/type.M0.html @@ -97,8 +96,19 @@ pub use default_generic_args::A1; // @has - '//*[@class="rust item-decl"]//code' "Multi" pub use default_generic_args::M0; -// @has user/type.F.html -// FIXME: Ideally, we would elide `&'a ()` but `'a` is an escaping bound var which we can't reason -// about at the moment since we don't keep track of bound vars. -// @has - '//*[@class="rust item-decl"]//code' "dyn for<'a> Trait<'a, &'a ()>" -pub use default_generic_args::F; +// @has user/type.D0.html +// @has - '//*[@class="rust item-decl"]//code' "dyn for<'a> Trait0<'a>" +pub use default_generic_args::D0; + +// Regression test for issue #119529. +// Check that we correctly elide def ty&const args inside trait object types. + +// @has user/type.D1.html +// @has - '//*[@class="rust item-decl"]//code' "dyn Trait1" +pub use default_generic_args::D1; +// @has user/type.D2.html +// @has - '//*[@class="rust item-decl"]//code' "dyn Trait1<(), K>" +pub use default_generic_args::D2; +// @has user/type.D3.html +// @has - '//*[@class="rust item-decl"]//code' "dyn Trait1;" +pub use default_generic_args::D3; diff --git a/tests/rustdoc/synthetic_auto/no-redundancy.rs b/tests/rustdoc/synthetic_auto/no-redundancy.rs index ea57d7388b85..fed9c9c7ba47 100644 --- a/tests/rustdoc/synthetic_auto/no-redundancy.rs +++ b/tests/rustdoc/synthetic_auto/no-redundancy.rs @@ -1,3 +1,6 @@ +// FIXME(fmease, #119216): Reenable this test! +// ignore-test + pub struct Inner { field: T, } diff --git a/tests/ui-fulldeps/deriving-global.rs b/tests/ui-fulldeps/deriving-global.rs index 214bb4368ffd..9c0fc13a5e2f 100644 --- a/tests/ui-fulldeps/deriving-global.rs +++ b/tests/ui-fulldeps/deriving-global.rs @@ -4,6 +4,7 @@ extern crate rustc_macros; extern crate rustc_serialize; +extern crate rustc_span; // Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta // files. diff --git a/tests/ui-fulldeps/deriving-hygiene.rs b/tests/ui-fulldeps/deriving-hygiene.rs index e1084a08fec9..48d3355b9d54 100644 --- a/tests/ui-fulldeps/deriving-hygiene.rs +++ b/tests/ui-fulldeps/deriving-hygiene.rs @@ -4,6 +4,7 @@ #![feature(rustc_private)] extern crate rustc_macros; extern crate rustc_serialize; +extern crate rustc_span; use rustc_macros::{Decodable, Encodable}; diff --git a/tests/ui-fulldeps/dropck-tarena-cycle-checked.rs b/tests/ui-fulldeps/dropck-tarena-cycle-checked.rs index 188da67295a1..cc97971a0ddb 100644 --- a/tests/ui-fulldeps/dropck-tarena-cycle-checked.rs +++ b/tests/ui-fulldeps/dropck-tarena-cycle-checked.rs @@ -1,5 +1,3 @@ -// ignore-stage1 - // Reject mixing cyclic structure and Drop when using TypedArena. // // (Compare against dropck-vec-cycle-checked.rs) diff --git a/tests/ui-fulldeps/dropck-tarena-cycle-checked.stderr b/tests/ui-fulldeps/dropck-tarena-cycle-checked.stderr index 2f5be3f7f559..f9ac36be60e7 100644 --- a/tests/ui-fulldeps/dropck-tarena-cycle-checked.stderr +++ b/tests/ui-fulldeps/dropck-tarena-cycle-checked.stderr @@ -1,5 +1,5 @@ error[E0597]: `arena` does not live long enough - --> $DIR/dropck-tarena-cycle-checked.rs:118:7 + --> $DIR/dropck-tarena-cycle-checked.rs:116:7 | LL | let arena = TypedArena::default(); | ----- binding `arena` declared here diff --git a/tests/ui-fulldeps/dropck-tarena-unsound-drop.rs b/tests/ui-fulldeps/dropck-tarena-unsound-drop.rs index 5f9a5fb76eb4..86485a9887fb 100644 --- a/tests/ui-fulldeps/dropck-tarena-unsound-drop.rs +++ b/tests/ui-fulldeps/dropck-tarena-unsound-drop.rs @@ -1,5 +1,3 @@ -// ignore-stage1 - // Check that an arena (TypedArena) cannot carry elements whose drop // methods might access borrowed data of lifetime that does not // strictly outlive the arena itself. diff --git a/tests/ui-fulldeps/dropck-tarena-unsound-drop.stderr b/tests/ui-fulldeps/dropck-tarena-unsound-drop.stderr index 8bb3911241d1..82aa339a83b9 100644 --- a/tests/ui-fulldeps/dropck-tarena-unsound-drop.stderr +++ b/tests/ui-fulldeps/dropck-tarena-unsound-drop.stderr @@ -1,5 +1,5 @@ error[E0597]: `arena` does not live long enough - --> $DIR/dropck-tarena-unsound-drop.rs:43:7 + --> $DIR/dropck-tarena-unsound-drop.rs:41:7 | LL | let arena: TypedArena = TypedArena::default(); | ----- binding `arena` declared here diff --git a/tests/ui-fulldeps/empty-struct-braces-derive.rs b/tests/ui-fulldeps/empty-struct-braces-derive.rs index 10e8beaa7b11..3637610af0d9 100644 --- a/tests/ui-fulldeps/empty-struct-braces-derive.rs +++ b/tests/ui-fulldeps/empty-struct-braces-derive.rs @@ -5,6 +5,7 @@ extern crate rustc_macros; extern crate rustc_serialize; +extern crate rustc_span; // Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta // files. diff --git a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs index 392199866654..39980ee7c672 100644 --- a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs +++ b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs @@ -1,6 +1,5 @@ // Test the `rustc::span_use_eq_ctxt` internal lint // compile-flags: -Z unstable-options -// ignore-stage1 #![feature(rustc_private)] #![deny(rustc::span_use_eq_ctxt)] diff --git a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr index fcf2565c8ab1..b52df0368b16 100644 --- a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr +++ b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr @@ -1,11 +1,11 @@ error: use `.eq_ctxt()` instead of `.ctxt() == .ctxt()` - --> $DIR/span_use_eq_ctxt.rs:13:5 + --> $DIR/span_use_eq_ctxt.rs:12:5 | LL | s.ctxt() == t.ctxt() | ^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/span_use_eq_ctxt.rs:6:9 + --> $DIR/span_use_eq_ctxt.rs:5:9 | LL | #![deny(rustc::span_use_eq_ctxt)] | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-fulldeps/pathless-extern-unstable.rs b/tests/ui-fulldeps/pathless-extern-unstable.rs index 50d157c5795e..7fba8343bc08 100644 --- a/tests/ui-fulldeps/pathless-extern-unstable.rs +++ b/tests/ui-fulldeps/pathless-extern-unstable.rs @@ -1,6 +1,5 @@ // edition:2018 // compile-flags:--extern rustc_middle -// ignore-stage1 // Test that `--extern rustc_middle` fails with `rustc_private`. diff --git a/tests/ui-fulldeps/pathless-extern-unstable.stderr b/tests/ui-fulldeps/pathless-extern-unstable.stderr index 840b95d755c6..cfd8669c45fe 100644 --- a/tests/ui-fulldeps/pathless-extern-unstable.stderr +++ b/tests/ui-fulldeps/pathless-extern-unstable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? - --> $DIR/pathless-extern-unstable.rs:7:9 + --> $DIR/pathless-extern-unstable.rs:6:9 | LL | pub use rustc_middle; | ^^^^^^^^^^^^ diff --git a/tests/ui-fulldeps/rustc_encodable_hygiene.rs b/tests/ui-fulldeps/rustc_encodable_hygiene.rs index 509a6b1d22ca..bec7930d4622 100644 --- a/tests/ui-fulldeps/rustc_encodable_hygiene.rs +++ b/tests/ui-fulldeps/rustc_encodable_hygiene.rs @@ -3,8 +3,8 @@ #![feature(rustc_private)] extern crate rustc_macros; -#[allow(dead_code)] extern crate rustc_serialize; +extern crate rustc_span; // Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta // files. diff --git a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs index 331483112611..a0a8114e0c5c 100644 --- a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs +++ b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs @@ -1,5 +1,4 @@ // rustc-env:CARGO_CRATE_NAME=rustc_dummy -// ignore-stage1 #![feature(rustc_private)] #![crate_type = "lib"] diff --git a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr index c752a5ee0575..4cdc24e6a6bc 100644 --- a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr +++ b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr @@ -1,5 +1,5 @@ error: diagnostic slug and crate name do not match - --> $DIR/enforce_slug_naming.rs:23:8 + --> $DIR/enforce_slug_naming.rs:22:8 | LL | #[diag(compiletest_example, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/statics/static-mut-foreign.rs b/tests/ui/abi/statics/static-mut-foreign.rs index ecd8ee94a01e..eb732e7c2c31 100644 --- a/tests/ui/abi/statics/static-mut-foreign.rs +++ b/tests/ui/abi/statics/static-mut-foreign.rs @@ -33,7 +33,9 @@ unsafe fn run() { rust_dbg_static_mut = -3; assert_eq!(rust_dbg_static_mut, -3); static_bound(&rust_dbg_static_mut); + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] static_bound_set(&mut rust_dbg_static_mut); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] } pub fn main() { diff --git a/tests/ui/abi/statics/static-mut-foreign.stderr b/tests/ui/abi/statics/static-mut-foreign.stderr new file mode 100644 index 000000000000..144ac056f87e --- /dev/null +++ b/tests/ui/abi/statics/static-mut-foreign.stderr @@ -0,0 +1,31 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/static-mut-foreign.rs:35:18 + | +LL | static_bound(&rust_dbg_static_mut); + | ^^^^^^^^^^^^^^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | static_bound(addr_of!(rust_dbg_static_mut)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: mutable reference of mutable static is discouraged + --> $DIR/static-mut-foreign.rs:37:22 + | +LL | static_bound_set(&mut rust_dbg_static_mut); + | ^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | static_bound_set(addr_of_mut!(rust_dbg_static_mut)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: 2 warnings emitted + diff --git a/tests/ui/anon-params/anon-params-edition-hygiene.rs b/tests/ui/anon-params/anon-params-edition-hygiene.rs index 6936205f8b96..0b69081d4eda 100644 --- a/tests/ui/anon-params/anon-params-edition-hygiene.rs +++ b/tests/ui/anon-params/anon-params-edition-hygiene.rs @@ -1,4 +1,3 @@ -// check-pass // edition:2018 // aux-build:anon-params-edition-hygiene.rs @@ -8,6 +7,8 @@ #[macro_use] extern crate anon_params_edition_hygiene; -generate_trait_2015!(u8); +generate_trait_2015_ident!(u8); +// FIXME: Edition hygiene doesn't work correctly with `tt`s in this case. +generate_trait_2015_tt!(u8); //~ ERROR expected one of `:`, `@`, or `|`, found `)` fn main() {} diff --git a/tests/ui/anon-params/anon-params-edition-hygiene.stderr b/tests/ui/anon-params/anon-params-edition-hygiene.stderr new file mode 100644 index 000000000000..373d7c6aebb5 --- /dev/null +++ b/tests/ui/anon-params/anon-params-edition-hygiene.stderr @@ -0,0 +1,23 @@ +error: expected one of `:`, `@`, or `|`, found `)` + --> $DIR/anon-params-edition-hygiene.rs:12:1 + | +LL | generate_trait_2015_tt!(u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected one of `:`, `@`, or `|` + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) + = note: this error originates in the macro `generate_trait_2015_tt` (in Nightly builds, run with -Z macro-backtrace for more info) +help: if this is a `self` type, give it a parameter name + | +LL | generate_trait_2015_tt!(self: u8); + | +++++ +help: if this is a parameter name, give it a type + | +LL | generate_trait_2015_tt!(u8: TypeName); + | ++++++++++ +help: if this is a type, explicitly ignore the parameter name + | +LL | generate_trait_2015_tt!(_: u8); + | ++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs b/tests/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs index aa4221becc24..283656552931 100644 --- a/tests/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs +++ b/tests/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs @@ -1,9 +1,18 @@ // edition:2015 #[macro_export] -macro_rules! generate_trait_2015 { +macro_rules! generate_trait_2015_ident { ($Type: ident) => { - trait Trait { + trait Trait1 { + fn method($Type) {} + } + }; +} + +#[macro_export] +macro_rules! generate_trait_2015_tt { + ($Type: tt) => { + trait Trait2 { fn method($Type) {} } }; diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/associated-consts/issue-105330.stderr index aeedf6b19497..e1461fec296e 100644 --- a/tests/ui/associated-consts/issue-105330.stderr +++ b/tests/ui/associated-consts/issue-105330.stderr @@ -33,11 +33,13 @@ LL | fn main>() { = note: see issue #92827 for more information = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in impl headers +error[E0562]: `impl Trait` is not allowed in impl headers --> $DIR/issue-105330.rs:6:27 | LL | impl TraitWAssocConst for impl Demo { | ^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0131]: `main` function is not allowed to have generic parameters --> $DIR/issue-105330.rs:15:8 diff --git a/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr index 2fceeb15ea98..3acec9c085a2 100644 --- a/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr +++ b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr @@ -13,7 +13,7 @@ LL | impl Windows { note: struct defined here, with 1 generic parameter: `T` --> $DIR/issue-109071.rs:5:8 | -LL | struct Windows {} +LL | struct Windows { t: T } | ^^^^^^^ - help: add missing generic argument | @@ -30,7 +30,7 @@ LL | type Item = &[T]; = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable error[E0223]: ambiguous associated type - --> $DIR/issue-109071.rs:15:22 + --> $DIR/issue-109071.rs:16:22 | LL | fn T() -> Option {} | ^^^^^^^^^^ diff --git a/tests/ui/associated-inherent-types/issue-109071.rs b/tests/ui/associated-inherent-types/issue-109071.rs index 951c708e3f95..a897aaebc58f 100644 --- a/tests/ui/associated-inherent-types/issue-109071.rs +++ b/tests/ui/associated-inherent-types/issue-109071.rs @@ -2,18 +2,20 @@ #![cfg_attr(with_gate, feature(inherent_associated_types))] #![cfg_attr(with_gate, allow(incomplete_features))] -struct Windows {} +struct Windows { t: T } impl Windows { //~ ERROR: missing generics for struct `Windows` type Item = &[T]; //~ ERROR: `&` without an explicit lifetime name cannot be used here //[no_gate]~^ ERROR: inherent associated types are unstable fn next() -> Option {} + //[with_gate]~^ ERROR type annotations needed } impl Windows { fn T() -> Option {} //[no_gate]~^ ERROR: ambiguous associated type + //[with_gate]~^^ ERROR type annotations needed } fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109071.with_gate.stderr b/tests/ui/associated-inherent-types/issue-109071.with_gate.stderr index a91bb7a5162e..d413c65dccb5 100644 --- a/tests/ui/associated-inherent-types/issue-109071.with_gate.stderr +++ b/tests/ui/associated-inherent-types/issue-109071.with_gate.stderr @@ -13,14 +13,26 @@ LL | impl Windows { note: struct defined here, with 1 generic parameter: `T` --> $DIR/issue-109071.rs:5:8 | -LL | struct Windows {} +LL | struct Windows { t: T } | ^^^^^^^ - help: add missing generic argument | LL | impl Windows { | +++ -error: aborting due to 2 previous errors +error[E0282]: type annotations needed + --> $DIR/issue-109071.rs:11:18 + | +LL | fn next() -> Option {} + | ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` -Some errors have detailed explanations: E0107, E0637. +error[E0282]: type annotations needed + --> $DIR/issue-109071.rs:16:15 + | +LL | fn T() -> Option {} + | ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0107, E0282, E0637. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/associated-inherent-types/issue-109299-1.rs b/tests/ui/associated-inherent-types/issue-109299-1.rs index 6f95273116b7..b86e2e31e064 100644 --- a/tests/ui/associated-inherent-types/issue-109299-1.rs +++ b/tests/ui/associated-inherent-types/issue-109299-1.rs @@ -8,5 +8,6 @@ impl Lexer { } type X = impl for Fn() -> Lexer::Cursor; //~ ERROR associated type `Cursor` not found for `Lexer` in the current scope +//~^ ERROR: unconstrained opaque type fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109299-1.stderr b/tests/ui/associated-inherent-types/issue-109299-1.stderr index c25ffb9d9c2a..5848fa4087da 100644 --- a/tests/ui/associated-inherent-types/issue-109299-1.stderr +++ b/tests/ui/associated-inherent-types/issue-109299-1.stderr @@ -10,6 +10,14 @@ LL | type X = impl for Fn() -> Lexer::Cursor; = note: the associated type was found for - `Lexer` -error: aborting due to 1 previous error +error: unconstrained opaque type + --> $DIR/issue-109299-1.rs:10:10 + | +LL | type X = impl for Fn() -> Lexer::Cursor; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `X` must be used in combination with a concrete type within the same module + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-inherent-types/issue-109768.rs b/tests/ui/associated-inherent-types/issue-109768.rs index a3ae2e2ab447..400f4f7de66f 100644 --- a/tests/ui/associated-inherent-types/issue-109768.rs +++ b/tests/ui/associated-inherent-types/issue-109768.rs @@ -8,5 +8,6 @@ impl Local { //~ ERROR missing generics for struct `Local` type AssocType3 = T; //~ ERROR inherent associated types are unstable const WRAPPED_ASSOC_3: Wrapper = Wrapper(); + //~^ ERROR: this struct takes 1 argument but 0 arguments were supplied } //~^ ERROR `main` function not found diff --git a/tests/ui/associated-inherent-types/issue-109768.stderr b/tests/ui/associated-inherent-types/issue-109768.stderr index 97706d4062a9..c489fd1ab9b0 100644 --- a/tests/ui/associated-inherent-types/issue-109768.stderr +++ b/tests/ui/associated-inherent-types/issue-109768.stderr @@ -1,5 +1,5 @@ error[E0601]: `main` function not found in crate `issue_109768` - --> $DIR/issue-109768.rs:11:2 + --> $DIR/issue-109768.rs:12:2 | LL | } | ^ consider adding a `main` function to `$DIR/issue-109768.rs` @@ -29,7 +29,23 @@ LL | type AssocType3 = T; = note: see issue #8995 for more information = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable -error: aborting due to 3 previous errors +error[E0061]: this struct takes 1 argument but 0 arguments were supplied + --> $DIR/issue-109768.rs:10:56 + | +LL | const WRAPPED_ASSOC_3: Wrapper = Wrapper(); + | ^^^^^^^-- an argument is missing + | +note: tuple struct defined here + --> $DIR/issue-109768.rs:3:8 + | +LL | struct Wrapper(T); + | ^^^^^^^ +help: provide the argument + | +LL | const WRAPPED_ASSOC_3: Wrapper = Wrapper(/* value */); + | ~~~~~~~~~~~~~ -Some errors have detailed explanations: E0107, E0601, E0658. -For more information about an error, try `rustc --explain E0107`. +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0061, E0107, E0601, E0658. +For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/associated-type-bounds/duplicate.rs b/tests/ui/associated-type-bounds/duplicate.rs index 5019804d4949..160b524c881c 100644 --- a/tests/ui/associated-type-bounds/duplicate.rs +++ b/tests/ui/associated-type-bounds/duplicate.rs @@ -134,14 +134,17 @@ where fn FRPIT1() -> impl Iterator { //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] iter::empty() + //~^ ERROR type annotations needed } fn FRPIT2() -> impl Iterator { //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] iter::empty() + //~^ ERROR type annotations needed } fn FRPIT3() -> impl Iterator { //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] iter::empty() + //~^ ERROR type annotations needed } fn FAPIT1(_: impl Iterator) {} //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] @@ -194,12 +197,15 @@ trait TRI3> {} trait TRS1: Iterator {} //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] +//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] trait TRS2: Iterator {} //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] +//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] trait TRS3: Iterator {} //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] +//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] trait TRW1 where T: Iterator, @@ -223,6 +229,7 @@ where Self: Iterator, //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] + //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] { } trait TRSW2 @@ -230,6 +237,7 @@ where Self: Iterator, //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] + //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] { } trait TRSW3 @@ -237,15 +245,19 @@ where Self: Iterator, //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] + //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] { } trait TRA1 { type A: Iterator; //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] + //~| ERROR `<::A as Iterator>::Item` cannot be sent between threads safely + //~| ERROR the trait bound `<::A as Iterator>::Item: Copy` is not satisfied } trait TRA2 { type A: Iterator; //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] + //~| ERROR the trait bound `<::A as Iterator>::Item: Copy` is not satisfied } trait TRA3 { type A: Iterator; diff --git a/tests/ui/associated-type-bounds/duplicate.stderr b/tests/ui/associated-type-bounds/duplicate.stderr index 38b812dfdd44..accb366dd155 100644 --- a/tests/ui/associated-type-bounds/duplicate.stderr +++ b/tests/ui/associated-type-bounds/duplicate.stderr @@ -7,7 +7,7 @@ LL | struct SI1> { | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:255:40 + --> $DIR/duplicate.rs:267:40 | LL | type TADyn1 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -15,7 +15,7 @@ LL | type TADyn1 = dyn Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:257:44 + --> $DIR/duplicate.rs:269:44 | LL | type TADyn2 = Box>; | ---------- ^^^^^^^^^^ re-bound here @@ -23,7 +23,7 @@ LL | type TADyn2 = Box>; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:259:43 + --> $DIR/duplicate.rs:271:43 | LL | type TADyn3 = dyn Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -223,7 +223,7 @@ LL | fn FRPIT1() -> impl Iterator { | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:138:42 + --> $DIR/duplicate.rs:139:42 | LL | fn FRPIT2() -> impl Iterator { | ---------- ^^^^^^^^^^ re-bound here @@ -231,7 +231,7 @@ LL | fn FRPIT2() -> impl Iterator { | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:142:45 + --> $DIR/duplicate.rs:144:45 | LL | fn FRPIT3() -> impl Iterator { | ------------- ^^^^^^^^^^^^^ re-bound here @@ -239,7 +239,7 @@ LL | fn FRPIT3() -> impl Iterator { | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:146:40 + --> $DIR/duplicate.rs:149:40 | LL | fn FAPIT1(_: impl Iterator) {} | ---------- ^^^^^^^^^^ re-bound here @@ -247,7 +247,7 @@ LL | fn FAPIT1(_: impl Iterator) {} | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:148:40 + --> $DIR/duplicate.rs:151:40 | LL | fn FAPIT2(_: impl Iterator) {} | ---------- ^^^^^^^^^^ re-bound here @@ -255,7 +255,7 @@ LL | fn FAPIT2(_: impl Iterator) {} | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:150:43 + --> $DIR/duplicate.rs:153:43 | LL | fn FAPIT3(_: impl Iterator) {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -263,7 +263,7 @@ LL | fn FAPIT3(_: impl Iterator) {} | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:153:35 + --> $DIR/duplicate.rs:156:35 | LL | type TAI1> = T; | ---------- ^^^^^^^^^^ re-bound here @@ -271,7 +271,7 @@ LL | type TAI1> = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:155:35 + --> $DIR/duplicate.rs:158:35 | LL | type TAI2> = T; | ---------- ^^^^^^^^^^ re-bound here @@ -279,7 +279,7 @@ LL | type TAI2> = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:157:38 + --> $DIR/duplicate.rs:160:38 | LL | type TAI3> = T; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -287,7 +287,7 @@ LL | type TAI3> = T; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:161:29 + --> $DIR/duplicate.rs:164:29 | LL | T: Iterator, | ---------- ^^^^^^^^^^ re-bound here @@ -295,7 +295,7 @@ LL | T: Iterator, | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:166:29 + --> $DIR/duplicate.rs:169:29 | LL | T: Iterator, | ---------- ^^^^^^^^^^ re-bound here @@ -303,7 +303,7 @@ LL | T: Iterator, | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:171:32 + --> $DIR/duplicate.rs:174:32 | LL | T: Iterator, | ------------- ^^^^^^^^^^^^^ re-bound here @@ -311,7 +311,7 @@ LL | T: Iterator, | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:175:36 + --> $DIR/duplicate.rs:178:36 | LL | type ETAI1> = impl Copy; | ---------- ^^^^^^^^^^ re-bound here @@ -319,7 +319,7 @@ LL | type ETAI1> = impl Copy; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:177:36 + --> $DIR/duplicate.rs:180:36 | LL | type ETAI2> = impl Copy; | ---------- ^^^^^^^^^^ re-bound here @@ -327,7 +327,7 @@ LL | type ETAI2> = impl Copy; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:179:39 + --> $DIR/duplicate.rs:182:39 | LL | type ETAI3> = impl Copy; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -335,7 +335,7 @@ LL | type ETAI3> = impl Copy; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:181:40 + --> $DIR/duplicate.rs:184:40 | LL | type ETAI4 = impl Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -343,7 +343,7 @@ LL | type ETAI4 = impl Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:183:40 + --> $DIR/duplicate.rs:186:40 | LL | type ETAI5 = impl Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -351,7 +351,7 @@ LL | type ETAI5 = impl Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:185:43 + --> $DIR/duplicate.rs:188:43 | LL | type ETAI6 = impl Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -359,7 +359,7 @@ LL | type ETAI6 = impl Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:188:36 + --> $DIR/duplicate.rs:191:36 | LL | trait TRI1> {} | ---------- ^^^^^^^^^^ re-bound here @@ -367,7 +367,7 @@ LL | trait TRI1> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:190:36 + --> $DIR/duplicate.rs:193:36 | LL | trait TRI2> {} | ---------- ^^^^^^^^^^ re-bound here @@ -375,7 +375,7 @@ LL | trait TRI2> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:192:39 + --> $DIR/duplicate.rs:195:39 | LL | trait TRI3> {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -383,7 +383,7 @@ LL | trait TRI3> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:194:34 + --> $DIR/duplicate.rs:197:34 | LL | trait TRS1: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -391,7 +391,7 @@ LL | trait TRS1: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:194:34 + --> $DIR/duplicate.rs:197:34 | LL | trait TRS1: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -401,7 +401,7 @@ LL | trait TRS1: Iterator {} = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:197:34 + --> $DIR/duplicate.rs:201:34 | LL | trait TRS2: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -409,7 +409,7 @@ LL | trait TRS2: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:197:34 + --> $DIR/duplicate.rs:201:34 | LL | trait TRS2: Iterator {} | ---------- ^^^^^^^^^^ re-bound here @@ -419,7 +419,7 @@ LL | trait TRS2: Iterator {} = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:200:37 + --> $DIR/duplicate.rs:205:37 | LL | trait TRS3: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -427,7 +427,7 @@ LL | trait TRS3: Iterator {} | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:200:37 + --> $DIR/duplicate.rs:205:37 | LL | trait TRS3: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -437,7 +437,7 @@ LL | trait TRS3: Iterator {} = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:205:29 + --> $DIR/duplicate.rs:211:29 | LL | T: Iterator, | ---------- ^^^^^^^^^^ re-bound here @@ -445,7 +445,7 @@ LL | T: Iterator, | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:211:29 + --> $DIR/duplicate.rs:217:29 | LL | T: Iterator, | ---------- ^^^^^^^^^^ re-bound here @@ -453,7 +453,7 @@ LL | T: Iterator, | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:217:32 + --> $DIR/duplicate.rs:223:32 | LL | T: Iterator, | ------------- ^^^^^^^^^^^^^ re-bound here @@ -461,7 +461,7 @@ LL | T: Iterator, | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:223:32 + --> $DIR/duplicate.rs:229:32 | LL | Self: Iterator, | ---------- ^^^^^^^^^^ re-bound here @@ -469,7 +469,7 @@ LL | Self: Iterator, | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:223:32 + --> $DIR/duplicate.rs:229:32 | LL | Self: Iterator, | ---------- ^^^^^^^^^^ re-bound here @@ -479,7 +479,7 @@ LL | Self: Iterator, = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:230:32 + --> $DIR/duplicate.rs:237:32 | LL | Self: Iterator, | ---------- ^^^^^^^^^^ re-bound here @@ -487,7 +487,7 @@ LL | Self: Iterator, | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:230:32 + --> $DIR/duplicate.rs:237:32 | LL | Self: Iterator, | ---------- ^^^^^^^^^^ re-bound here @@ -497,7 +497,7 @@ LL | Self: Iterator, = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:237:35 + --> $DIR/duplicate.rs:245:35 | LL | Self: Iterator, | ------------- ^^^^^^^^^^^^^ re-bound here @@ -505,7 +505,7 @@ LL | Self: Iterator, | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:237:35 + --> $DIR/duplicate.rs:245:35 | LL | Self: Iterator, | ------------- ^^^^^^^^^^^^^ re-bound here @@ -515,7 +515,7 @@ LL | Self: Iterator, = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:243:34 + --> $DIR/duplicate.rs:252:34 | LL | type A: Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -523,7 +523,7 @@ LL | type A: Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:247:34 + --> $DIR/duplicate.rs:258:34 | LL | type A: Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -531,13 +531,141 @@ LL | type A: Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:251:37 + --> $DIR/duplicate.rs:263:37 | LL | type A: Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: aborting due to 66 previous errors +error[E0282]: type annotations needed + --> $DIR/duplicate.rs:136:5 + | +LL | iter::empty() + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` + | +help: consider specifying the generic argument + | +LL | iter::empty::() + | +++++ -For more information about this error, try `rustc --explain E0719`. +error[E0282]: type annotations needed + --> $DIR/duplicate.rs:141:5 + | +LL | iter::empty() + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` + | +help: consider specifying the generic argument + | +LL | iter::empty::() + | +++++ + +error[E0282]: type annotations needed + --> $DIR/duplicate.rs:146:5 + | +LL | iter::empty() + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` + | +help: consider specifying the generic argument + | +LL | iter::empty::() + | +++++ + +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:197:34 + | +LL | trait TRS1: Iterator {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:201:34 + | +LL | trait TRS2: Iterator {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:205:37 + | +LL | trait TRS3: Iterator {} + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:229:32 + | +LL | Self: Iterator, + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:237:32 + | +LL | Self: Iterator, + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate.rs:245:35 + | +LL | Self: Iterator, + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: the trait bound `<::A as Iterator>::Item: Copy` is not satisfied + --> $DIR/duplicate.rs:252:28 + | +LL | type A: Iterator; + | ^^^^ the trait `Copy` is not implemented for `<::A as Iterator>::Item` + | +help: consider further restricting the associated type + | +LL | trait TRA1 where <::A as Iterator>::Item: Copy { + | +++++++++++++++++++++++++++++++++++++++++++++++++ + +error[E0277]: `<::A as Iterator>::Item` cannot be sent between threads safely + --> $DIR/duplicate.rs:252:40 + | +LL | type A: Iterator; + | ^^^^ `<::A as Iterator>::Item` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `<::A as Iterator>::Item` +help: consider further restricting the associated type + | +LL | trait TRA1 where <::A as Iterator>::Item: Send { + | +++++++++++++++++++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `<::A as Iterator>::Item: Copy` is not satisfied + --> $DIR/duplicate.rs:258:28 + | +LL | type A: Iterator; + | ^^^^ the trait `Copy` is not implemented for `<::A as Iterator>::Item` + | +help: consider further restricting the associated type + | +LL | trait TRA2 where <::A as Iterator>::Item: Copy { + | +++++++++++++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 78 previous errors + +Some errors have detailed explanations: E0277, E0282, E0719. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.rs b/tests/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.rs index c85d41c7f519..eaf3090bbd38 100644 --- a/tests/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.rs +++ b/tests/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.rs @@ -25,7 +25,7 @@ fn c(_: C::Color) where C : Vehicle, C : Box { //~^ ERROR ambiguous associated type `Color` in bounds of `C` } -struct D; +struct D(X); impl D where X : Vehicle { fn d(&self, _: X::Color) where X : Box { } //~^ ERROR ambiguous associated type `Color` in bounds of `X` diff --git a/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.rs b/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.rs index df19332b6458..b757521e0a45 100644 --- a/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.rs +++ b/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.rs @@ -20,7 +20,7 @@ fn dent(c: C, color: C::Color) { //~^ ERROR ambiguous associated type `Color` in bounds of `C` } -fn dent_object(c: dyn BoxCar) { +fn dent_object(c: &dyn BoxCar) { //~^ ERROR ambiguous associated type //~| ERROR the value of the associated types } @@ -29,7 +29,7 @@ fn paint(c: C, d: C::Color) { //~^ ERROR ambiguous associated type `Color` in bounds of `C` } -fn dent_object_2(c: dyn BoxCar) where ::Color = COLOR { +fn dent_object_2(c: &dyn BoxCar) where ::Color = COLOR { //~^ ERROR the value of the associated types //~| ERROR equality constraints are not yet supported in `where` clauses } diff --git a/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr b/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr index 66037054e064..a4874903285a 100644 --- a/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr +++ b/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr @@ -1,8 +1,8 @@ error: equality constraints are not yet supported in `where` clauses - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:46 + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:47 | -LL | fn dent_object_2(c: dyn BoxCar) where ::Color = COLOR { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported +LL | fn dent_object_2(c: &dyn BoxCar) where ::Color = COLOR { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported | = note: see issue #20041 for more information @@ -28,7 +28,7 @@ LL | fn dent(c: C, color: ::Color) { | ~~~~~~~~~~~~ error[E0222]: ambiguous associated type `Color` in bounds of `BoxCar` - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:37 + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:38 | LL | type Color; | ---------- ambiguous `Color` from `Vehicle` @@ -36,8 +36,8 @@ LL | type Color; LL | type Color; | ---------- ambiguous `Color` from `Box` ... -LL | fn dent_object(c: dyn BoxCar) { - | ^^^^^^^^^^^ ambiguous associated type `Color` +LL | fn dent_object(c: &dyn BoxCar) { + | ^^^^^^^^^^^ ambiguous associated type `Color` | = help: consider introducing a new type parameter `T` and adding `where` constraints: where @@ -46,7 +46,7 @@ LL | fn dent_object(c: dyn BoxCar) { T: Box::Color = COLOR error[E0191]: the value of the associated types `Color` in `Box`, `Color` in `Vehicle` must be specified - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:30 + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:31 | LL | type Color; | ---------- `Vehicle::Color` defined here @@ -54,8 +54,8 @@ LL | type Color; LL | type Color; | ---------- `Box::Color` defined here ... -LL | fn dent_object(c: dyn BoxCar) { - | ^^^^^^^^^^^^^^^^^^^ associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified +LL | fn dent_object(c: &dyn BoxCar) { + | ^^^^^^^^^^^^^^^^^^^ associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified | = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types @@ -81,7 +81,7 @@ LL | fn paint(c: C, d: ::Color) { | ~~~~~~~~~~~~ error[E0191]: the value of the associated types `Color` in `Box`, `Color` in `Vehicle` must be specified - --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:32 + --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:33 | LL | type Color; | ---------- `Vehicle::Color` defined here @@ -89,8 +89,8 @@ LL | type Color; LL | type Color; | ---------- `Box::Color` defined here ... -LL | fn dent_object_2(c: dyn BoxCar) where ::Color = COLOR { - | ^^^^^^ associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified +LL | fn dent_object_2(c: &dyn BoxCar) where ::Color = COLOR { + | ^^^^^^ associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified | = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types diff --git a/tests/ui/associated-types/issue-23595-1.rs b/tests/ui/associated-types/issue-23595-1.rs index 483c205f42d6..9222f5b66509 100644 --- a/tests/ui/associated-types/issue-23595-1.rs +++ b/tests/ui/associated-types/issue-23595-1.rs @@ -7,6 +7,7 @@ trait Hierarchy { type ChildKey; type Children = dyn Index; //~^ ERROR: the value of the associated types + //~| ERROR: the size for values of type fn data(&self) -> Option<(Self::Value, Self::Children)>; } diff --git a/tests/ui/associated-types/issue-23595-1.stderr b/tests/ui/associated-types/issue-23595-1.stderr index f9d58c23cbba..46906ab3fb7a 100644 --- a/tests/ui/associated-types/issue-23595-1.stderr +++ b/tests/ui/associated-types/issue-23595-1.stderr @@ -8,6 +8,20 @@ LL | type ChildKey; LL | type Children = dyn Index; | ------------- `Children` defined here ^^^^^^^^^ help: specify the associated types: `Hierarchy` -error: aborting due to 1 previous error +error[E0277]: the size for values of type `(dyn Index<::ChildKey, Output = (dyn Hierarchy + 'static)> + 'static)` cannot be known at compilation time + --> $DIR/issue-23595-1.rs:8:21 + | +LL | type Children = dyn Index; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Index<::ChildKey, Output = (dyn Hierarchy + 'static)> + 'static)` +note: required by a bound in `Hierarchy::Children` + --> $DIR/issue-23595-1.rs:8:5 + | +LL | type Children = dyn Index; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Hierarchy::Children` -For more information about this error, try `rustc --explain E0191`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0191, E0277. +For more information about an error, try `rustc --explain E0191`. diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.rs b/tests/ui/async-await/in-trait/async-recursive-generic.rs index c6031ce28d1d..33eb2b2de131 100644 --- a/tests/ui/async-await/in-trait/async-recursive-generic.rs +++ b/tests/ui/async-await/in-trait/async-recursive-generic.rs @@ -6,7 +6,7 @@ trait MyTrait { impl MyTrait for T where T: Copy { async fn foo_recursive(&self, n: usize) -> T { - //~^ ERROR recursion in an `async fn` requires boxing + //~^ ERROR recursion in an async fn requires boxing if n > 0 { self.foo_recursive(n - 1).await } else { diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.stderr b/tests/ui/async-await/in-trait/async-recursive-generic.stderr index 11489c18ad40..d085747bc4bf 100644 --- a/tests/ui/async-await/in-trait/async-recursive-generic.stderr +++ b/tests/ui/async-await/in-trait/async-recursive-generic.stderr @@ -1,11 +1,13 @@ -error[E0733]: recursion in an `async fn` requires boxing +error[E0733]: recursion in an async fn requires boxing --> $DIR/async-recursive-generic.rs:8:5 | LL | async fn foo_recursive(&self, n: usize) -> T { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | self.foo_recursive(n - 1).await + | ------------------------------- recursive call here | - = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` - = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future error: aborting due to 1 previous error diff --git a/tests/ui/async-await/in-trait/async-recursive.rs b/tests/ui/async-await/in-trait/async-recursive.rs index 09f1ffe499e3..2534c43413ed 100644 --- a/tests/ui/async-await/in-trait/async-recursive.rs +++ b/tests/ui/async-await/in-trait/async-recursive.rs @@ -6,7 +6,7 @@ trait MyTrait { impl MyTrait for i32 { async fn foo_recursive(&self, n: usize) -> i32 { - //~^ ERROR recursion in an `async fn` requires boxing + //~^ ERROR recursion in an async fn requires boxing if n > 0 { self.foo_recursive(n - 1).await } else { diff --git a/tests/ui/async-await/in-trait/async-recursive.stderr b/tests/ui/async-await/in-trait/async-recursive.stderr index 587962857269..25ebc6e77c4f 100644 --- a/tests/ui/async-await/in-trait/async-recursive.stderr +++ b/tests/ui/async-await/in-trait/async-recursive.stderr @@ -1,11 +1,13 @@ -error[E0733]: recursion in an `async fn` requires boxing +error[E0733]: recursion in an async fn requires boxing --> $DIR/async-recursive.rs:8:5 | LL | async fn foo_recursive(&self, n: usize) -> i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | self.foo_recursive(n - 1).await + | ------------------------------- recursive call here | - = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` - = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future error: aborting due to 1 previous error diff --git a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs index 8443cbcf4ac8..4b615343a05f 100644 --- a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs +++ b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs @@ -1,6 +1,7 @@ // edition: 2021 + +// Test doesn't fail until monomorphization time, unfortunately. // build-fail -//~^^ ERROR cycle detected when computing layout of fn main() { let _ = async { @@ -31,6 +32,7 @@ where C: First, { async fn second(self) { + //~^ ERROR recursion in an async fn requires boxing self.first().await.second().await; } } diff --git a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr index 8e573b512ad4..8126c6e13942 100644 --- a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr +++ b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr @@ -1,12 +1,11 @@ -error[E0391]: cycle detected when computing layout of `core::mem::maybe_uninit::MaybeUninit<{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}>` +error[E0733]: recursion in an async fn requires boxing + --> $DIR/indirect-recursion-issue-112047.rs:34:5 | - = note: ...which requires computing layout of `core::mem::manually_drop::ManuallyDrop<{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}>`... - = note: ...which requires computing layout of `{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}`... - = note: ...which requires computing layout of `core::mem::maybe_uninit::MaybeUninit<<::Second as Second>::{opaque#0}>`... - = note: ...which again requires computing layout of `core::mem::maybe_uninit::MaybeUninit<{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}>`, completing the cycle - = note: cycle used when computing layout of `{async block@$DIR/indirect-recursion-issue-112047.rs:6:13: 8:6}` - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +LL | async fn second(self) { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0391`. +For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/async-await/issues/issue-65159.rs b/tests/ui/async-await/issues/issue-65159.rs index 6e547508bd46..aed111e21442 100644 --- a/tests/ui/async-await/issues/issue-65159.rs +++ b/tests/ui/async-await/issues/issue-65159.rs @@ -5,7 +5,7 @@ async fn copy() -> Result<()> //~^ ERROR enum takes 2 generic arguments { - Ok(()) + Ok(()) //~ ERROR: type annotations needed } fn main() { } diff --git a/tests/ui/async-await/issues/issue-65159.stderr b/tests/ui/async-await/issues/issue-65159.stderr index 19512116a66c..77a0ea5027c1 100644 --- a/tests/ui/async-await/issues/issue-65159.stderr +++ b/tests/ui/async-await/issues/issue-65159.stderr @@ -11,6 +11,18 @@ help: add missing generic argument LL | async fn copy() -> Result<(), E> | +++ -error: aborting due to 1 previous error +error[E0282]: type annotations needed + --> $DIR/issue-65159.rs:8:5 + | +LL | Ok(()) + | ^^ cannot infer type of the type parameter `E` declared on the enum `Result` + | +help: consider specifying the generic arguments + | +LL | Ok::<(), E>(()) + | +++++++++ -For more information about this error, try `rustc --explain E0107`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0282. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs index bb2a61f03ce1..fedc814b0418 100644 --- a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs +++ b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs @@ -2,11 +2,11 @@ // Test that impl trait does not allow creating recursive types that are // otherwise forbidden when using `async` and `await`. -async fn rec_1() { //~ ERROR recursion in an `async fn` +async fn rec_1() { //~ ERROR recursion in an async fn rec_2().await; } -async fn rec_2() { //~ ERROR recursion in an `async fn` +async fn rec_2() { rec_1().await; } diff --git a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr index 9442609e8058..52fb41be1fbc 100644 --- a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr +++ b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr @@ -1,21 +1,20 @@ -error[E0733]: recursion in an `async fn` requires boxing +error[E0733]: recursion in an async fn requires boxing --> $DIR/mutually-recursive-async-impl-trait-type.rs:5:1 | LL | async fn rec_1() { - | ^^^^^^^^^^^^^^^^ recursive `async fn` + | ^^^^^^^^^^^^^^^^ +LL | rec_2().await; + | ------------- recursive call here | - = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` - = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion - -error[E0733]: recursion in an `async fn` requires boxing +note: which leads to this async fn --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:1 | LL | async fn rec_2() { - | ^^^^^^^^^^^^^^^^ recursive `async fn` - | - = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` - = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + | ^^^^^^^^^^^^^^^^ +LL | rec_1().await; + | ------------- ...leading to this recursive call + = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/async-await/pin-needed-to-poll-2.stderr b/tests/ui/async-await/pin-needed-to-poll-2.stderr index 9c1ad32cc2ce..8eb671531e79 100644 --- a/tests/ui/async-await/pin-needed-to-poll-2.stderr +++ b/tests/ui/async-await/pin-needed-to-poll-2.stderr @@ -13,7 +13,7 @@ note: required because it appears within the type `Sleep` | LL | struct Sleep(std::marker::PhantomPinned); | ^^^^^ -note: required by a bound in `Pin::

::new` +note: required by a bound in `Pin::::new` --> $SRC_DIR/core/src/pin.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/async-await/recursive-async-impl-trait-type.rs b/tests/ui/async-await/recursive-async-impl-trait-type.rs index edc4cb8ac5df..9351ee53f075 100644 --- a/tests/ui/async-await/recursive-async-impl-trait-type.rs +++ b/tests/ui/async-await/recursive-async-impl-trait-type.rs @@ -3,7 +3,7 @@ // otherwise forbidden when using `async` and `await`. async fn recursive_async_function() -> () { - //~^ ERROR recursion in an `async fn` requires boxing + //~^ ERROR recursion in an async fn requires boxing recursive_async_function().await; } diff --git a/tests/ui/async-await/recursive-async-impl-trait-type.stderr b/tests/ui/async-await/recursive-async-impl-trait-type.stderr index 969258f84ed6..5475469335fb 100644 --- a/tests/ui/async-await/recursive-async-impl-trait-type.stderr +++ b/tests/ui/async-await/recursive-async-impl-trait-type.stderr @@ -1,11 +1,13 @@ -error[E0733]: recursion in an `async fn` requires boxing +error[E0733]: recursion in an async fn requires boxing --> $DIR/recursive-async-impl-trait-type.rs:5:1 | LL | async fn recursive_async_function() -> () { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | recursive_async_function().await; + | -------------------------------- recursive call here | - = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` - = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future error: aborting due to 1 previous error diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs index 1b16a492a7a1..68a750778ada 100644 --- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs @@ -9,5 +9,6 @@ trait Super1<'a> { impl Super1<'_, bar(): Send> for () {} //~^ ERROR associated type bindings are not allowed here +//~| ERROR not all trait items implemented fn main() {} diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr index 4321d876e163..d925c7316b6e 100644 --- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr @@ -13,6 +13,16 @@ error[E0229]: associated type bindings are not allowed here LL | impl Super1<'_, bar(): Send> for () {} | ^^^^^^^^^^^ associated type not allowed here -error: aborting due to 1 previous error; 1 warning emitted +error[E0046]: not all trait items implemented, missing: `bar` + --> $DIR/rtn-in-impl-signature.rs:10:1 + | +LL | fn bar<'b>() -> bool; + | --------------------- `bar` from trait +... +LL | impl Super1<'_, bar(): Send> for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `bar` in implementation -For more information about this error, try `rustc --explain E0229`. +error: aborting due to 2 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0046, E0229. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr index 739c04a76730..e23fc459358b 100644 --- a/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr +++ b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr @@ -26,7 +26,7 @@ LL | let _ = #[track_caller] || { = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:28:17 + --> $DIR/async-closure-gate.rs:29:17 | LL | let _ = #[track_caller] || { | ^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | let _ = #[track_caller] || { = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:36:9 + --> $DIR/async-closure-gate.rs:37:9 | LL | #[track_caller] || { | ^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | #[track_caller] || { = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:45:13 + --> $DIR/async-closure-gate.rs:47:13 | LL | #[track_caller] || { | ^^^^^^^^^^^^^^^ @@ -52,6 +52,40 @@ LL | #[track_caller] || { = note: see issue #87417 for more information = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable -error: aborting due to 6 previous errors +error[E0308]: mismatched types + --> $DIR/async-closure-gate.rs:27:5 + | +LL | fn foo3() { + | - help: a return type might be missing here: `-> _` +LL | / async { +LL | | +LL | | let _ = #[track_caller] || { +LL | | +LL | | }; +LL | | } + | |_____^ expected `()`, found `async` block + | + = note: expected unit type `()` + found `async` block `{async block@$DIR/async-closure-gate.rs:27:5: 32:6}` -For more information about this error, try `rustc --explain E0658`. +error[E0308]: mismatched types + --> $DIR/async-closure-gate.rs:44:5 + | +LL | fn foo5() { + | - help: a return type might be missing here: `-> _` +LL | / async { +LL | | +LL | | let _ = || { +LL | | #[track_caller] || { +... | +LL | | }; +LL | | } + | |_____^ expected `()`, found `async` block + | + = note: expected unit type `()` + found `async` block `{async block@$DIR/async-closure-gate.rs:44:5: 51:6}` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr index 739c04a76730..e23fc459358b 100644 --- a/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr +++ b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr @@ -26,7 +26,7 @@ LL | let _ = #[track_caller] || { = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:28:17 + --> $DIR/async-closure-gate.rs:29:17 | LL | let _ = #[track_caller] || { | ^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | let _ = #[track_caller] || { = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:36:9 + --> $DIR/async-closure-gate.rs:37:9 | LL | #[track_caller] || { | ^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | #[track_caller] || { = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:45:13 + --> $DIR/async-closure-gate.rs:47:13 | LL | #[track_caller] || { | ^^^^^^^^^^^^^^^ @@ -52,6 +52,40 @@ LL | #[track_caller] || { = note: see issue #87417 for more information = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable -error: aborting due to 6 previous errors +error[E0308]: mismatched types + --> $DIR/async-closure-gate.rs:27:5 + | +LL | fn foo3() { + | - help: a return type might be missing here: `-> _` +LL | / async { +LL | | +LL | | let _ = #[track_caller] || { +LL | | +LL | | }; +LL | | } + | |_____^ expected `()`, found `async` block + | + = note: expected unit type `()` + found `async` block `{async block@$DIR/async-closure-gate.rs:27:5: 32:6}` -For more information about this error, try `rustc --explain E0658`. +error[E0308]: mismatched types + --> $DIR/async-closure-gate.rs:44:5 + | +LL | fn foo5() { + | - help: a return type might be missing here: `-> _` +LL | / async { +LL | | +LL | | let _ = || { +LL | | #[track_caller] || { +... | +LL | | }; +LL | | } + | |_____^ expected `()`, found `async` block + | + = note: expected unit type `()` + found `async` block `{async block@$DIR/async-closure-gate.rs:44:5: 51:6}` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/track-caller/async-closure-gate.rs b/tests/ui/async-await/track-caller/async-closure-gate.rs index 8d8d081aa90b..911934a22327 100644 --- a/tests/ui/async-await/track-caller/async-closure-gate.rs +++ b/tests/ui/async-await/track-caller/async-closure-gate.rs @@ -25,6 +25,7 @@ async fn foo2() { fn foo3() { async { + //~^ ERROR mismatched types let _ = #[track_caller] || { //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] }; @@ -41,6 +42,7 @@ async fn foo4() { fn foo5() { async { + //~^ ERROR mismatched types let _ = || { #[track_caller] || { //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] diff --git a/tests/ui/borrowck/borrowck-access-permissions.rs b/tests/ui/borrowck/borrowck-access-permissions.rs index 469ad508b0e7..1638644103ba 100644 --- a/tests/ui/borrowck/borrowck-access-permissions.rs +++ b/tests/ui/borrowck/borrowck-access-permissions.rs @@ -1,21 +1,27 @@ -static static_x : i32 = 1; -static mut static_x_mut : i32 = 1; +static static_x: i32 = 1; +static mut static_x_mut: i32 = 1; fn main() { let x = 1; let mut x_mut = 1; - { // borrow of local + { + // borrow of local let _y1 = &mut x; //~ ERROR [E0596] let _y2 = &mut x_mut; // No error } - { // borrow of static + { + // borrow of static let _y1 = &mut static_x; //~ ERROR [E0596] - unsafe { let _y2 = &mut static_x_mut; } // No error + unsafe { + let _y2 = &mut static_x_mut; + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + } } - { // borrow of deref to box + { + // borrow of deref to box let box_x = Box::new(1); let mut box_x_mut = Box::new(1); @@ -23,7 +29,8 @@ fn main() { let _y2 = &mut *box_x_mut; // No error } - { // borrow of deref to reference + { + // borrow of deref to reference let ref_x = &x; let ref_x_mut = &mut x_mut; @@ -31,9 +38,10 @@ fn main() { let _y2 = &mut *ref_x_mut; // No error } - { // borrow of deref to pointer - let ptr_x : *const _ = &x; - let ptr_mut_x : *mut _ = &mut x_mut; + { + // borrow of deref to pointer + let ptr_x: *const _ = &x; + let ptr_mut_x: *mut _ = &mut x_mut; unsafe { let _y1 = &mut *ptr_x; //~ ERROR [E0596] @@ -41,8 +49,12 @@ fn main() { } } - { // borrowing mutably through an immutable reference - struct Foo<'a> { f: &'a mut i32, g: &'a i32 }; + { + // borrowing mutably through an immutable reference + struct Foo<'a> { + f: &'a mut i32, + g: &'a i32, + }; let mut foo = Foo { f: &mut x_mut, g: &x }; let foo_ref = &foo; let _y = &mut *foo_ref.f; //~ ERROR [E0596] diff --git a/tests/ui/borrowck/borrowck-access-permissions.stderr b/tests/ui/borrowck/borrowck-access-permissions.stderr index c161e2d95b43..93d92295dd9b 100644 --- a/tests/ui/borrowck/borrowck-access-permissions.stderr +++ b/tests/ui/borrowck/borrowck-access-permissions.stderr @@ -1,5 +1,20 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/borrowck-access-permissions.rs:18:23 + | +LL | let _y2 = &mut static_x_mut; + | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let _y2 = addr_of_mut!(static_x_mut); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/borrowck-access-permissions.rs:9:19 + --> $DIR/borrowck-access-permissions.rs:10:19 | LL | let _y1 = &mut x; | ^^^^^^ cannot borrow as mutable @@ -10,13 +25,13 @@ LL | let mut x = 1; | +++ error[E0596]: cannot borrow immutable static item `static_x` as mutable - --> $DIR/borrowck-access-permissions.rs:14:19 + --> $DIR/borrowck-access-permissions.rs:16:19 | LL | let _y1 = &mut static_x; | ^^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `*box_x` as mutable, as `box_x` is not declared as mutable - --> $DIR/borrowck-access-permissions.rs:22:19 + --> $DIR/borrowck-access-permissions.rs:28:19 | LL | let _y1 = &mut *box_x; | ^^^^^^^^^^^ cannot borrow as mutable @@ -27,7 +42,7 @@ LL | let mut box_x = Box::new(1); | +++ error[E0596]: cannot borrow `*ref_x` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-access-permissions.rs:30:19 + --> $DIR/borrowck-access-permissions.rs:37:19 | LL | let _y1 = &mut *ref_x; | ^^^^^^^^^^^ `ref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -38,18 +53,18 @@ LL | let ref_x = &mut x; | +++ error[E0596]: cannot borrow `*ptr_x` as mutable, as it is behind a `*const` pointer - --> $DIR/borrowck-access-permissions.rs:39:23 + --> $DIR/borrowck-access-permissions.rs:47:23 | LL | let _y1 = &mut *ptr_x; | ^^^^^^^^^^^ `ptr_x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable | help: consider changing this to be a mutable pointer | -LL | let ptr_x : *const _ = &mut x; - | +++ +LL | let ptr_x: *const _ = &mut x; + | +++ error[E0596]: cannot borrow `*foo_ref.f` as mutable, as it is behind a `&` reference - --> $DIR/borrowck-access-permissions.rs:48:18 + --> $DIR/borrowck-access-permissions.rs:60:18 | LL | let _y = &mut *foo_ref.f; | ^^^^^^^^^^^^^^^ `foo_ref` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -59,6 +74,6 @@ help: consider changing this to be a mutable reference LL | let foo_ref = &mut foo; | +++ -error: aborting due to 6 previous errors +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs index adc7dfd541f4..1bf079e24cae 100644 --- a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs +++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs @@ -2,17 +2,22 @@ // Test file taken from issue 45129 (https://github.com/rust-lang/rust/issues/45129) -struct Foo { x: [usize; 2] } +struct Foo { + x: [usize; 2], +} static mut SFOO: Foo = Foo { x: [23, 32] }; impl Foo { - fn x(&mut self) -> &mut usize { &mut self.x[0] } + fn x(&mut self) -> &mut usize { + &mut self.x[0] + } } fn main() { unsafe { let sfoo: *mut Foo = &mut SFOO; + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] let x = (*sfoo).x(); (*sfoo).x[1] += 1; *x += 1; diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr new file mode 100644 index 000000000000..7a3824f79a4c --- /dev/null +++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr @@ -0,0 +1,17 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/borrowck-unsafe-static-mutable-borrows.rs:19:30 + | +LL | let sfoo: *mut Foo = &mut SFOO; + | ^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let sfoo: *mut Foo = addr_of_mut!(SFOO); + | ~~~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/borrowck/issue-20801.rs b/tests/ui/borrowck/issue-20801.rs index c3f136f2876b..ec83af5d5dfc 100644 --- a/tests/ui/borrowck/issue-20801.rs +++ b/tests/ui/borrowck/issue-20801.rs @@ -12,6 +12,7 @@ fn imm_ref() -> &'static T { fn mut_ref() -> &'static mut T { unsafe { &mut GLOBAL_MUT_T } + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] } fn mut_ptr() -> *mut T { diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr index 215bf0100636..b2bee2d88039 100644 --- a/tests/ui/borrowck/issue-20801.stderr +++ b/tests/ui/borrowck/issue-20801.stderr @@ -1,5 +1,20 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/issue-20801.rs:14:14 + | +LL | unsafe { &mut GLOBAL_MUT_T } + | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | unsafe { addr_of_mut!(GLOBAL_MUT_T) } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0507]: cannot move out of a mutable reference - --> $DIR/issue-20801.rs:26:22 + --> $DIR/issue-20801.rs:27:22 | LL | let a = unsafe { *mut_ref() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -11,7 +26,7 @@ LL + let a = unsafe { mut_ref() }; | error[E0507]: cannot move out of a shared reference - --> $DIR/issue-20801.rs:29:22 + --> $DIR/issue-20801.rs:30:22 | LL | let b = unsafe { *imm_ref() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -23,7 +38,7 @@ LL + let b = unsafe { imm_ref() }; | error[E0507]: cannot move out of a raw pointer - --> $DIR/issue-20801.rs:32:22 + --> $DIR/issue-20801.rs:33:22 | LL | let c = unsafe { *mut_ptr() }; | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -35,7 +50,7 @@ LL + let c = unsafe { mut_ptr() }; | error[E0507]: cannot move out of a raw pointer - --> $DIR/issue-20801.rs:35:22 + --> $DIR/issue-20801.rs:36:22 | LL | let d = unsafe { *const_ptr() }; | ^^^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait @@ -46,6 +61,6 @@ LL - let d = unsafe { *const_ptr() }; LL + let d = unsafe { const_ptr() }; | -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs index b3cce1b3a061..9b172b413191 100644 --- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs +++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs @@ -8,7 +8,10 @@ mod borrowck_closures_unique { static mut Y: isize = 3; let mut c1 = |y: &'static mut isize| x = y; //~^ ERROR is not declared as mutable - unsafe { c1(&mut Y); } + unsafe { + c1(&mut Y); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + } } } @@ -17,36 +20,50 @@ mod borrowck_closures_unique_grandparent { static mut Z: isize = 3; let mut c1 = |z: &'static mut isize| { let mut c2 = |y: &'static mut isize| x = y; - //~^ ERROR is not declared as mutable + //~^ ERROR is not declared as mutable c2(z); }; - unsafe { c1(&mut Z); } + unsafe { + c1(&mut Z); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + } } } // adapted from mutability_errors.rs mod mutability_errors { pub fn capture_assign_whole(x: (i32,)) { - || { x = (1,); }; - //~^ ERROR is not declared as mutable + || { + x = (1,); + //~^ ERROR is not declared as mutable + }; } pub fn capture_assign_part(x: (i32,)) { - || { x.0 = 1; }; - //~^ ERROR is not declared as mutable + || { + x.0 = 1; + //~^ ERROR is not declared as mutable + }; } pub fn capture_reborrow_whole(x: (i32,)) { - || { &mut x; }; - //~^ ERROR is not declared as mutable + || { + &mut x; + //~^ ERROR is not declared as mutable + }; } pub fn capture_reborrow_part(x: (i32,)) { - || { &mut x.0; }; - //~^ ERROR is not declared as mutable + || { + &mut x.0; + //~^ ERROR is not declared as mutable + }; } } fn main() { static mut X: isize = 2; - unsafe { borrowck_closures_unique::e(&mut X); } + unsafe { + borrowck_closures_unique::e(&mut X); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + } mutability_errors::capture_assign_whole((1000,)); mutability_errors::capture_assign_part((2000,)); diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr index 4c299cdc455a..e4e4947fce1c 100644 --- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr +++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr @@ -1,3 +1,46 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:12:16 + | +LL | c1(&mut Y); + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | c1(addr_of_mut!(Y)); + | ~~~~~~~~~~~~~~~ + +warning: mutable reference of mutable static is discouraged + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:27:16 + | +LL | c1(&mut Z); + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | c1(addr_of_mut!(Z)); + | ~~~~~~~~~~~~~~~ + +warning: mutable reference of mutable static is discouraged + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:64:37 + | +LL | borrowck_closures_unique::e(&mut X); + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | borrowck_closures_unique::e(addr_of_mut!(X)); + | ~~~~~~~~~~~~~~~ + error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:9:46 | @@ -8,7 +51,7 @@ LL | let mut c1 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:50 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:22:50 | LL | pub fn ee(x: &'static mut isize) { | - help: consider changing this to be mutable: `mut x` @@ -17,38 +60,42 @@ LL | let mut c2 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:37:13 | LL | pub fn capture_assign_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` -LL | || { x = (1,); }; - | ^^^^^^^^ cannot assign +LL | || { +LL | x = (1,); + | ^^^^^^^^ cannot assign error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:34:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:43:13 | LL | pub fn capture_assign_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` -LL | || { x.0 = 1; }; - | ^^^^^^^ cannot assign +LL | || { +LL | x.0 = 1; + | ^^^^^^^ cannot assign error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:38:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:49:13 | LL | pub fn capture_reborrow_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` -LL | || { &mut x; }; - | ^^^^^^ cannot borrow as mutable +LL | || { +LL | &mut x; + | ^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:13 | LL | pub fn capture_reborrow_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` -LL | || { &mut x.0; }; - | ^^^^^^^^ cannot borrow as mutable +LL | || { +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable -error: aborting due to 6 previous errors +error: aborting due to 6 previous errors; 3 warnings emitted Some errors have detailed explanations: E0594, E0596. For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs index b52939ffc119..c10246eec649 100644 --- a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs +++ b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs @@ -17,6 +17,7 @@ async fn buy_lock(coroutine: &Mutex) -> LockedMarket<'_> { //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument was supplied //~^^ ERROR struct takes 1 generic argument but 0 generic arguments were supplied LockedMarket(coroutine.lock().unwrap().buy()) + //~^ ERROR: cannot return value referencing temporary value } struct LockedMarket(T); diff --git a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr index 516c1d065e67..2b10cf67d15b 100644 --- a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr +++ b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr @@ -7,7 +7,7 @@ LL | async fn buy_lock(coroutine: &Mutex) -> LockedMarket<'_> | expected 0 lifetime arguments | note: struct defined here, with 0 lifetime parameters - --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8 + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8 | LL | struct LockedMarket(T); | ^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | async fn buy_lock(coroutine: &Mutex) -> LockedMarket<'_> | ^^^^^^^^^^^^ expected 1 generic argument | note: struct defined here, with 1 generic parameter: `T` - --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8 + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8 | LL | struct LockedMarket(T); | ^^^^^^^^^^^^ - @@ -28,6 +28,16 @@ help: add missing generic argument LL | async fn buy_lock(coroutine: &Mutex) -> LockedMarket<'_, T> { | +++ -error: aborting due to 2 previous errors +error[E0515]: cannot return value referencing temporary value + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:19:5 + | +LL | LockedMarket(coroutine.lock().unwrap().buy()) + | ^^^^^^^^^^^^^-------------------------^^^^^^^ + | | | + | | temporary value created here + | returns a value referencing data owned by the current function -For more information about this error, try `rustc --explain E0107`. +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0107, E0515. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.stderr b/tests/ui/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.stderr index f5cb3e2b5f80..48fc84618823 100644 --- a/tests/ui/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.stderr +++ b/tests/ui/closures/coerce-unsafe-closure-to-unsafe-fn-ptr.stderr @@ -1,4 +1,4 @@ -error[E0133]: call to unsafe function `Pin::

::new_unchecked` is unsafe and requires unsafe function or block +error[E0133]: call to unsafe function `Pin::::new_unchecked` is unsafe and requires unsafe function or block --> $DIR/coerce-unsafe-closure-to-unsafe-fn-ptr.rs:2:31 | LL | let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); }; diff --git a/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.rs b/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.rs index 01f7d6ce9010..c50bbcec5215 100644 --- a/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.rs +++ b/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.rs @@ -1,18 +1,15 @@ -#![deny(coinductive_overlap_in_coherence)] - use std::borrow::Borrow; use std::cmp::Ordering; use std::marker::PhantomData; #[derive(PartialEq, Default)] +//~^ ERROR conflicting implementations of trait `PartialEq>` for type `Interval<_>` pub(crate) struct Interval(PhantomData); // This impl overlaps with the `derive` unless we reject the nested // `Interval: PartialOrd>` candidate which results -// in a - currently inductive - cycle. +// in a -- currently inductive -- cycle. impl PartialEq for Interval -//~^ ERROR implementations of `PartialEq>` for `Interval<_>` will conflict in the future -//~| WARN this was previously accepted by the compiler but is being phased out where T: Borrow, Q: ?Sized + PartialOrd, diff --git a/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.stderr b/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.stderr index 4535b6f68115..af4dbfcad0e2 100644 --- a/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.stderr +++ b/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.stderr @@ -1,51 +1,17 @@ -error: implementations of `PartialEq>` for `Interval<_>` will conflict in the future - --> $DIR/warn-when-cycle-is-error-in-coherence.rs:13:1 +error[E0119]: conflicting implementations of trait `PartialEq>` for type `Interval<_>` + --> $DIR/warn-when-cycle-is-error-in-coherence.rs:5:10 | LL | #[derive(PartialEq, Default)] - | --------- the second impl is here + | ^^^^^^^^^ conflicting implementation for `Interval<_>` ... LL | / impl PartialEq for Interval -LL | | -LL | | LL | | where LL | | T: Borrow, LL | | Q: ?Sized + PartialOrd, - | |___________________________^ the first impl is here + | |___________________________- first implementation here | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #114040 - = note: impls that are not considered to overlap may be considered to overlap in the future - = note: `Interval<_>: PartialOrd` may be considered to hold in future releases, causing the impls to overlap -note: the lint level is defined here - --> $DIR/warn-when-cycle-is-error-in-coherence.rs:1:9 - | -LL | #![deny(coinductive_overlap_in_coherence)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error -Future incompatibility report: Future breakage diagnostic: -error: implementations of `PartialEq>` for `Interval<_>` will conflict in the future - --> $DIR/warn-when-cycle-is-error-in-coherence.rs:13:1 - | -LL | #[derive(PartialEq, Default)] - | --------- the second impl is here -... -LL | / impl PartialEq for Interval -LL | | -LL | | -LL | | where -LL | | T: Borrow, -LL | | Q: ?Sized + PartialOrd, - | |___________________________^ the first impl is here - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #114040 - = note: impls that are not considered to overlap may be considered to overlap in the future - = note: `Interval<_>: PartialOrd` may be considered to hold in future releases, causing the impls to overlap -note: the lint level is defined here - --> $DIR/warn-when-cycle-is-error-in-coherence.rs:1:9 - | -LL | #![deny(coinductive_overlap_in_coherence)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/const-generics/assoc_const_eq_diagnostic.rs b/tests/ui/const-generics/assoc_const_eq_diagnostic.rs index d51696f9ebde..573d8055a79c 100644 --- a/tests/ui/const-generics/assoc_const_eq_diagnostic.rs +++ b/tests/ui/const-generics/assoc_const_eq_diagnostic.rs @@ -9,9 +9,10 @@ pub trait Parse { } pub trait CoolStuff: Parse {} -//~^ ERROR expected type, found variant +//~^ ERROR expected constant, found type //~| ERROR expected constant, found type //~| ERROR expected constant, found type +//~| ERROR expected type fn no_help() -> Mode::Cool {} //~^ ERROR expected type, found variant diff --git a/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr b/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr index 3d724bb16424..13f081940f39 100644 --- a/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr +++ b/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr @@ -8,7 +8,7 @@ LL | pub trait CoolStuff: Parse {} | help: try using the variant's enum: `Mode` error[E0573]: expected type, found variant `Mode::Cool` - --> $DIR/assoc_const_eq_diagnostic.rs:16:17 + --> $DIR/assoc_const_eq_diagnostic.rs:17:17 | LL | fn no_help() -> Mode::Cool {} | ^^^^^^^^^^ @@ -53,6 +53,25 @@ help: consider adding braces here LL | pub trait CoolStuff: Parse {} | + + -error: aborting due to 4 previous errors +error: expected constant, found type + --> $DIR/assoc_const_eq_diagnostic.rs:11:35 + | +LL | pub trait CoolStuff: Parse {} + | ---- ^^^^^^^^^^ unexpected type + | | + | expected a constant because of this associated constant + | +note: the associated constant is defined here + --> $DIR/assoc_const_eq_diagnostic.rs:8:5 + | +LL | const MODE: Mode; + | ^^^^^^^^^^^^^^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding braces here + | +LL | pub trait CoolStuff: Parse {} + | + + + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0573`. diff --git a/tests/ui/const-generics/generic_const_exprs/issue-102768.rs b/tests/ui/const-generics/generic_const_exprs/issue-102768.rs index 18a9b53cf768..f2ad7d7ce8b9 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-102768.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-102768.rs @@ -9,6 +9,11 @@ const _: () = { fn f2<'a>(arg: Box = &'a ()>>) {} //~^ ERROR associated type takes 1 lifetime argument but 0 lifetime arguments //~| ERROR associated type takes 0 generic arguments but 1 generic argument + //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments + //~| ERROR associated type takes 0 generic arguments but 1 generic argument + //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments + //~| ERROR associated type takes 0 generic arguments but 1 generic argument + //~| ERROR `X` cannot be made into an object }; fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr index 175d54e41848..a470c36134cf 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr @@ -28,6 +28,86 @@ note: associated type defined here, with 0 generic parameters LL | type Y<'a>; | ^ -error: aborting due to 2 previous errors +error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/issue-102768.rs:9:30 + | +LL | fn f2<'a>(arg: Box = &'a ()>>) {} + | ^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/issue-102768.rs:5:10 + | +LL | type Y<'a>; + | ^ -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime argument + | +LL | fn f2<'a>(arg: Box = &'a ()>>) {} + | +++ -For more information about this error, try `rustc --explain E0107`. +error[E0107]: associated type takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/issue-102768.rs:9:30 + | +LL | fn f2<'a>(arg: Box = &'a ()>>) {} + | ^--- help: remove these generics + | | + | expected 0 generic arguments + | +note: associated type defined here, with 0 generic parameters + --> $DIR/issue-102768.rs:5:10 + | +LL | type Y<'a>; + | ^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/issue-102768.rs:9:30 + | +LL | fn f2<'a>(arg: Box = &'a ()>>) {} + | ^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/issue-102768.rs:5:10 + | +LL | type Y<'a>; + | ^ -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime argument + | +LL | fn f2<'a>(arg: Box = &'a ()>>) {} + | +++ + +error[E0107]: associated type takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/issue-102768.rs:9:30 + | +LL | fn f2<'a>(arg: Box = &'a ()>>) {} + | ^--- help: remove these generics + | | + | expected 0 generic arguments + | +note: associated type defined here, with 0 generic parameters + --> $DIR/issue-102768.rs:5:10 + | +LL | type Y<'a>; + | ^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0038]: the trait `X` cannot be made into an object + --> $DIR/issue-102768.rs:9:24 + | +LL | fn f2<'a>(arg: Box = &'a ()>>) {} + | ^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/issue-102768.rs:5:10 + | +LL | trait X { + | - this trait cannot be made into an object... +LL | type Y<'a>; + | ^ ...because it contains the generic associated type `Y` + = help: consider moving `Y` to another trait + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0038, E0107. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/const-generics/generic_const_exprs/issue-105257.rs b/tests/ui/const-generics/generic_const_exprs/issue-105257.rs index d8b23bc01a96..a107556fd79d 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-105257.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-105257.rs @@ -3,6 +3,7 @@ trait Trait { fn fnc(&self) {} //~ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + //~^ ERROR: mismatched types fn foo() }>(&self) {} //~ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions } diff --git a/tests/ui/const-generics/generic_const_exprs/issue-105257.stderr b/tests/ui/const-generics/generic_const_exprs/issue-105257.stderr index ed7a8cb19a4a..d7ded0f1f748 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-105257.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-105257.stderr @@ -5,10 +5,17 @@ LL | fn fnc(&self) {} | ^^^^^^^^^^^^^^^^^^^ error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/issue-105257.rs:6:12 + --> $DIR/issue-105257.rs:7:12 | LL | fn foo() }>(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/issue-105257.rs:5:29 + | +LL | fn fnc(&self) {} + | ^^ expected `usize`, found `&str` +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.stderr b/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.stderr index 7bef98b1d5d2..1fe0109771c5 100644 --- a/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.stderr +++ b/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.stderr @@ -4,5 +4,14 @@ error: cannot capture late-bound lifetime in constant LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> { | -- lifetime defined here ^^ -error: aborting due to 1 previous error +error: overly complex generic constant + --> $DIR/late-bound-in-return-issue-77357.rs:9:46 + | +LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constants + | + = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future + +error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/min_const_generics/macro-fail.rs b/tests/ui/const-generics/min_const_generics/macro-fail.rs index 7fb69032e6fc..f3df96d468c3 100644 --- a/tests/ui/const-generics/min_const_generics/macro-fail.rs +++ b/tests/ui/const-generics/min_const_generics/macro-fail.rs @@ -14,6 +14,7 @@ impl Marker for Example {} fn make_marker() -> impl Marker { //~^ ERROR: type provided when a constant was expected Example:: + //~^ ERROR: type provided when a constant was expected } fn from_marker(_: impl Marker<{ @@ -33,7 +34,9 @@ fn main() { }>; let _fail = Example::; + //~^ ERROR: type provided when a constant was expected let _fail = Example::; //~^ ERROR unexpected end of macro invocation + //~| ERROR: type provided when a constant was expected } diff --git a/tests/ui/const-generics/min_const_generics/macro-fail.stderr b/tests/ui/const-generics/min_const_generics/macro-fail.stderr index cc629fd920fa..06a111008a30 100644 --- a/tests/ui/const-generics/min_const_generics/macro-fail.stderr +++ b/tests/ui/const-generics/min_const_generics/macro-fail.stderr @@ -1,5 +1,5 @@ error: expected type, found `{` - --> $DIR/macro-fail.rs:28:27 + --> $DIR/macro-fail.rs:29:27 | LL | fn make_marker() -> impl Marker { | ---------------------- @@ -13,7 +13,7 @@ LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info) error: expected type, found `{` - --> $DIR/macro-fail.rs:28:27 + --> $DIR/macro-fail.rs:29:27 | LL | Example:: | ---------------------- @@ -41,7 +41,7 @@ LL | let _fail = Example::; = note: this error originates in the macro `external_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: unexpected end of macro invocation - --> $DIR/macro-fail.rs:37:25 + --> $DIR/macro-fail.rs:39:25 | LL | macro_rules! gimme_a_const { | -------------------------- when calling this macro @@ -50,7 +50,7 @@ LL | let _fail = Example::; | ^^^^^^^^^^^^^^^^ missing tokens in macro arguments | note: while trying to match meta-variable `$rusty:ident` - --> $DIR/macro-fail.rs:28:8 + --> $DIR/macro-fail.rs:29:8 | LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} | ^^^^^^^^^^^^^ @@ -61,6 +61,24 @@ error[E0747]: type provided when a constant was expected LL | fn make_marker() -> impl Marker { | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error[E0747]: type provided when a constant was expected + --> $DIR/macro-fail.rs:16:13 + | +LL | Example:: + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0747]: type provided when a constant was expected + --> $DIR/macro-fail.rs:36:25 + | +LL | let _fail = Example::; + | ^^^^^^^^^^^^^^^^^ + +error[E0747]: type provided when a constant was expected + --> $DIR/macro-fail.rs:39:25 + | +LL | let _fail = Example::; + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0747`. diff --git a/tests/ui/consts/const-eval/ub-enum.64bit.stderr b/tests/ui/consts/const-eval/ub-enum.64bit.stderr deleted file mode 100644 index 6db43d379d15..000000000000 --- a/tests/ui/consts/const-eval/ub-enum.64bit.stderr +++ /dev/null @@ -1,134 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:27:1 - | -LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0000000000000001, but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:30:1 - | -LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer - | - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - -error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:33:1 - | -LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer - | - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:45:1 - | -LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0000000000000000, but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:47:1 - | -LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer - | - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - -error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:50:1 - | -LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer - | - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - -error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:59:42 - | -LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory - -error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:64:1 - | -LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer - | - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:81:1 - | -LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:83:1 - | -LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:91:1 - | -LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:96:77 - | -LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant - -error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:98:77 - | -LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant - -error[E0080]: evaluation of constant value failed - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL - | - = note: read discriminant of an uninhabited enum variant - | -note: inside `discriminant::` - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -note: inside `TEST_ICE_89765` - --> $DIR/ub-enum.rs:103:14 - | -LL | unsafe { std::mem::discriminant(&*(&() as *const () as *const Never)); }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 14 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-enum.rs b/tests/ui/consts/const-eval/ub-enum.rs index 72a0c9efed2c..c11ace612f13 100644 --- a/tests/ui/consts/const-eval/ub-enum.rs +++ b/tests/ui/consts/const-eval/ub-enum.rs @@ -1,7 +1,7 @@ -// stderr-per-bitwidth // Strip out raw byte dumps to make comparison platform-independent: // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" +// normalize-stderr-test "0x0+" -> "0x0" #![feature(never_type)] #![allow(invalid_value)] diff --git a/tests/ui/consts/const-eval/ub-enum.32bit.stderr b/tests/ui/consts/const-eval/ub-enum.stderr similarity index 98% rename from tests/ui/consts/const-eval/ub-enum.32bit.stderr rename to tests/ui/consts/const-eval/ub-enum.stderr index c0ad6caecf2b..a0712f64c7bc 100644 --- a/tests/ui/consts/const-eval/ub-enum.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-enum.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:27:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x00000001, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x01, but expected a valid enum tag | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -31,7 +31,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:45:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x00000000, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0, but expected a valid enum tag | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/consts/const-eval/ub-uninhabit.rs b/tests/ui/consts/const-eval/ub-uninhabit.rs index 01600f545ae0..0eb9ab415d79 100644 --- a/tests/ui/consts/const-eval/ub-uninhabit.rs +++ b/tests/ui/consts/const-eval/ub-uninhabit.rs @@ -1,6 +1,6 @@ // Strip out raw byte dumps to make comparison platform-independent: // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" #![feature(core_intrinsics)] #![feature(never_type)] diff --git a/tests/ui/consts/const_let_assign2.rs b/tests/ui/consts/const_let_assign2.rs index 28265c85dd1f..1c7afe0e3d6c 100644 --- a/tests/ui/consts/const_let_assign2.rs +++ b/tests/ui/consts/const_let_assign2.rs @@ -16,6 +16,7 @@ static mut BB: AA = AA::new(); fn main() { let ptr = unsafe { &mut BB }; + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] for a in ptr.data.iter() { println!("{}", a); } diff --git a/tests/ui/consts/const_let_assign2.stderr b/tests/ui/consts/const_let_assign2.stderr new file mode 100644 index 000000000000..2764153a8a59 --- /dev/null +++ b/tests/ui/consts/const_let_assign2.stderr @@ -0,0 +1,17 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/const_let_assign2.rs:18:24 + | +LL | let ptr = unsafe { &mut BB }; + | ^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let ptr = unsafe { addr_of_mut!(BB) }; + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/consts/escaping-bound-var.rs b/tests/ui/consts/escaping-bound-var.rs index 7c1fbd24f555..a538d607d6ca 100644 --- a/tests/ui/consts/escaping-bound-var.rs +++ b/tests/ui/consts/escaping-bound-var.rs @@ -3,7 +3,7 @@ fn test<'a>( _: &'a (), -) -> [(); { +) -> [(); { //~ ERROR: mismatched types let x: &'a (); //~^ ERROR cannot capture late-bound lifetime in constant 1 diff --git a/tests/ui/consts/escaping-bound-var.stderr b/tests/ui/consts/escaping-bound-var.stderr index a943c84e3b2a..bb0d285f4d06 100644 --- a/tests/ui/consts/escaping-bound-var.stderr +++ b/tests/ui/consts/escaping-bound-var.stderr @@ -16,5 +16,23 @@ LL | fn test<'a>( LL | let x: &'a (); | ^^ -error: aborting due to 1 previous error; 1 warning emitted +error[E0308]: mismatched types + --> $DIR/escaping-bound-var.rs:6:6 + | +LL | fn test<'a>( + | ---- implicitly returns `()` as its body has no tail or `return` expression +LL | _: &'a (), +LL | ) -> [(); { + | ______^ +LL | | let x: &'a (); +LL | | +LL | | 1 +LL | | }] { + | |__^ expected `[(); { + let x: &'a (); + 1 +}]`, found `()` +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/issue-103790.rs b/tests/ui/consts/issue-103790.rs index ea3cac605b15..5d130821dc8e 100644 --- a/tests/ui/consts/issue-103790.rs +++ b/tests/ui/consts/issue-103790.rs @@ -6,5 +6,6 @@ struct S; //~| ERROR missing generics for struct `S` //~| ERROR cycle detected when computing type of `S::S` //~| ERROR cycle detected when computing type of `S` +//~| ERROR `()` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/consts/issue-103790.stderr b/tests/ui/consts/issue-103790.stderr index 67334469dcde..55bc9675401b 100644 --- a/tests/ui/consts/issue-103790.stderr +++ b/tests/ui/consts/issue-103790.stderr @@ -61,7 +61,16 @@ LL | | fn main() {} | |____________^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 4 previous errors +error: `()` is forbidden as the type of a const generic parameter + --> $DIR/issue-103790.rs:4:19 + | +LL | struct S; + | ^^ + | + = note: the only supported types are integers, `bool` and `char` + = help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0107, E0391, E0403. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs index 62bbb3b569c3..4fedc48452be 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.rs +++ b/tests/ui/consts/issue-17718-const-bad-values.rs @@ -3,7 +3,8 @@ const C1: &'static mut [usize] = &mut []; static mut S: usize = 3; const C2: &'static mut usize = unsafe { &mut S }; -//~^ ERROR: constants cannot refer to statics +//~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] +//~^^ ERROR: constants cannot refer to statics //~| ERROR: constants cannot refer to statics fn main() {} diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr index 405c2195dec4..2dc91f52669e 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.stderr +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -1,3 +1,18 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/issue-17718-const-bad-values.rs:5:41 + | +LL | const C2: &'static mut usize = unsafe { &mut S }; + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | const C2: &'static mut usize = unsafe { addr_of_mut!(S) }; + | ~~~~~~~~~~~~~~~ + error[E0764]: mutable references are not allowed in the final value of constants --> $DIR/issue-17718-const-bad-values.rs:1:34 | @@ -21,7 +36,7 @@ LL | const C2: &'static mut usize = unsafe { &mut S }; = help: consider extracting the value of the `static` to a `const`, and referring to that = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 3 previous errors +error: aborting due to 3 previous errors; 1 warning emitted Some errors have detailed explanations: E0013, E0764. For more information about an error, try `rustc --explain E0013`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr index 7960648ce3a1..ed9db6754264 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr @@ -1,3 +1,18 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/const_refers_to_static_cross_crate.rs:13:14 + | +LL | unsafe { &static_cross_crate::ZERO } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | unsafe { addr_of!(static_cross_crate::ZERO) } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static_cross_crate.rs:10:1 | @@ -10,13 +25,13 @@ LL | const SLICE_MUT: &[u8; 1] = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:34:9 + --> $DIR/const_refers_to_static_cross_crate.rs:42:9 | LL | SLICE_MUT => true, | ^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static_cross_crate.rs:15:1 + --> $DIR/const_refers_to_static_cross_crate.rs:17:1 | LL | const U8_MUT: &u8 = { | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant @@ -27,31 +42,31 @@ LL | const U8_MUT: &u8 = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:42:9 + --> $DIR/const_refers_to_static_cross_crate.rs:50:9 | LL | U8_MUT => true, | ^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/const_refers_to_static_cross_crate.rs:22:15 + --> $DIR/const_refers_to_static_cross_crate.rs:25:15 | LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:52:9 + --> $DIR/const_refers_to_static_cross_crate.rs:60:9 | LL | U8_MUT2 => true, | ^^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:59:9 + --> $DIR/const_refers_to_static_cross_crate.rs:67:9 | LL | U8_MUT3 => true, | ^^^^^^^ @@ -59,61 +74,61 @@ LL | U8_MUT3 => true, warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:22:17 + --> $DIR/const_refers_to_static_cross_crate.rs:25:17 | LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 8 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr index 6ae0b2d1bfef..275323bc286c 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr @@ -1,3 +1,18 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/const_refers_to_static_cross_crate.rs:13:14 + | +LL | unsafe { &static_cross_crate::ZERO } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | unsafe { addr_of!(static_cross_crate::ZERO) } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static_cross_crate.rs:10:1 | @@ -10,13 +25,13 @@ LL | const SLICE_MUT: &[u8; 1] = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:34:9 + --> $DIR/const_refers_to_static_cross_crate.rs:42:9 | LL | SLICE_MUT => true, | ^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static_cross_crate.rs:15:1 + --> $DIR/const_refers_to_static_cross_crate.rs:17:1 | LL | const U8_MUT: &u8 = { | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant @@ -27,31 +42,31 @@ LL | const U8_MUT: &u8 = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:42:9 + --> $DIR/const_refers_to_static_cross_crate.rs:50:9 | LL | U8_MUT => true, | ^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/const_refers_to_static_cross_crate.rs:22:15 + --> $DIR/const_refers_to_static_cross_crate.rs:25:15 | LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:52:9 + --> $DIR/const_refers_to_static_cross_crate.rs:60:9 | LL | U8_MUT2 => true, | ^^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:59:9 + --> $DIR/const_refers_to_static_cross_crate.rs:67:9 | LL | U8_MUT3 => true, | ^^^^^^^ @@ -59,61 +74,61 @@ LL | U8_MUT3 => true, warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + --> $DIR/const_refers_to_static_cross_crate.rs:20:15 | LL | unsafe { &static_cross_crate::ZERO[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:22:17 + --> $DIR/const_refers_to_static_cross_crate.rs:25:17 | LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + --> $DIR/const_refers_to_static_cross_crate.rs:31:15 | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | match static_cross_crate::OPT_ZERO { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 8 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs index bbaa32ddfd1b..3eafa58d9f9f 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs @@ -7,13 +7,16 @@ extern crate static_cross_crate; // Sneaky: reference to a mutable static. // Allowing this would be a disaster for pattern matching, we could violate exhaustiveness checking! -const SLICE_MUT: &[u8; 1] = { //~ ERROR undefined behavior to use this value -//~| encountered a reference pointing to a static variable +const SLICE_MUT: &[u8; 1] = { + //~^ ERROR undefined behavior to use this value + //~| encountered a reference pointing to a static variable unsafe { &static_cross_crate::ZERO } + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] }; -const U8_MUT: &u8 = { //~ ERROR undefined behavior to use this value -//~| encountered a reference pointing to a static variable +const U8_MUT: &u8 = { + //~^ ERROR undefined behavior to use this value + //~| encountered a reference pointing to a static variable unsafe { &static_cross_crate::ZERO[0] } }; @@ -24,9 +27,14 @@ const U8_MUT2: &u8 = { //~| constant accesses static }; const U8_MUT3: &u8 = { - unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - //~^ ERROR evaluation of constant value failed - //~| constant accesses static + unsafe { + match static_cross_crate::OPT_ZERO { + //~^ ERROR evaluation of constant value failed + //~| constant accesses static + Some(ref u) => u, + None => panic!(), + } + } }; pub fn test(x: &[u8; 1]) -> bool { diff --git a/tests/ui/consts/static_mut_containing_mut_ref.rs b/tests/ui/consts/static_mut_containing_mut_ref.rs index df09c76c5584..874aa59df0bb 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref.rs +++ b/tests/ui/consts/static_mut_containing_mut_ref.rs @@ -3,5 +3,6 @@ static mut STDERR_BUFFER_SPACE: [u8; 42] = [0u8; 42]; pub static mut STDERR_BUFFER: *mut [u8] = unsafe { &mut STDERR_BUFFER_SPACE }; +//~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref.stderr b/tests/ui/consts/static_mut_containing_mut_ref.stderr new file mode 100644 index 000000000000..56ceba41cf88 --- /dev/null +++ b/tests/ui/consts/static_mut_containing_mut_ref.stderr @@ -0,0 +1,17 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/static_mut_containing_mut_ref.rs:5:52 + | +LL | pub static mut STDERR_BUFFER: *mut [u8] = unsafe { &mut STDERR_BUFFER_SPACE }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | pub static mut STDERR_BUFFER: *mut [u8] = unsafe { addr_of_mut!(STDERR_BUFFER_SPACE) }; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr index 3d0de233569c..bc32ecc2c35f 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr @@ -1,9 +1,24 @@ -error[E0080]: could not evaluate static initializer - --> $DIR/static_mut_containing_mut_ref2.rs:7:45 +warning: mutable reference of mutable static is discouraged + --> $DIR/static_mut_containing_mut_ref2.rs:8:6 | -LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer +LL | *(&mut STDERR_BUFFER_SPACE) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | *addr_of_mut!(STDERR_BUFFER_SPACE) = 42; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 1 previous error +error[E0080]: could not evaluate static initializer + --> $DIR/static_mut_containing_mut_ref2.rs:8:5 + | +LL | *(&mut STDERR_BUFFER_SPACE) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer + +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.rs b/tests/ui/consts/static_mut_containing_mut_ref2.rs index 61368546083d..fa79a78eab42 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.rs +++ b/tests/ui/consts/static_mut_containing_mut_ref2.rs @@ -4,8 +4,12 @@ static mut STDERR_BUFFER_SPACE: u8 = 0; -pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; -//[mut_refs]~^ ERROR could not evaluate static initializer -//[stock]~^^ ERROR mutable references are not allowed in statics +pub static mut STDERR_BUFFER: () = unsafe { + *(&mut STDERR_BUFFER_SPACE) = 42; + //[mut_refs]~^ ERROR could not evaluate static initializer + //[stock]~^^ ERROR mutable references are not allowed in statics + //[mut_refs]~^^^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + //[stock]~^^^^ WARN mutable reference of mutable static is discouraged [static_mut_ref] +}; fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr index 3d5b012d42f3..c6e5b07e3b70 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr @@ -1,12 +1,27 @@ -error[E0658]: mutable references are not allowed in statics - --> $DIR/static_mut_containing_mut_ref2.rs:7:46 +warning: mutable reference of mutable static is discouraged + --> $DIR/static_mut_containing_mut_ref2.rs:8:6 | -LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | *(&mut STDERR_BUFFER_SPACE) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | *addr_of_mut!(STDERR_BUFFER_SPACE) = 42; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0658]: mutable references are not allowed in statics + --> $DIR/static_mut_containing_mut_ref2.rs:8:6 + | +LL | *(&mut STDERR_BUFFER_SPACE) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/validate_never_arrays.rs b/tests/ui/consts/validate_never_arrays.rs index f96ca6839265..71c1340e5f81 100644 --- a/tests/ui/consts/validate_never_arrays.rs +++ b/tests/ui/consts/validate_never_arrays.rs @@ -1,6 +1,6 @@ // Strip out raw byte dumps to make comparison platform-independent: // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" #![feature(never_type)] const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior diff --git a/tests/ui/derives/issue-97343.rs b/tests/ui/derives/issue-97343.rs index 6f0e4d55aeb0..91f0aa376e9a 100644 --- a/tests/ui/derives/issue-97343.rs +++ b/tests/ui/derives/issue-97343.rs @@ -2,6 +2,7 @@ use std::fmt::Debug; #[derive(Debug)] pub struct Irrelevant { //~ ERROR type arguments are not allowed on type parameter + //~^ ERROR `Irrelevant` must be used irrelevant: Irrelevant, } diff --git a/tests/ui/derives/issue-97343.stderr b/tests/ui/derives/issue-97343.stderr index efb2fb70f5a5..45612ae6f474 100644 --- a/tests/ui/derives/issue-97343.stderr +++ b/tests/ui/derives/issue-97343.stderr @@ -16,6 +16,16 @@ LL | pub struct Irrelevant { | ^^^^^^^^^^ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error +error[E0210]: type parameter `Irrelevant` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/issue-97343.rs:4:23 + | +LL | pub struct Irrelevant { + | ^^^^^^^^^^ type parameter `Irrelevant` must be used as the type parameter for some local type + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local + = note: only traits defined in the current crate can be implemented for a type parameter -For more information about this error, try `rustc --explain E0109`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0109, E0210. +For more information about an error, try `rustc --explain E0109`. diff --git a/tests/ui/destructuring-assignment/struct_destructure_fail.stderr b/tests/ui/destructuring-assignment/struct_destructure_fail.stderr index ae7b3d1e5a92..57851ed417ea 100644 --- a/tests/ui/destructuring-assignment/struct_destructure_fail.stderr +++ b/tests/ui/destructuring-assignment/struct_destructure_fail.stderr @@ -12,11 +12,16 @@ error: functional record updates are not allowed in destructuring assignments LL | Struct { a, ..d } = Struct { a: 1, b: 2 }; | ^ help: consider removing the trailing pattern -error: base expression required after `..` +error[E0797]: base expression required after `..` --> $DIR/struct_destructure_fail.rs:15:19 | LL | Struct { a, .. }; - | ^ add a base expression here + | ^ + | +help: add a base expression here + | +LL | Struct { a, ../* expr */ }; + | ++++++++++ error[E0026]: struct `Struct` does not have a field named `c` --> $DIR/struct_destructure_fail.rs:10:20 @@ -41,5 +46,5 @@ LL | Struct { a, .. } = Struct { a: 1, b: 2 }; error: aborting due to 5 previous errors -Some errors have detailed explanations: E0026, E0027. +Some errors have detailed explanations: E0026, E0027, E0797. For more information about an error, try `rustc --explain E0026`. diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/auxiliary/other.rs b/tests/ui/diagnostic_namespace/on_unimplemented/auxiliary/other.rs new file mode 100644 index 000000000000..884bab2800a5 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_unimplemented/auxiliary/other.rs @@ -0,0 +1,8 @@ +#![feature(diagnostic_namespace)] + +#[diagnostic::on_unimplemented( + message = "Message", + note = "Note", + label = "label" +)] +pub trait Foo {} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs new file mode 100644 index 000000000000..b39375a09f36 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs @@ -0,0 +1,12 @@ +// aux-build:other.rs + +extern crate other; + +use other::Foo; + +fn take_foo(_: impl Foo) {} + +fn main() { + take_foo(()); + //~^ERROR Message +} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr new file mode 100644 index 000000000000..a9968538d0d3 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr @@ -0,0 +1,19 @@ +error[E0277]: Message + --> $DIR/error_is_shown_in_downstream_crates.rs:10:14 + | +LL | take_foo(()); + | -------- ^^ label + | | + | required by a bound introduced by this call + | + = help: the trait `Foo` is not implemented for `()` + = note: Note +note: required by a bound in `take_foo` + --> $DIR/error_is_shown_in_downstream_crates.rs:7:21 + | +LL | fn take_foo(_: impl Foo) {} + | ^^^ required by this bound in `take_foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/did_you_mean/bad-assoc-ty.rs b/tests/ui/did_you_mean/bad-assoc-ty.rs index f787c416c2d6..5a559b01ea28 100644 --- a/tests/ui/did_you_mean/bad-assoc-ty.rs +++ b/tests/ui/did_you_mean/bad-assoc-ty.rs @@ -71,6 +71,7 @@ enum N where F: Fn() -> _ { union O where F: Fn() -> _ { //~^ ERROR the placeholder `_` is not allowed within types on item signatures for unions foo: F, + //~^ ERROR must implement `Copy` } trait P where F: Fn() -> _ { diff --git a/tests/ui/did_you_mean/bad-assoc-ty.stderr b/tests/ui/did_you_mean/bad-assoc-ty.stderr index 5c0c7a0b94ff..3c474d19d1d0 100644 --- a/tests/ui/did_you_mean/bad-assoc-ty.stderr +++ b/tests/ui/did_you_mean/bad-assoc-ty.stderr @@ -299,7 +299,7 @@ LL | union O where F: Fn() -> T { | +++ ~ error[E0121]: the placeholder `_` is not allowed within types on item signatures for traits - --> $DIR/bad-assoc-ty.rs:76:29 + --> $DIR/bad-assoc-ty.rs:77:29 | LL | trait P where F: Fn() -> _ { | ^ not allowed in type signatures @@ -310,7 +310,7 @@ LL | trait P where F: Fn() -> T { | +++ ~ error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions - --> $DIR/bad-assoc-ty.rs:81:38 + --> $DIR/bad-assoc-ty.rs:82:38 | LL | fn foo(_: F) where F: Fn() -> _ {} | ^ not allowed in type signatures @@ -320,7 +320,19 @@ help: use type parameters instead LL | fn foo(_: F) where F: Fn() -> T {} | +++ ~ -error: aborting due to 28 previous errors; 1 warning emitted +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/bad-assoc-ty.rs:73:5 + | +LL | foo: F, + | ^^^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | foo: std::mem::ManuallyDrop, + | +++++++++++++++++++++++ + -Some errors have detailed explanations: E0121, E0223. +error: aborting due to 29 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0121, E0223, E0740. For more information about an error, try `rustc --explain E0121`. diff --git a/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.fixed b/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.fixed index 4963790c35de..eebe8d6e3f33 100644 --- a/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.fixed +++ b/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.fixed @@ -8,6 +8,7 @@ trait Foo: Sized { impl Foo for () { fn bar(i: i32, t: usize, s: &()) -> (usize, i32) { //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions + //~| ERROR type annotations needed (1, 2) } } diff --git a/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.rs b/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.rs index ddf39c9c8619..aa7510821af9 100644 --- a/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.rs +++ b/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.rs @@ -8,6 +8,7 @@ trait Foo: Sized { impl Foo for () { fn bar(i: _, t: _, s: _) -> _ { //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions + //~| ERROR type annotations needed (1, 2) } } diff --git a/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.stderr b/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.stderr index 2ca6436bb999..6f38def69981 100644 --- a/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.stderr +++ b/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.stderr @@ -13,6 +13,13 @@ help: try replacing `_` with the types in the corresponding trait method signatu LL | fn bar(i: i32, t: usize, s: &()) -> (usize, i32) { | ~~~ ~~~~~ ~~~ ~~~~~~~~~~~~ -error: aborting due to 1 previous error +error[E0282]: type annotations needed + --> $DIR/replace-impl-infer-ty-from-trait.rs:9:12 + | +LL | fn bar(i: _, t: _, s: _) -> _ { + | ^ cannot infer type -For more information about this error, try `rustc --explain E0121`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0121, E0282. +For more information about an error, try `rustc --explain E0121`. diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs index a99f260dde3b..52603744c45f 100644 --- a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs +++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs @@ -13,38 +13,39 @@ pub fn main() { d::println("created empty log"); test(&log); - assert_eq!(&log.borrow()[..], - [ - // created empty log - // +-- Make D(da_0, 0) - // | +-- Make D(de_1, 1) - // | | calling foo - // | | entered foo - // | | +-- Make D(de_2, 2) - // | | | +-- Make D(da_1, 3) - // | | | | +-- Make D(de_3, 4) - // | | | | | +-- Make D(de_4, 5) - 3, // | | | +-- Drop D(da_1, 3) - // | | | | | - 4, // | | | +-- Drop D(de_3, 4) - // | | | | - // | | | | eval tail of foo - // | | | +-- Make D(de_5, 6) - // | | | | +-- Make D(de_6, 7) - 5, // | | | | | +-- Drop D(de_4, 5) - // | | | | | - 2, // | | +-- Drop D(de_2, 2) - // | | | | - 6, // | | +-- Drop D(de_5, 6) - // | | | - 1, // | +-- Drop D(de_1, 1) - // | | - 0, // +-- Drop D(da_0, 0) - // | - // | result D(de_6, 7) - 7 // +-- Drop D(de_6, 7) - - ]); + assert_eq!( + &log.borrow()[..], + [ + // created empty log + // +-- Make D(da_0, 0) + // | +-- Make D(de_1, 1) + // | | calling foo + // | | entered foo + // | | +-- Make D(de_2, 2) + // | | | +-- Make D(da_1, 3) + // | | | | +-- Make D(de_3, 4) + // | | | | | +-- Make D(de_4, 5) + 3, // | | | +-- Drop D(da_1, 3) + // | | | | | + 4, // | | | +-- Drop D(de_3, 4) + // | | | | + // | | | | eval tail of foo + // | | | +-- Make D(de_5, 6) + // | | | | +-- Make D(de_6, 7) + 5, // | | | | | +-- Drop D(de_4, 5) + // | | | | | + 2, // | | +-- Drop D(de_2, 2) + // | | | | + 6, // | | +-- Drop D(de_5, 6) + // | | | + 1, // | +-- Drop D(de_1, 1) + // | | + 0, // +-- Drop D(da_0, 0) + // | + // | result D(de_6, 7) + 7 // +-- Drop D(de_6, 7) + ] + ); } fn test<'a>(log: d::Log<'a>) { @@ -57,13 +58,13 @@ fn test<'a>(log: d::Log<'a>) { fn foo<'a>(da0: D<'a>, de1: D<'a>) -> D<'a> { d::println("entered foo"); - let de2 = de1.incr(); // creates D(de_2, 2) + let de2 = de1.incr(); // creates D(de_2, 2) let de4 = { let _da1 = da0.incr(); // creates D(da_1, 3) - de2.incr().incr() // creates D(de_3, 4) and D(de_4, 5) + de2.incr().incr() // creates D(de_3, 4) and D(de_4, 5) }; d::println("eval tail of foo"); - de4.incr().incr() // creates D(de_5, 6) and D(de_6, 7) + de4.incr().incr() // creates D(de_5, 6) and D(de_6, 7) } // This module provides simultaneous printouts of the dynamic extents @@ -74,9 +75,9 @@ const PREF_INDENT: u32 = 16; pub mod d { #![allow(unused_parens)] + use std::cell::RefCell; use std::fmt; use std::mem; - use std::cell::RefCell; static mut counter: u32 = 0; static mut trails: u64 = 0; @@ -89,7 +90,8 @@ pub mod d { pub fn max_width() -> u32 { unsafe { - (mem::size_of_val(&trails)*8) as u32 + (mem::size_of_val(&trails) * 8) as u32 + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] } } @@ -123,7 +125,11 @@ pub mod d { } pub struct D<'a> { - name: &'static str, i: u32, uid: u32, trail: u32, log: Log<'a> + name: &'static str, + i: u32, + uid: u32, + trail: u32, + log: Log<'a>, } impl<'a> fmt::Display for D<'a> { @@ -139,9 +145,7 @@ pub mod d { let ctr = counter; counter += 1; trails |= (1 << trail); - let ret = D { - name: name, i: i, log: log, uid: ctr, trail: trail - }; + let ret = D { name: name, i: i, log: log, uid: ctr, trail: trail }; indent_println(trail, &format!("+-- Make {}", ret)); ret } @@ -153,7 +157,9 @@ pub mod d { impl<'a> Drop for D<'a> { fn drop(&mut self) { - unsafe { trails &= !(1 << self.trail); }; + unsafe { + trails &= !(1 << self.trail); + }; self.log.borrow_mut().push(self.uid); indent_println(self.trail, &format!("+-- Drop {}", self)); indent_println(::PREF_INDENT, ""); diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr b/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr new file mode 100644 index 000000000000..fd36ccbcbee4 --- /dev/null +++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr @@ -0,0 +1,17 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/issue-23338-ensure-param-drop-order.rs:93:31 + | +LL | (mem::size_of_val(&trails) * 8) as u32 + | ^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | (mem::size_of_val(addr_of!(trails)) * 8) as u32 + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/dyn-keyword/dyn-2021-edition-error.rs b/tests/ui/dyn-keyword/dyn-2021-edition-error.rs index 0f05d8753eaa..bc1bed8a9a4c 100644 --- a/tests/ui/dyn-keyword/dyn-2021-edition-error.rs +++ b/tests/ui/dyn-keyword/dyn-2021-edition-error.rs @@ -4,6 +4,7 @@ fn function(x: &SomeTrait, y: Box) { //~^ ERROR trait objects must include the `dyn` keyword //~| ERROR trait objects must include the `dyn` keyword let _x: &SomeTrait = todo!(); + //~^ ERROR trait objects must include the `dyn` keyword } trait SomeTrait {} diff --git a/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr b/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr index 08ee77116f0b..b39689afd1ca 100644 --- a/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr +++ b/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr @@ -20,6 +20,17 @@ help: add `dyn` keyword before this trait LL | fn function(x: &SomeTrait, y: Box) { | +++ -error: aborting due to 2 previous errors +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/dyn-2021-edition-error.rs:6:14 + | +LL | let _x: &SomeTrait = todo!(); + | ^^^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL | let _x: &dyn SomeTrait = todo!(); + | +++ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/dyn-star/union.rs b/tests/ui/dyn-star/union.rs new file mode 100644 index 000000000000..ad3a85a937ae --- /dev/null +++ b/tests/ui/dyn-star/union.rs @@ -0,0 +1,16 @@ +#![feature(dyn_star)] +//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes + +union Union { + x: usize, +} + +trait Trait {} +impl Trait for Union {} + +fn bar(_: dyn* Trait) {} + +fn main() { + bar(Union { x: 0usize }); + //~^ ERROR `Union` needs to have the same ABI as a pointer +} diff --git a/tests/ui/dyn-star/union.stderr b/tests/ui/dyn-star/union.stderr new file mode 100644 index 000000000000..906eb4f5163e --- /dev/null +++ b/tests/ui/dyn-star/union.stderr @@ -0,0 +1,20 @@ +warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/union.rs:1:12 + | +LL | #![feature(dyn_star)] + | ^^^^^^^^ + | + = note: see issue #102425 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: `Union` needs to have the same ABI as a pointer + --> $DIR/union.rs:14:9 + | +LL | bar(Union { x: 0usize }); + | ^^^^^^^^^^^^^^^^^^^ `Union` needs to be a pointer-like type + | + = help: the trait `PointerLike` is not implemented for `Union` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/editions/auxiliary/edition-kw-macro-2015.rs b/tests/ui/editions/auxiliary/edition-kw-macro-2015.rs index 7cfd128f2bfe..a4a2b156e139 100644 --- a/tests/ui/editions/auxiliary/edition-kw-macro-2015.rs +++ b/tests/ui/editions/auxiliary/edition-kw-macro-2015.rs @@ -26,3 +26,8 @@ macro_rules! consumes_async_raw { macro_rules! passes_ident { ($i: ident) => ($i) } + +#[macro_export] +macro_rules! passes_tt { + ($i: tt) => ($i) +} diff --git a/tests/ui/editions/auxiliary/edition-kw-macro-2018.rs b/tests/ui/editions/auxiliary/edition-kw-macro-2018.rs index d07c0218db3f..02db38103d2a 100644 --- a/tests/ui/editions/auxiliary/edition-kw-macro-2018.rs +++ b/tests/ui/editions/auxiliary/edition-kw-macro-2018.rs @@ -26,3 +26,8 @@ macro_rules! consumes_async_raw { macro_rules! passes_ident { ($i: ident) => ($i) } + +#[macro_export] +macro_rules! passes_tt { + ($i: tt) => ($i) +} diff --git a/tests/ui/editions/edition-keywords-2015-2015-parsing.rs b/tests/ui/editions/edition-keywords-2015-2015-parsing.rs index d1752a7ec71d..3574bc815155 100644 --- a/tests/ui/editions/edition-keywords-2015-2015-parsing.rs +++ b/tests/ui/editions/edition-keywords-2015-2015-parsing.rs @@ -19,6 +19,8 @@ pub fn check_async() { if passes_ident!(async) == 1 {} // OK if passes_ident!(r#async) == 1 {} // OK + if passes_tt!(async) == 1 {} // OK + if passes_tt!(r#async) == 1 {} // OK module::async(); // OK module::r#async(); // OK } diff --git a/tests/ui/editions/edition-keywords-2015-2015.rs b/tests/ui/editions/edition-keywords-2015-2015.rs index 943d203b806f..77a2cb2e6dea 100644 --- a/tests/ui/editions/edition-keywords-2015-2015.rs +++ b/tests/ui/editions/edition-keywords-2015-2015.rs @@ -20,6 +20,8 @@ pub fn check_async() { if passes_ident!(async) == 1 {} // OK if passes_ident!(r#async) == 1 {} // OK + if passes_tt!(async) == 1 {} // OK + if passes_tt!(r#async) == 1 {} // OK one_async::async(); // OK one_async::r#async(); // OK two_async::async(); // OK diff --git a/tests/ui/editions/edition-keywords-2015-2018-parsing.rs b/tests/ui/editions/edition-keywords-2015-2018-parsing.rs index 44455f43856c..49f8562a6b19 100644 --- a/tests/ui/editions/edition-keywords-2015-2018-parsing.rs +++ b/tests/ui/editions/edition-keywords-2015-2018-parsing.rs @@ -19,6 +19,8 @@ pub fn check_async() { if passes_ident!(async) == 1 {} // OK if passes_ident!(r#async) == 1 {} // OK + if passes_tt!(async) == 1 {} // OK + if passes_tt!(r#async) == 1 {} // OK module::async(); // OK module::r#async(); // OK } diff --git a/tests/ui/editions/edition-keywords-2015-2018.rs b/tests/ui/editions/edition-keywords-2015-2018.rs index 8c3397c951db..a431a06bd104 100644 --- a/tests/ui/editions/edition-keywords-2015-2018.rs +++ b/tests/ui/editions/edition-keywords-2015-2018.rs @@ -20,6 +20,8 @@ pub fn check_async() { if passes_ident!(async) == 1 {} // OK if passes_ident!(r#async) == 1 {} // OK + if passes_tt!(async) == 1 {} // OK + if passes_tt!(r#async) == 1 {} // OK // one_async::async(); // ERROR, unresolved name // one_async::r#async(); // ERROR, unresolved name two_async::async(); // OK diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs index d5ed9fb9a285..8472430361fb 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs @@ -21,8 +21,10 @@ pub fn check_async() { r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` r#async = consumes_async_raw!(r#async); // OK - if passes_ident!(async) == 1 {} + if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved if passes_ident!(r#async) == 1 {} // OK + if passes_tt!(async) == 1 {} //~ ERROR macro expansion ends with an incomplete expression + if passes_tt!(r#async) == 1 {} // OK module::async(); //~ ERROR expected identifier, found keyword `async` module::r#async(); // OK diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr index 1a4a94e97332..42db75f66597 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -10,7 +10,7 @@ LL | let mut r#async = 1; | ++ error: expected identifier, found keyword `async` - --> $DIR/edition-keywords-2018-2015-parsing.rs:26:13 + --> $DIR/edition-keywords-2018-2015-parsing.rs:28:13 | LL | module::async(); | ^^^^^ expected identifier, found keyword @@ -52,17 +52,23 @@ LL | ($i: ident) => ($i) | ::: $DIR/edition-keywords-2018-2015-parsing.rs:24:8 | -LL | if passes_ident!(async) == 1 {} +LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved | -------------------- in this macro invocation +error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` + --> $DIR/edition-keywords-2018-2015-parsing.rs:26:24 + | +LL | if passes_tt!(async) == 1 {} + | ^ expected one of `move`, `|`, or `||` + error[E0308]: mismatched types - --> $DIR/edition-keywords-2018-2015-parsing.rs:29:33 + --> $DIR/edition-keywords-2018-2015-parsing.rs:31:33 | LL | let _recovery_witness: () = 0; | -- ^ expected `()`, found integer | | | expected due to this -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/editions/edition-keywords-2018-2015.rs b/tests/ui/editions/edition-keywords-2018-2015.rs index 2cb2dfb18a02..4a02f8671721 100644 --- a/tests/ui/editions/edition-keywords-2018-2015.rs +++ b/tests/ui/editions/edition-keywords-2018-2015.rs @@ -18,6 +18,8 @@ pub fn check_async() { // if passes_ident!(async) == 1 {} // ERROR, reserved if passes_ident!(r#async) == 1 {} // OK + // if passes_tt!(async) == 1 {} // ERROR, reserved + if passes_tt!(r#async) == 1 {} // OK // one_async::async(); // ERROR, reserved one_async::r#async(); // OK // two_async::async(); // ERROR, reserved diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs index 044ab249f2c2..c0d8927d0597 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs @@ -12,6 +12,13 @@ mod module { pub fn r#async() {} } +macro_rules! local_passes_ident { + ($i: ident) => ($i) //~ ERROR macro expansion ends with an incomplete expression +} +macro_rules! local_passes_tt { + ($i: tt) => ($i) //~ ERROR macro expansion ends with an incomplete expression +} + pub fn check_async() { let mut async = 1; //~ ERROR expected identifier, found keyword `async` let mut r#async = 1; // OK @@ -21,8 +28,14 @@ pub fn check_async() { r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` r#async = consumes_async_raw!(r#async); // OK - if passes_ident!(async) == 1 {} + if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved if passes_ident!(r#async) == 1 {} // OK + if passes_tt!(async) == 1 {} //~ ERROR macro expansion ends with an incomplete expression + if passes_tt!(r#async) == 1 {} // OK + if local_passes_ident!(async) == 1 {} // Error reported above in the macro + if local_passes_ident!(r#async) == 1 {} // OK + if local_passes_tt!(async) == 1 {} // Error reported above in the macro + if local_passes_tt!(r#async) == 1 {} // OK module::async(); //~ ERROR expected identifier, found keyword `async` module::r#async(); // OK diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr index 19eb7ac98239..6f08cff433b1 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -1,5 +1,5 @@ error: expected identifier, found keyword `async` - --> $DIR/edition-keywords-2018-2018-parsing.rs:16:13 + --> $DIR/edition-keywords-2018-2018-parsing.rs:23:13 | LL | let mut async = 1; | ^^^^^ expected identifier, found keyword @@ -10,7 +10,7 @@ LL | let mut r#async = 1; | ++ error: expected identifier, found keyword `async` - --> $DIR/edition-keywords-2018-2018-parsing.rs:26:13 + --> $DIR/edition-keywords-2018-2018-parsing.rs:39:13 | LL | module::async(); | ^^^^^ expected identifier, found keyword @@ -21,7 +21,7 @@ LL | module::r#async(); | ++ error: no rules expected the token `r#async` - --> $DIR/edition-keywords-2018-2018-parsing.rs:20:31 + --> $DIR/edition-keywords-2018-2018-parsing.rs:27:31 | LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call @@ -33,7 +33,7 @@ LL | (async) => (1) | ^^^^^ error: no rules expected the token `async` - --> $DIR/edition-keywords-2018-2018-parsing.rs:21:35 + --> $DIR/edition-keywords-2018-2018-parsing.rs:28:35 | LL | r#async = consumes_async_raw!(async); | ^^^^^ no rules expected this token in macro call @@ -50,19 +50,37 @@ error: macro expansion ends with an incomplete expression: expected one of `move LL | ($i: ident) => ($i) | ^ expected one of `move`, `|`, or `||` | - ::: $DIR/edition-keywords-2018-2018-parsing.rs:24:8 + ::: $DIR/edition-keywords-2018-2018-parsing.rs:31:8 | -LL | if passes_ident!(async) == 1 {} +LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved | -------------------- in this macro invocation +error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` + --> $DIR/edition-keywords-2018-2018-parsing.rs:33:24 + | +LL | if passes_tt!(async) == 1 {} + | ^ expected one of `move`, `|`, or `||` + +error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` + --> $DIR/edition-keywords-2018-2018-parsing.rs:16:23 + | +LL | ($i: ident) => ($i) + | ^ expected one of `move`, `|`, or `||` + +error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` + --> $DIR/edition-keywords-2018-2018-parsing.rs:19:20 + | +LL | ($i: tt) => ($i) + | ^ expected one of `move`, `|`, or `||` + error[E0308]: mismatched types - --> $DIR/edition-keywords-2018-2018-parsing.rs:29:33 + --> $DIR/edition-keywords-2018-2018-parsing.rs:42:33 | LL | let _recovery_witness: () = 0; | -- ^ expected `()`, found integer | | | expected due to this -error: aborting due to 6 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/editions/edition-keywords-2018-2018.rs b/tests/ui/editions/edition-keywords-2018-2018.rs index 5043440aa167..e72943261375 100644 --- a/tests/ui/editions/edition-keywords-2018-2018.rs +++ b/tests/ui/editions/edition-keywords-2018-2018.rs @@ -18,6 +18,8 @@ pub fn check_async() { // if passes_ident!(async) == 1 {} // ERROR, reserved if passes_ident!(r#async) == 1 {} // OK + // if passes_tt!(async) == 1 {} // ERROR, reserved + if passes_tt!(r#async) == 1 {} // OK // one_async::async(); // ERROR, reserved // one_async::r#async(); // ERROR, unresolved name // two_async::async(); // ERROR, reserved diff --git a/tests/ui/error-codes/E0017.rs b/tests/ui/error-codes/E0017.rs index c211ad1a2f8f..9d3433fa543f 100644 --- a/tests/ui/error-codes/E0017.rs +++ b/tests/ui/error-codes/E0017.rs @@ -3,12 +3,16 @@ const C: i32 = 2; static mut M: i32 = 3; const CR: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed - //~| WARN taking a mutable +//~| WARN taking a mutable + static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 - //~| ERROR cannot borrow - //~| ERROR mutable references are not allowed +//~| ERROR cannot borrow +//~| ERROR mutable references are not allowed static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed - //~| WARN taking a mutable +//~| WARN taking a mutable + static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR mutable references are not +//~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + fn main() {} diff --git a/tests/ui/error-codes/E0017.stderr b/tests/ui/error-codes/E0017.stderr index 6e48f9582f1c..ea6055da1c1f 100644 --- a/tests/ui/error-codes/E0017.stderr +++ b/tests/ui/error-codes/E0017.stderr @@ -1,3 +1,18 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/E0017.rs:15:52 + | +LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { addr_of_mut!(M) }; + | ~~~~~~~~~~~~~~~ + warning: taking a mutable reference to a `const` item --> $DIR/E0017.rs:5:30 | @@ -20,7 +35,7 @@ LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ error[E0658]: mutation through a reference is not allowed in statics - --> $DIR/E0017.rs:7:39 + --> $DIR/E0017.rs:8:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ @@ -29,19 +44,19 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:7:39 + --> $DIR/E0017.rs:8:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0017.rs:7:39 + --> $DIR/E0017.rs:8:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable warning: taking a mutable reference to a `const` item - --> $DIR/E0017.rs:11:38 + --> $DIR/E0017.rs:12:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ @@ -55,18 +70,18 @@ LL | const C: i32 = 2; | ^^^^^^^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:11:38 + --> $DIR/E0017.rs:12:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:13:52 + --> $DIR/E0017.rs:15:52 | LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; | ^^^^^^ -error: aborting due to 6 previous errors; 2 warnings emitted +error: aborting due to 6 previous errors; 3 warnings emitted Some errors have detailed explanations: E0596, E0658, E0764. For more information about an error, try `rustc --explain E0596`. diff --git a/tests/ui/error-codes/E0227.rs b/tests/ui/error-codes/E0227.rs index 0f0a781d2f9d..4dd4da55fa32 100644 --- a/tests/ui/error-codes/E0227.rs +++ b/tests/ui/error-codes/E0227.rs @@ -6,6 +6,7 @@ trait FooBar<'foo, 'bar>: Foo<'foo> + Bar<'bar> {} struct Baz<'foo, 'bar> { baz: dyn FooBar<'foo, 'bar>, //~^ ERROR ambiguous lifetime bound, explicit lifetime bound required + //~| ERROR lifetime bound not satisfied } fn main() { diff --git a/tests/ui/error-codes/E0227.stderr b/tests/ui/error-codes/E0227.stderr index c77a2e98af70..6338034a022a 100644 --- a/tests/ui/error-codes/E0227.stderr +++ b/tests/ui/error-codes/E0227.stderr @@ -4,6 +4,24 @@ error[E0227]: ambiguous lifetime bound, explicit lifetime bound required LL | baz: dyn FooBar<'foo, 'bar>, | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error[E0478]: lifetime bound not satisfied + --> $DIR/E0227.rs:7:10 + | +LL | baz: dyn FooBar<'foo, 'bar>, + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'bar` as defined here + --> $DIR/E0227.rs:6:18 + | +LL | struct Baz<'foo, 'bar> { + | ^^^^ +note: but lifetime parameter must outlive the lifetime `'foo` as defined here + --> $DIR/E0227.rs:6:12 + | +LL | struct Baz<'foo, 'bar> { + | ^^^^ -For more information about this error, try `rustc --explain E0227`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0227, E0478. +For more information about an error, try `rustc --explain E0227`. diff --git a/tests/ui/error-codes/E0229.rs b/tests/ui/error-codes/E0229.rs index 4c1934107a6d..b7cdb1737b00 100644 --- a/tests/ui/error-codes/E0229.rs +++ b/tests/ui/error-codes/E0229.rs @@ -12,6 +12,9 @@ impl Foo for isize { fn baz(x: &>::A) {} //~^ ERROR associated type bindings are not allowed here [E0229] +//~| ERROR associated type bindings are not allowed here [E0229] +//~| ERROR associated type bindings are not allowed here [E0229] +//~| ERROR the trait bound `I: Foo` is not satisfied fn main() { } diff --git a/tests/ui/error-codes/E0229.stderr b/tests/ui/error-codes/E0229.stderr index e981fb91ce89..a7a2904bb898 100644 --- a/tests/ui/error-codes/E0229.stderr +++ b/tests/ui/error-codes/E0229.stderr @@ -4,6 +4,34 @@ error[E0229]: associated type bindings are not allowed here LL | fn baz(x: &>::A) {} | ^^^^^ associated type not allowed here -error: aborting due to 1 previous error +error[E0229]: associated type bindings are not allowed here + --> $DIR/E0229.rs:13:25 + | +LL | fn baz(x: &>::A) {} + | ^^^^^ associated type not allowed here + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -For more information about this error, try `rustc --explain E0229`. +error[E0229]: associated type bindings are not allowed here + --> $DIR/E0229.rs:13:25 + | +LL | fn baz(x: &>::A) {} + | ^^^^^ associated type not allowed here + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: the trait bound `I: Foo` is not satisfied + --> $DIR/E0229.rs:13:15 + | +LL | fn baz(x: &>::A) {} + | ^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `I` + | +help: consider restricting type parameter `I` + | +LL | fn baz(x: &>::A) {} + | +++++ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0229, E0277. +For more information about an error, try `rustc --explain E0229`. diff --git a/tests/ui/error-codes/E0719.rs b/tests/ui/error-codes/E0719.rs index cbf1bb219a07..0ea6d19000bd 100644 --- a/tests/ui/error-codes/E0719.rs +++ b/tests/ui/error-codes/E0719.rs @@ -1,6 +1,7 @@ trait Foo: Iterator {} //~^ ERROR is already specified //~| ERROR is already specified +//~| ERROR is already specified type Unit = (); @@ -11,5 +12,6 @@ fn test() -> Box> { fn main() { let _: &dyn Iterator; + //~^ ERROR already specified test(); } diff --git a/tests/ui/error-codes/E0719.stderr b/tests/ui/error-codes/E0719.stderr index 00aea97139a7..f048a8aabd44 100644 --- a/tests/ui/error-codes/E0719.stderr +++ b/tests/ui/error-codes/E0719.stderr @@ -17,13 +17,31 @@ LL | trait Foo: Iterator {} = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/E0719.rs:7:42 + --> $DIR/E0719.rs:8:42 | LL | fn test() -> Box> { | --------- ^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: aborting due to 3 previous errors +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/E0719.rs:1:33 + | +LL | trait Foo: Iterator {} + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/E0719.rs:14:38 + | +LL | let _: &dyn Iterator; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0719`. diff --git a/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs b/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs index 233120c92f38..24fc512dfbf0 100644 --- a/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs +++ b/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs @@ -22,7 +22,7 @@ //[thin]compile-flags: -C lto=thin //[fat]compile-flags: -C lto=fat -#![feature(core_panic)] +#![feature(panic_internals)] // (For some reason, reproducing the LTO issue requires pulling in std // explicitly this way.) diff --git a/tests/ui/feature-gates/feature-gate-associated_type_bounds.rs b/tests/ui/feature-gates/feature-gate-associated_type_bounds.rs index 152c7a8de66a..073599edad7b 100644 --- a/tests/ui/feature-gates/feature-gate-associated_type_bounds.rs +++ b/tests/ui/feature-gates/feature-gate-associated_type_bounds.rs @@ -54,20 +54,20 @@ fn _rpit_dyn() -> Box> { Box::new(S1) } const _cdef: impl Tr1 = S1; //~^ ERROR associated type bounds are unstable -//~| ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~| ERROR `impl Trait` is not allowed in const types // FIXME: uncomment when `impl_trait_in_bindings` feature is fixed. // const _cdef_dyn: &dyn Tr1 = &S1; static _sdef: impl Tr1 = S1; //~^ ERROR associated type bounds are unstable -//~| ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~| ERROR `impl Trait` is not allowed in static types // FIXME: uncomment when `impl_trait_in_bindings` feature is fixed. // static _sdef_dyn: &dyn Tr1 = &S1; fn main() { let _: impl Tr1 = S1; //~^ ERROR associated type bounds are unstable - //~| ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~| ERROR `impl Trait` is not allowed in the type of variable bindings // FIXME: uncomment when `impl_trait_in_bindings` feature is fixed. // let _: &dyn Tr1 = &S1; } diff --git a/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr b/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr index f2bceda9bea7..4a643d31259f 100644 --- a/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr @@ -115,23 +115,29 @@ LL | let _: impl Tr1 = S1; = note: see issue #52662 for more information = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in const types +error[E0562]: `impl Trait` is not allowed in const types --> $DIR/feature-gate-associated_type_bounds.rs:55:14 | LL | const _cdef: impl Tr1 = S1; | ^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in const types +error[E0562]: `impl Trait` is not allowed in static types --> $DIR/feature-gate-associated_type_bounds.rs:61:15 | LL | static _sdef: impl Tr1 = S1; | ^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in variable bindings +error[E0562]: `impl Trait` is not allowed in the type of variable bindings --> $DIR/feature-gate-associated_type_bounds.rs:68:12 | LL | let _: impl Tr1 = S1; | ^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0277]: the trait bound `<::A as Iterator>::Item: Copy` is not satisfied --> $DIR/feature-gate-associated_type_bounds.rs:12:28 diff --git a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.rs b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.rs index de0487cdb208..2c130664e9a1 100644 --- a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.rs +++ b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.rs @@ -5,6 +5,7 @@ trait Foo { impl Foo for () { type Bar = impl std::fmt::Debug; //~^ ERROR: `impl Trait` in associated types is unstable + //~| ERROR: unconstrained opaque type } struct Mop; @@ -13,6 +14,7 @@ impl Mop { type Bop = impl std::fmt::Debug; //~^ ERROR: `impl Trait` in associated types is unstable //~| ERROR: inherent associated types are unstable + //~| ERROR: unconstrained opaque type } fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr index 9a1ded968225..420363ced6f7 100644 --- a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr +++ b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr @@ -8,7 +8,7 @@ LL | type Bar = impl std::fmt::Debug; = help: add `#![feature(impl_trait_in_assoc_type)]` to the crate attributes to enable error[E0658]: `impl Trait` in associated types is unstable - --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:13:16 + --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:14:16 | LL | type Bop = impl std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | type Bop = impl std::fmt::Debug; = help: add `#![feature(impl_trait_in_assoc_type)]` to the crate attributes to enable error[E0658]: inherent associated types are unstable - --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:13:5 + --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:14:5 | LL | type Bop = impl std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,6 +25,22 @@ LL | type Bop = impl std::fmt::Debug; = note: see issue #8995 for more information = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable -error: aborting due to 3 previous errors +error: unconstrained opaque type + --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:6:16 + | +LL | type Bar = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `Bar` must be used in combination with a concrete type within the same impl + +error: unconstrained opaque type + --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:14:16 + | +LL | type Bop = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `Bop` must be used in combination with a concrete type within the same impl + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.rs b/tests/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.rs index 1b9530fa82f3..c75eabd6ac83 100644 --- a/tests/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.rs +++ b/tests/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.rs @@ -1,6 +1,6 @@ fn f() -> impl Fn() -> impl Sized { || () } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait return +//~^ ERROR `impl Trait` is not allowed in the return type of `Fn` trait bounds fn g() -> &'static dyn Fn() -> impl Sized { &|| () } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait return +//~^ ERROR `impl Trait` is not allowed in the return type of `Fn` trait bounds fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.stderr b/tests/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.stderr index f0c0cd040e03..dacf1ca4c37c 100644 --- a/tests/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.stderr +++ b/tests/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.stderr @@ -1,18 +1,20 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait return types +error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds --> $DIR/feature-gate-impl_trait_in_fn_trait_return.rs:1:24 | LL | fn f() -> impl Fn() -> impl Sized { || () } | ^^^^^^^^^^ | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods = note: see issue #99697 for more information = help: add `#![feature(impl_trait_in_fn_trait_return)]` to the crate attributes to enable -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait return types +error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds --> $DIR/feature-gate-impl_trait_in_fn_trait_return.rs:3:32 | LL | fn g() -> &'static dyn Fn() -> impl Sized { &|| () } | ^^^^^^^^^^ | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods = note: see issue #99697 for more information = help: add `#![feature(impl_trait_in_fn_trait_return)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.rs b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.rs index eecf2046ccbe..b8ce9c85b727 100644 --- a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.rs +++ b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.rs @@ -7,29 +7,35 @@ struct Foo; impl Fn<()> for Foo { -//~^ ERROR the precise format of `Fn`-family traits' type parameters is subject to change -//~| ERROR manual implementations of `Fn` are experimental + //~^ ERROR the precise format of `Fn`-family traits' type parameters is subject to change + //~| ERROR manual implementations of `Fn` are experimental + //~| ERROR expected a `FnMut()` closure, found `Foo` extern "rust-call" fn call(self, args: ()) -> () {} //~^ ERROR rust-call ABI is subject to change + //~| ERROR `call` has an incompatible type for trait } struct Foo1; impl FnOnce() for Foo1 { -//~^ ERROR associated type bindings are not allowed here -//~| ERROR manual implementations of `FnOnce` are experimental + //~^ ERROR associated type bindings are not allowed here + //~| ERROR manual implementations of `FnOnce` are experimental + //~| ERROR not all trait items implemented extern "rust-call" fn call_once(self, args: ()) -> () {} //~^ ERROR rust-call ABI is subject to change } struct Bar; impl FnMut<()> for Bar { -//~^ ERROR the precise format of `Fn`-family traits' type parameters is subject to change -//~| ERROR manual implementations of `FnMut` are experimental + //~^ ERROR the precise format of `Fn`-family traits' type parameters is subject to change + //~| ERROR manual implementations of `FnMut` are experimental + //~| ERROR expected a `FnOnce()` closure, found `Bar` extern "rust-call" fn call_mut(&self, args: ()) -> () {} //~^ ERROR rust-call ABI is subject to change + //~| ERROR incompatible type for trait } struct Baz; impl FnOnce<()> for Baz { -//~^ ERROR the precise format of `Fn`-family traits' type parameters is subject to change -//~| ERROR manual implementations of `FnOnce` are experimental + //~^ ERROR the precise format of `Fn`-family traits' type parameters is subject to change + //~| ERROR manual implementations of `FnOnce` are experimental + //~| ERROR not all trait items implemented extern "rust-call" fn call_once(&self, args: ()) -> () {} //~^ ERROR rust-call ABI is subject to change } diff --git a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr index b1613f638d30..b417dfb506ad 100644 --- a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr +++ b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr @@ -1,5 +1,5 @@ error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:12:12 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:13:12 | LL | extern "rust-call" fn call(self, args: ()) -> () {} | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | extern "rust-call" fn call(self, args: ()) -> () {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:19:12 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:22:12 | LL | extern "rust-call" fn call_once(self, args: ()) -> () {} | ^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | extern "rust-call" fn call_once(self, args: ()) -> () {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:26:12 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:12 | LL | extern "rust-call" fn call_mut(&self, args: ()) -> () {} | ^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | extern "rust-call" fn call_mut(&self, args: ()) -> () {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:33:12 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:39:12 | LL | extern "rust-call" fn call_once(&self, args: ()) -> () {} | ^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | impl Fn<()> for Foo { = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0183]: manual implementations of `FnOnce` are experimental - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:6 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:18:6 | LL | impl FnOnce() for Foo1 { | ^^^^^^^^ manual implementations of `FnOnce` are experimental @@ -60,19 +60,19 @@ LL | impl FnOnce() for Foo1 { = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0229]: associated type bindings are not allowed here - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:6 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:18:6 | LL | impl FnOnce() for Foo1 { | ^^^^^^^^ associated type not allowed here | help: parenthesized trait syntax expands to `FnOnce<(), Output=()>` - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:6 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:18:6 | LL | impl FnOnce() for Foo1 { | ^^^^^^^^ error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:6 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:26:6 | LL | impl FnMut<()> for Bar { | ^^^^^^^^^ @@ -81,7 +81,7 @@ LL | impl FnMut<()> for Bar { = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0183]: manual implementations of `FnMut` are experimental - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:6 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:26:6 | LL | impl FnMut<()> for Bar { | ^^^^^^^^^ manual implementations of `FnMut` are experimental @@ -89,7 +89,7 @@ LL | impl FnMut<()> for Bar { = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:6 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:35:6 | LL | impl FnOnce<()> for Baz { | ^^^^^^^^^^ @@ -98,14 +98,76 @@ LL | impl FnOnce<()> for Baz { = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0183]: manual implementations of `FnOnce` are experimental - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:6 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:35:6 | LL | impl FnOnce<()> for Baz { | ^^^^^^^^^^ manual implementations of `FnOnce` are experimental | = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable -error: aborting due to 12 previous errors +error[E0277]: expected a `FnMut()` closure, found `Foo` + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:17 + | +LL | impl Fn<()> for Foo { + | ^^^ expected an `FnMut()` closure, found `Foo` + | + = help: the trait `FnMut<()>` is not implemented for `Foo` + = note: wrap the `Foo` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `Fn` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL -Some errors have detailed explanations: E0183, E0229, E0658. -For more information about an error, try `rustc --explain E0183`. +error[E0053]: method `call` has an incompatible type for trait + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:13:32 + | +LL | extern "rust-call" fn call(self, args: ()) -> () {} + | ^^^^ + | | + | expected `&Foo`, found `Foo` + | help: change the self-receiver type to match the trait: `&self` + | + = note: expected signature `extern "rust-call" fn(&Foo, ()) -> _` + found signature `extern "rust-call" fn(Foo, ())` + +error[E0046]: not all trait items implemented, missing: `Output` + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:18:1 + | +LL | impl FnOnce() for Foo1 { + | ^^^^^^^^^^^^^^^^^^^^^^ missing `Output` in implementation + | + = help: implement the missing item: `type Output = /* Type */;` + +error[E0277]: expected a `FnOnce()` closure, found `Bar` + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:26:20 + | +LL | impl FnMut<()> for Bar { + | ^^^ expected an `FnOnce()` closure, found `Bar` + | + = help: the trait `FnOnce<()>` is not implemented for `Bar` + = note: wrap the `Bar` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `FnMut` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL + +error[E0053]: method `call_mut` has an incompatible type for trait + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:36 + | +LL | extern "rust-call" fn call_mut(&self, args: ()) -> () {} + | ^^^^^ + | | + | types differ in mutability + | help: change the self-receiver type to match the trait: `&mut self` + | + = note: expected signature `extern "rust-call" fn(&mut Bar, ()) -> _` + found signature `extern "rust-call" fn(&Bar, ())` + +error[E0046]: not all trait items implemented, missing: `Output` + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:35:1 + | +LL | impl FnOnce<()> for Baz { + | ^^^^^^^^^^^^^^^^^^^^^^^ missing `Output` in implementation + | + = help: implement the missing item: `type Output = /* Type */;` + +error: aborting due to 18 previous errors + +Some errors have detailed explanations: E0046, E0053, E0183, E0229, E0277, E0658. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/fmt/format-string-wrong-order.rs b/tests/ui/fmt/format-string-wrong-order.rs index 0bad54023965..da775be3ffd6 100644 --- a/tests/ui/fmt/format-string-wrong-order.rs +++ b/tests/ui/fmt/format-string-wrong-order.rs @@ -12,4 +12,10 @@ fn main() { //~^ ERROR invalid format string: expected `'}'`, found `'?'` format!("{?:#?}", bar); //~^ ERROR invalid format string: expected format parameter to occur after `:` + format!("Hello {<5:}!", "x"); + //~^ ERROR invalid format string: expected format parameter to occur after `:` + format!("Hello {^5:}!", "x"); + //~^ ERROR invalid format string: expected format parameter to occur after `:` + format!("Hello {>5:}!", "x"); + //~^ ERROR invalid format string: expected format parameter to occur after `:` } diff --git a/tests/ui/fmt/format-string-wrong-order.stderr b/tests/ui/fmt/format-string-wrong-order.stderr index 0a2e04026d97..3ef07720c153 100644 --- a/tests/ui/fmt/format-string-wrong-order.stderr +++ b/tests/ui/fmt/format-string-wrong-order.stderr @@ -50,5 +50,23 @@ LL | format!("{?:#?}", bar); | = note: `?` comes after `:`, try `:?` instead -error: aborting due to 6 previous errors +error: invalid format string: expected format parameter to occur after `:` + --> $DIR/format-string-wrong-order.rs:15:21 + | +LL | format!("Hello {<5:}!", "x"); + | ^ expected `<` to occur after `:` in format string + +error: invalid format string: expected format parameter to occur after `:` + --> $DIR/format-string-wrong-order.rs:17:21 + | +LL | format!("Hello {^5:}!", "x"); + | ^ expected `^` to occur after `:` in format string + +error: invalid format string: expected format parameter to occur after `:` + --> $DIR/format-string-wrong-order.rs:19:21 + | +LL | format!("Hello {>5:}!", "x"); + | ^ expected `>` to occur after `:` in format string + +error: aborting due to 9 previous errors diff --git a/tests/ui/fn/issue-39259.rs b/tests/ui/fn/issue-39259.rs index 5872f1007b01..16983b652fc8 100644 --- a/tests/ui/fn/issue-39259.rs +++ b/tests/ui/fn/issue-39259.rs @@ -4,8 +4,10 @@ struct S; impl Fn(u32) -> u32 for S { -//~^ ERROR associated type bindings are not allowed here [E0229] + //~^ ERROR associated type bindings are not allowed here [E0229] + //~| ERROR expected a `FnMut(u32)` closure, found `S` fn call(&self) -> u32 { + //~^ ERROR method `call` has 1 parameter but the declaration in trait `call` has 2 5 } } diff --git a/tests/ui/fn/issue-39259.stderr b/tests/ui/fn/issue-39259.stderr index bd102e581356..47150a3c155c 100644 --- a/tests/ui/fn/issue-39259.stderr +++ b/tests/ui/fn/issue-39259.stderr @@ -10,6 +10,25 @@ help: parenthesized trait syntax expands to `Fn<(u32,), Output=u32>` LL | impl Fn(u32) -> u32 for S { | ^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error[E0277]: expected a `FnMut(u32)` closure, found `S` + --> $DIR/issue-39259.rs:6:25 + | +LL | impl Fn(u32) -> u32 for S { + | ^ expected an `FnMut(u32)` closure, found `S` + | + = help: the trait `FnMut<(u32,)>` is not implemented for `S` +note: required by a bound in `Fn` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL -For more information about this error, try `rustc --explain E0229`. +error[E0050]: method `call` has 1 parameter but the declaration in trait `call` has 2 + --> $DIR/issue-39259.rs:9:13 + | +LL | fn call(&self) -> u32 { + | ^^^^^ expected 2 parameters, found 1 + | + = note: `call` from trait: `extern "rust-call" fn(&Self, Args) -> >::Output` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0050, E0229, E0277. +For more information about an error, try `rustc --explain E0050`. diff --git a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs index 86b164ba7d8a..1a4678c7e70b 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs +++ b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs @@ -6,4 +6,7 @@ fn main() { fn _f(arg : Box X = &'a [u32]>>) {} //~^ ERROR: use of undeclared lifetime name `'x` //~| ERROR: binding for associated type `Y` references lifetime + //~| ERROR: binding for associated type `Y` references lifetime + //~| ERROR: binding for associated type `Y` references lifetime + //~| ERROR: the trait `X` cannot be made into an object } diff --git a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr index b77f10084c92..4a56b20eb59b 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr +++ b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr @@ -20,7 +20,38 @@ error[E0582]: binding for associated type `Y` references lifetime `'a`, which do LL | fn _f(arg : Box X = &'a [u32]>>) {} | ^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error[E0582]: binding for associated type `Y` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:6:33 + | +LL | fn _f(arg : Box X = &'a [u32]>>) {} + | ^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -Some errors have detailed explanations: E0261, E0582. -For more information about an error, try `rustc --explain E0261`. +error[E0582]: binding for associated type `Y` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:6:33 + | +LL | fn _f(arg : Box X = &'a [u32]>>) {} + | ^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0038]: the trait `X` cannot be made into an object + --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:6:19 + | +LL | fn _f(arg : Box X = &'a [u32]>>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:2:8 + | +LL | trait X { + | - this trait cannot be made into an object... +LL | type Y<'x>; + | ^ ...because it contains the generic associated type `Y` + = help: consider moving `Y` to another trait + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0038, E0261, E0582. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs index 83b86f04a957..285493132b64 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs +++ b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs @@ -4,10 +4,11 @@ trait X { fn foo<'a>(t : Self::Y<'a>) -> Self::Y<'a> { t } } -impl X for T { +impl X for T { //~ ERROR: not all trait items implemented fn foo<'a, T1: X>(t : T1) -> T1::Y<'a> { //~^ ERROR missing generics for associated type //~^^ ERROR missing generics for associated type + //~| ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters t } } diff --git a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr index 7f535ec432c1..74ce93a613cf 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr +++ b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr @@ -31,6 +31,27 @@ help: add missing lifetime argument LL | fn foo<'a, T1: X = T1>>(t : T1) -> T1::Y<'a> { | ++++ -error: aborting due to 2 previous errors +error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters + --> $DIR/gat-trait-path-missing-lifetime.rs:8:10 + | +LL | fn foo<'a>(t : Self::Y<'a>) -> Self::Y<'a> { t } + | -- expected 0 type parameters +... +LL | fn foo<'a, T1: X>(t : T1) -> T1::Y<'a> { + | ^^ ^^ + | | + | found 1 type parameter -For more information about this error, try `rustc --explain E0107`. +error[E0046]: not all trait items implemented, missing: `Y` + --> $DIR/gat-trait-path-missing-lifetime.rs:7:1 + | +LL | type Y<'a>; + | ---------- `Y` from trait +... +LL | impl X for T { + | ^^^^^^^^^^^^^^^ missing `Y` in implementation + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0046, E0049, E0107. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs index 5738dfa83eea..c41344270130 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs +++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs @@ -7,10 +7,19 @@ fn foo<'a>(arg: Box>) {} //~| ERROR: parenthesized generic arguments cannot be used //~| ERROR associated type takes 0 generic arguments but 1 generic argument //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments + //~| ERROR associated type takes 0 generic arguments but 1 generic argument + //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments + //~| ERROR associated type takes 0 generic arguments but 1 generic argument + //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments + //~| ERROR at least one trait is required + //~| ERROR: the trait `X` cannot be made into an object fn bar<'a>(arg: Box>) {} //~^ ERROR: parenthesized generic arguments cannot be used //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments + //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments + //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments + //~| ERROR: the trait `X` cannot be made into an object fn main() {} diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr index 461853379b56..bad2ae9c9183 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr +++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr @@ -16,7 +16,7 @@ LL | fn foo<'a>(arg: Box = &'a ()>>) {} | ~ ~ error: parenthesized generic arguments cannot be used in associated type constraints - --> $DIR/gat-trait-path-parenthesised-args.rs:12:27 + --> $DIR/gat-trait-path-parenthesised-args.rs:18:27 | LL | fn bar<'a>(arg: Box>) {} | ^-- @@ -54,7 +54,7 @@ LL | type Y<'a>; | ^ error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied - --> $DIR/gat-trait-path-parenthesised-args.rs:12:27 + --> $DIR/gat-trait-path-parenthesised-args.rs:18:27 | LL | fn bar<'a>(arg: Box>) {} | ^ expected 1 lifetime argument @@ -69,6 +69,141 @@ help: add missing lifetime argument LL | fn bar<'a>(arg: Box>) {} | ++ -error: aborting due to 6 previous errors +error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/gat-trait-path-parenthesised-args.rs:5:27 + | +LL | fn foo<'a>(arg: Box>) {} + | ^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 + | +LL | type Y<'a>; + | ^ -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime argument + | +LL | fn foo<'a>(arg: Box>) {} + | +++ -For more information about this error, try `rustc --explain E0107`. +error[E0107]: associated type takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/gat-trait-path-parenthesised-args.rs:5:27 + | +LL | fn foo<'a>(arg: Box>) {} + | ^---- help: remove these generics + | | + | expected 0 generic arguments + | +note: associated type defined here, with 0 generic parameters + --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 + | +LL | type Y<'a>; + | ^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/gat-trait-path-parenthesised-args.rs:5:27 + | +LL | fn foo<'a>(arg: Box>) {} + | ^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 + | +LL | type Y<'a>; + | ^ -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime argument + | +LL | fn foo<'a>(arg: Box>) {} + | +++ + +error[E0107]: associated type takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/gat-trait-path-parenthesised-args.rs:5:27 + | +LL | fn foo<'a>(arg: Box>) {} + | ^---- help: remove these generics + | | + | expected 0 generic arguments + | +note: associated type defined here, with 0 generic parameters + --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 + | +LL | type Y<'a>; + | ^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0224]: at least one trait is required for an object type + --> $DIR/gat-trait-path-parenthesised-args.rs:5:29 + | +LL | fn foo<'a>(arg: Box>) {} + | ^^ + +error[E0038]: the trait `X` cannot be made into an object + --> $DIR/gat-trait-path-parenthesised-args.rs:5:21 + | +LL | fn foo<'a>(arg: Box>) {} + | ^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 + | +LL | trait X { + | - this trait cannot be made into an object... +LL | type Y<'a>; + | ^ ...because it contains the generic associated type `Y` + = help: consider moving `Y` to another trait + +error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/gat-trait-path-parenthesised-args.rs:18:27 + | +LL | fn bar<'a>(arg: Box>) {} + | ^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 + | +LL | type Y<'a>; + | ^ -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime argument + | +LL | fn bar<'a>(arg: Box>) {} + | ++ + +error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/gat-trait-path-parenthesised-args.rs:18:27 + | +LL | fn bar<'a>(arg: Box>) {} + | ^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 + | +LL | type Y<'a>; + | ^ -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime argument + | +LL | fn bar<'a>(arg: Box>) {} + | ++ + +error[E0038]: the trait `X` cannot be made into an object + --> $DIR/gat-trait-path-parenthesised-args.rs:18:21 + | +LL | fn bar<'a>(arg: Box>) {} + | ^^^^^^^^^^^^^^^ `X` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 + | +LL | trait X { + | - this trait cannot be made into an object... +LL | type Y<'a>; + | ^ ...because it contains the generic associated type `Y` + = help: consider moving `Y` to another trait + +error: aborting due to 15 previous errors + +Some errors have detailed explanations: E0038, E0107, E0224. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/generic-associated-types/issue-71176.rs b/tests/ui/generic-associated-types/issue-71176.rs index f0e162d825f9..e58b6f6091e7 100644 --- a/tests/ui/generic-associated-types/issue-71176.rs +++ b/tests/ui/generic-associated-types/issue-71176.rs @@ -9,6 +9,9 @@ impl Provider for () { struct Holder { inner: Box>, //~^ ERROR: missing generics for associated type + //~| ERROR: missing generics for associated type + //~| ERROR: missing generics for associated type + //~| ERROR: the trait `Provider` cannot be made into an object } fn main() { diff --git a/tests/ui/generic-associated-types/issue-71176.stderr b/tests/ui/generic-associated-types/issue-71176.stderr index ed837f347533..a1913bb618bc 100644 --- a/tests/ui/generic-associated-types/issue-71176.stderr +++ b/tests/ui/generic-associated-types/issue-71176.stderr @@ -14,6 +14,57 @@ help: add missing lifetime argument LL | inner: Box = B>>, | ++++ -error: aborting due to 1 previous error +error[E0107]: missing generics for associated type `Provider::A` + --> $DIR/issue-71176.rs:10:27 + | +LL | inner: Box>, + | ^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/issue-71176.rs:2:10 + | +LL | type A<'a>; + | ^ -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime argument + | +LL | inner: Box = B>>, + | ++++ -For more information about this error, try `rustc --explain E0107`. +error[E0107]: missing generics for associated type `Provider::A` + --> $DIR/issue-71176.rs:10:27 + | +LL | inner: Box>, + | ^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/issue-71176.rs:2:10 + | +LL | type A<'a>; + | ^ -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime argument + | +LL | inner: Box = B>>, + | ++++ + +error[E0038]: the trait `Provider` cannot be made into an object + --> $DIR/issue-71176.rs:10:14 + | +LL | inner: Box>, + | ^^^^^^^^^^^^^^^^^^^ `Provider` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/issue-71176.rs:2:10 + | +LL | trait Provider { + | -------- this trait cannot be made into an object... +LL | type A<'a>; + | ^ ...because it contains the generic associated type `A` + = help: consider moving `A` to another trait + = help: only type `()` implements the trait, consider using it directly instead + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0038, E0107. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/generic-associated-types/issue-79636-1.rs b/tests/ui/generic-associated-types/issue-79636-1.rs index a89039b5c720..a05311d59c11 100644 --- a/tests/ui/generic-associated-types/issue-79636-1.rs +++ b/tests/ui/generic-associated-types/issue-79636-1.rs @@ -3,6 +3,7 @@ trait Monad { type Wrapped; fn bind(self, f: F) -> Self::Wrapped { + //~^ ERROR: the size for values of type `Self` cannot be known todo!() } } @@ -14,8 +15,10 @@ where //~^ ERROR: missing generics for associated type `Monad::Wrapped` { outer.bind(|inner| inner) + //~^ ERROR type annotations needed } fn main() { assert_eq!(join(Some(Some(true))), Some(true)); + //~^ ERROR: `Option>: Monad` is not satisfied } diff --git a/tests/ui/generic-associated-types/issue-79636-1.stderr b/tests/ui/generic-associated-types/issue-79636-1.stderr index 4076e951875e..743d8b7d4627 100644 --- a/tests/ui/generic-associated-types/issue-79636-1.stderr +++ b/tests/ui/generic-associated-types/issue-79636-1.stderr @@ -1,5 +1,5 @@ error[E0107]: missing generics for associated type `Monad::Wrapped` - --> $DIR/issue-79636-1.rs:13:34 + --> $DIR/issue-79636-1.rs:14:34 | LL | MInner: Monad>, | ^^^^^^^ expected 1 generic argument @@ -14,6 +14,56 @@ help: add missing generic argument LL | MInner: Monad = MOuter::Wrapped>, | +++ -error: aborting due to 1 previous error +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/issue-79636-1.rs:5:19 + | +LL | fn bind(self, f: F) -> Self::Wrapped { + | ^^^^ doesn't have a size known at compile-time + | + = help: unsized fn params are gated as an unstable feature +help: consider further restricting `Self` + | +LL | fn bind(self, f: F) -> Self::Wrapped where Self: Sized { + | +++++++++++++++++ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn bind(&self, f: F) -> Self::Wrapped { + | + -For more information about this error, try `rustc --explain E0107`. +error[E0282]: type annotations needed + --> $DIR/issue-79636-1.rs:17:17 + | +LL | outer.bind(|inner| inner) + | ^^^^^ + | +help: consider giving this closure parameter an explicit type + | +LL | outer.bind(|inner: /* Type */| inner) + | ++++++++++++ + +error[E0277]: the trait bound `Option>: Monad` is not satisfied + --> $DIR/issue-79636-1.rs:22:21 + | +LL | assert_eq!(join(Some(Some(true))), Some(true)); + | ---- ^^^^^^^^^^^^^^^^ the trait `Monad` is not implemented for `Option>` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/issue-79636-1.rs:1:1 + | +LL | trait Monad { + | ^^^^^^^^^^^ +note: required by a bound in `join` + --> $DIR/issue-79636-1.rs:13:13 + | +LL | fn join(outer: MOuter) -> MOuter::Wrapped + | ---- required by a bound in this function +LL | where +LL | MOuter: Monad, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `join` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0107, E0277, E0282. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/generic-associated-types/issue-80433.rs b/tests/ui/generic-associated-types/issue-80433.rs index 05ff82fa7d5d..bdba78c2ccd2 100644 --- a/tests/ui/generic-associated-types/issue-80433.rs +++ b/tests/ui/generic-associated-types/issue-80433.rs @@ -4,7 +4,7 @@ struct E { } trait TestMut { - type Output<'a>; + type Output<'a>; //~ ERROR missing required bound fn test_mut<'a>(&'a mut self) -> Self::Output<'a>; } diff --git a/tests/ui/generic-associated-types/issue-80433.stderr b/tests/ui/generic-associated-types/issue-80433.stderr index 488fbeceddd1..ab1fb7944180 100644 --- a/tests/ui/generic-associated-types/issue-80433.stderr +++ b/tests/ui/generic-associated-types/issue-80433.stderr @@ -14,6 +14,17 @@ help: add missing lifetime argument LL | fn test_simpler<'a>(dst: &'a mut impl TestMut = &'a mut f32>) | ++++ -error: aborting due to 1 previous error +error: missing required bound on `Output` + --> $DIR/issue-80433.rs:7:5 + | +LL | type Output<'a>; + | ^^^^^^^^^^^^^^^- + | | + | help: add the required where clause: `where Self: 'a` + | + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/generic-associated-types/missing_lifetime_args.rs b/tests/ui/generic-associated-types/missing_lifetime_args.rs index 331511ba61a4..470db5412b28 100644 --- a/tests/ui/generic-associated-types/missing_lifetime_args.rs +++ b/tests/ui/generic-associated-types/missing_lifetime_args.rs @@ -10,6 +10,9 @@ struct Foo<'a, 'b, 'c> { fn foo<'c, 'd>(_arg: Box>) {} //~^ ERROR missing generics for associated type +//~| ERROR missing generics for associated type +//~| ERROR missing generics for associated type +//~| ERROR the trait `X` cannot be made into an object fn bar<'a, 'b, 'c>(_arg: Foo<'a, 'b>) {} //~^ ERROR struct takes 3 lifetime arguments but 2 lifetime diff --git a/tests/ui/generic-associated-types/missing_lifetime_args.stderr b/tests/ui/generic-associated-types/missing_lifetime_args.stderr index 1a7a2e787a1a..5980c60c51c6 100644 --- a/tests/ui/generic-associated-types/missing_lifetime_args.stderr +++ b/tests/ui/generic-associated-types/missing_lifetime_args.stderr @@ -15,7 +15,7 @@ LL | fn foo<'c, 'd>(_arg: Box = (&'c u32, &'d u32)>>) {} | ++++++++ error[E0107]: struct takes 3 lifetime arguments but 2 lifetime arguments were supplied - --> $DIR/missing_lifetime_args.rs:14:26 + --> $DIR/missing_lifetime_args.rs:17:26 | LL | fn bar<'a, 'b, 'c>(_arg: Foo<'a, 'b>) {} | ^^^ -- -- supplied 2 lifetime arguments @@ -33,7 +33,7 @@ LL | fn bar<'a, 'b, 'c>(_arg: Foo<'a, 'b, 'a>) {} | ++++ error[E0107]: struct takes 3 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing_lifetime_args.rs:17:16 + --> $DIR/missing_lifetime_args.rs:20:16 | LL | fn f<'a>(_arg: Foo<'a>) {} | ^^^ -- supplied 1 lifetime argument @@ -50,6 +50,56 @@ help: add missing lifetime arguments LL | fn f<'a>(_arg: Foo<'a, 'a, 'a>) {} | ++++++++ -error: aborting due to 3 previous errors +error[E0107]: missing generics for associated type `X::Y` + --> $DIR/missing_lifetime_args.rs:11:32 + | +LL | fn foo<'c, 'd>(_arg: Box>) {} + | ^ expected 2 lifetime arguments + | +note: associated type defined here, with 2 lifetime parameters: `'a`, `'b` + --> $DIR/missing_lifetime_args.rs:2:10 + | +LL | type Y<'a, 'b>; + | ^ -- -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime arguments + | +LL | fn foo<'c, 'd>(_arg: Box = (&'c u32, &'d u32)>>) {} + | ++++++++ -For more information about this error, try `rustc --explain E0107`. +error[E0107]: missing generics for associated type `X::Y` + --> $DIR/missing_lifetime_args.rs:11:32 + | +LL | fn foo<'c, 'd>(_arg: Box>) {} + | ^ expected 2 lifetime arguments + | +note: associated type defined here, with 2 lifetime parameters: `'a`, `'b` + --> $DIR/missing_lifetime_args.rs:2:10 + | +LL | type Y<'a, 'b>; + | ^ -- -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime arguments + | +LL | fn foo<'c, 'd>(_arg: Box = (&'c u32, &'d u32)>>) {} + | ++++++++ + +error[E0038]: the trait `X` cannot be made into an object + --> $DIR/missing_lifetime_args.rs:11:26 + | +LL | fn foo<'c, 'd>(_arg: Box>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/missing_lifetime_args.rs:2:10 + | +LL | trait X { + | - this trait cannot be made into an object... +LL | type Y<'a, 'b>; + | ^ ...because it contains the generic associated type `Y` + = help: consider moving `Y` to another trait + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0038, E0107. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs index c58f9cf1dfc8..d6fc3df1026f 100644 --- a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs +++ b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs @@ -6,6 +6,11 @@ const _: () = { fn f2<'a>(arg : Box = &'a ()>>) {} //~^ ERROR associated type takes 1 lifetime argument but 0 lifetime arguments //~| ERROR associated type takes 0 generic arguments but 1 generic argument + //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments + //~| ERROR associated type takes 0 generic arguments but 1 generic argument + //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments + //~| ERROR associated type takes 0 generic arguments but 1 generic argument + //~| ERROR the trait `X` cannot be made into an object }; fn main() {} diff --git a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr index fab5b474d928..2090f75aed32 100644 --- a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr +++ b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr @@ -28,6 +28,86 @@ note: associated type defined here, with 0 generic parameters LL | type Y<'a>; | ^ -error: aborting due to 2 previous errors +error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/trait-path-type-error-once-implemented.rs:6:29 + | +LL | fn f2<'a>(arg : Box = &'a ()>>) {} + | ^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/trait-path-type-error-once-implemented.rs:2:10 + | +LL | type Y<'a>; + | ^ -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime argument + | +LL | fn f2<'a>(arg : Box = &'a ()>>) {} + | +++ -For more information about this error, try `rustc --explain E0107`. +error[E0107]: associated type takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/trait-path-type-error-once-implemented.rs:6:29 + | +LL | fn f2<'a>(arg : Box = &'a ()>>) {} + | ^--- help: remove these generics + | | + | expected 0 generic arguments + | +note: associated type defined here, with 0 generic parameters + --> $DIR/trait-path-type-error-once-implemented.rs:2:10 + | +LL | type Y<'a>; + | ^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/trait-path-type-error-once-implemented.rs:6:29 + | +LL | fn f2<'a>(arg : Box = &'a ()>>) {} + | ^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/trait-path-type-error-once-implemented.rs:2:10 + | +LL | type Y<'a>; + | ^ -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime argument + | +LL | fn f2<'a>(arg : Box = &'a ()>>) {} + | +++ + +error[E0107]: associated type takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/trait-path-type-error-once-implemented.rs:6:29 + | +LL | fn f2<'a>(arg : Box = &'a ()>>) {} + | ^--- help: remove these generics + | | + | expected 0 generic arguments + | +note: associated type defined here, with 0 generic parameters + --> $DIR/trait-path-type-error-once-implemented.rs:2:10 + | +LL | type Y<'a>; + | ^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0038]: the trait `X` cannot be made into an object + --> $DIR/trait-path-type-error-once-implemented.rs:6:23 + | +LL | fn f2<'a>(arg : Box = &'a ()>>) {} + | ^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/trait-path-type-error-once-implemented.rs:2:10 + | +LL | trait X { + | - this trait cannot be made into an object... +LL | type Y<'a>; + | ^ ...because it contains the generic associated type `Y` + = help: consider moving `Y` to another trait + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0038, E0107. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/generic-associated-types/type-param-defaults.rs b/tests/ui/generic-associated-types/type-param-defaults.rs index f034076b0109..a9c8c5c12d9e 100644 --- a/tests/ui/generic-associated-types/type-param-defaults.rs +++ b/tests/ui/generic-associated-types/type-param-defaults.rs @@ -29,6 +29,8 @@ where fn main() { // errors foo::<()>(); + //~^ ERROR type mismatch + //~| ERROR `u64: Other` is not satisfied // works foo::(); } diff --git a/tests/ui/generic-associated-types/type-param-defaults.stderr b/tests/ui/generic-associated-types/type-param-defaults.stderr index 85ccaba0e69e..3c094d45fffc 100644 --- a/tests/ui/generic-associated-types/type-param-defaults.stderr +++ b/tests/ui/generic-associated-types/type-param-defaults.stderr @@ -16,5 +16,43 @@ error: defaults for type parameters are only allowed in `struct`, `enum`, `type` LL | type Assoc = T; | ^^^^^^^ -error: aborting due to 3 previous errors +error[E0271]: type mismatch resolving `<() as Trait>::Assoc == u32` + --> $DIR/type-param-defaults.rs:31:11 + | +LL | foo::<()>(); + | ^^ type mismatch resolving `<() as Trait>::Assoc == u32` + | +note: expected this to be `u32` + --> $DIR/type-param-defaults.rs:11:27 + | +LL | type Assoc = u64; + | ^^^ +note: required by a bound in `foo` + --> $DIR/type-param-defaults.rs:25:14 + | +LL | fn foo() + | --- required by a bound in this function +LL | where +LL | T: Trait, + | ^^^^^^^^^^^ required by this bound in `foo` +error[E0277]: the trait bound `u64: Other` is not satisfied + --> $DIR/type-param-defaults.rs:31:11 + | +LL | foo::<()>(); + | ^^ the trait `Other` is not implemented for `u64` + | + = help: the trait `Other` is implemented for `u32` +note: required by a bound in `foo` + --> $DIR/type-param-defaults.rs:26:15 + | +LL | fn foo() + | --- required by a bound in this function +... +LL | T::Assoc: Other { + | ^^^^^ required by this bound in `foo` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/generic-const-items/parameter-defaults.rs b/tests/ui/generic-const-items/parameter-defaults.rs index a6f82c249feb..c933db17fa20 100644 --- a/tests/ui/generic-const-items/parameter-defaults.rs +++ b/tests/ui/generic-const-items/parameter-defaults.rs @@ -11,4 +11,5 @@ const NONE: Option = None::; //~ ERROR defaults for type parameter fn main() { let _ = NONE; + //~^ ERROR type annotations needed } diff --git a/tests/ui/generic-const-items/parameter-defaults.stderr b/tests/ui/generic-const-items/parameter-defaults.stderr index 598622869454..697423e8dc39 100644 --- a/tests/ui/generic-const-items/parameter-defaults.stderr +++ b/tests/ui/generic-const-items/parameter-defaults.stderr @@ -4,5 +4,17 @@ error: defaults for type parameters are only allowed in `struct`, `enum`, `type` LL | const NONE: Option = None::; | ^^^^^^ -error: aborting due to 1 previous error +error[E0282]: type annotations needed for `Option` + --> $DIR/parameter-defaults.rs:13:9 + | +LL | let _ = NONE; + | ^ + | +help: consider giving this pattern a type, where the type for type parameter `T` is specified + | +LL | let _: Option = NONE; + | +++++++++++ +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/generics/wrong-number-of-args.rs b/tests/ui/generics/wrong-number-of-args.rs index e4eaff21af1d..95463d1c32c3 100644 --- a/tests/ui/generics/wrong-number-of-args.rs +++ b/tests/ui/generics/wrong-number-of-args.rs @@ -21,7 +21,7 @@ mod no_generics { } mod type_and_type { - struct Ty; + struct Ty(A, B); type A = Ty; //~^ ERROR missing generics for struct `type_and_type::Ty` @@ -43,7 +43,7 @@ mod type_and_type { } mod lifetime_and_type { - struct Ty<'a, T>; + struct Ty<'a, T>(&'a T); type A = Ty; //~^ ERROR missing generics for struct @@ -75,7 +75,7 @@ mod lifetime_and_type { } mod type_and_type_and_type { - struct Ty; + struct Ty(A, B, C); type A = Ty; //~^ ERROR missing generics for struct `type_and_type_and_type::Ty` diff --git a/tests/ui/generics/wrong-number-of-args.stderr b/tests/ui/generics/wrong-number-of-args.stderr index 9006fb10b67f..e04408a0fdf3 100644 --- a/tests/ui/generics/wrong-number-of-args.stderr +++ b/tests/ui/generics/wrong-number-of-args.stderr @@ -246,7 +246,7 @@ LL | type A = Ty; note: struct defined here, with 2 generic parameters: `A`, `B` --> $DIR/wrong-number-of-args.rs:24:12 | -LL | struct Ty; +LL | struct Ty(A, B); | ^^ - - help: add missing generic arguments | @@ -264,7 +264,7 @@ LL | type B = Ty; note: struct defined here, with 2 generic parameters: `A`, `B` --> $DIR/wrong-number-of-args.rs:24:12 | -LL | struct Ty; +LL | struct Ty(A, B); | ^^ - - help: add missing generic argument | @@ -282,7 +282,7 @@ LL | type D = Ty; note: struct defined here, with 2 generic parameters: `A`, `B` --> $DIR/wrong-number-of-args.rs:24:12 | -LL | struct Ty; +LL | struct Ty(A, B); | ^^ - - error[E0107]: struct takes 2 generic arguments but 0 generic arguments were supplied @@ -294,7 +294,7 @@ LL | type E = Ty<>; note: struct defined here, with 2 generic parameters: `A`, `B` --> $DIR/wrong-number-of-args.rs:24:12 | -LL | struct Ty; +LL | struct Ty(A, B); | ^^ - - help: add missing generic arguments | @@ -310,7 +310,7 @@ LL | type A = Ty; note: struct defined here, with 1 generic parameter: `T` --> $DIR/wrong-number-of-args.rs:46:12 | -LL | struct Ty<'a, T>; +LL | struct Ty<'a, T>(&'a T); | ^^ - help: add missing generic argument | @@ -326,7 +326,7 @@ LL | type B = Ty<'static>; note: struct defined here, with 1 generic parameter: `T` --> $DIR/wrong-number-of-args.rs:46:12 | -LL | struct Ty<'a, T>; +LL | struct Ty<'a, T>(&'a T); | ^^ - help: add missing generic argument | @@ -342,7 +342,7 @@ LL | type E = Ty<>; note: struct defined here, with 1 generic parameter: `T` --> $DIR/wrong-number-of-args.rs:46:12 | -LL | struct Ty<'a, T>; +LL | struct Ty<'a, T>(&'a T); | ^^ - help: add missing generic argument | @@ -360,7 +360,7 @@ LL | type F = Ty<'static, usize, 'static, usize>; note: struct defined here, with 1 lifetime parameter: `'a` --> $DIR/wrong-number-of-args.rs:46:12 | -LL | struct Ty<'a, T>; +LL | struct Ty<'a, T>(&'a T); | ^^ -- error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied @@ -374,7 +374,7 @@ LL | type F = Ty<'static, usize, 'static, usize>; note: struct defined here, with 1 generic parameter: `T` --> $DIR/wrong-number-of-args.rs:46:12 | -LL | struct Ty<'a, T>; +LL | struct Ty<'a, T>(&'a T); | ^^ - error[E0107]: missing generics for struct `type_and_type_and_type::Ty` @@ -386,7 +386,7 @@ LL | type A = Ty; note: struct defined here, with at least 2 generic parameters: `A`, `B` --> $DIR/wrong-number-of-args.rs:78:12 | -LL | struct Ty; +LL | struct Ty(A, B, C); | ^^ - - help: add missing generic arguments | @@ -404,7 +404,7 @@ LL | type B = Ty; note: struct defined here, with at least 2 generic parameters: `A`, `B` --> $DIR/wrong-number-of-args.rs:78:12 | -LL | struct Ty; +LL | struct Ty(A, B, C); | ^^ - - help: add missing generic argument | @@ -422,7 +422,7 @@ LL | type E = Ty; note: struct defined here, with at most 3 generic parameters: `A`, `B`, `C` --> $DIR/wrong-number-of-args.rs:78:12 | -LL | struct Ty; +LL | struct Ty(A, B, C); | ^^ - - ---------------- error[E0107]: struct takes at least 2 generic arguments but 0 generic arguments were supplied @@ -434,7 +434,7 @@ LL | type F = Ty<>; note: struct defined here, with at least 2 generic parameters: `A`, `B` --> $DIR/wrong-number-of-args.rs:78:12 | -LL | struct Ty; +LL | struct Ty(A, B, C); | ^^ - - help: add missing generic arguments | diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-cache-issue-54302.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-cache-issue-54302.stderr index 7f81ee331bf6..186af160d908 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-cache-issue-54302.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-cache-issue-54302.stderr @@ -4,7 +4,7 @@ error: implementation of `Deserialize` is not general enough LL | assert_deserialize_owned::<&'static str>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough | - = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`... + = note: `&str` must implement `Deserialize<'0>`, for any lifetime `'0`... = note: ...but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr index 28c259be35f6..e50aad876d8c 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr @@ -12,7 +12,7 @@ error: higher-ranked lifetime error LL | v.t(|| {}); | ^^^^^ | - = note: could not prove `for<'a> &'a V: 'static` + = note: could not prove `for<'a> &'a V: 'b` error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-20616.rs b/tests/ui/impl-header-lifetime-elision/bare_type.rs similarity index 82% rename from tests/ui/issues/issue-20616.rs rename to tests/ui/impl-header-lifetime-elision/bare_type.rs index 6c24d437272e..9af98f870d2d 100644 --- a/tests/ui/issues/issue-20616.rs +++ b/tests/ui/impl-header-lifetime-elision/bare_type.rs @@ -33,12 +33,11 @@ type TypeI = T; static STATIC: () = (); fn main() { - // ensure token `>=` works fine - let _: TypeA<'static>= &STATIC; - let _: TypeA<'static,>= &STATIC; + let _: TypeA<'static> = &STATIC; + let _: TypeA<'static,> = &STATIC; // ensure token `>>=` works fine - let _: Box>= Box::new(&STATIC); - let _: Box>= Box::new(&STATIC); + let _: Box> = Box::new(&STATIC); + let _: Box> = Box::new(&STATIC); } diff --git a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr index 2e13ca753fc2..7917fa991ee3 100644 --- a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr +++ b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr @@ -1,3 +1,9 @@ +error[E0277]: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied + --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13 + | +LL | fn ice() -> impl AsRef { + | ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not implemented for `()` + error[E0782]: trait objects must include the `dyn` keyword --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:24 | @@ -9,6 +15,7 @@ help: add `dyn` keyword before this trait LL | fn ice() -> impl AsRef { | +++ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0782`. +Some errors have detailed explanations: E0277, E0782. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs index bed81c4bca76..55d69069afb5 100644 --- a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs +++ b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs @@ -6,6 +6,7 @@ fn ice() -> impl AsRef { //[edition2015]~^ ERROR: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied [E0277] //[edition2021]~^^ ERROR: trait objects must include the `dyn` keyword [E0782] + //[edition2021]~| ERROR: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied [E0277] todo!() } diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs b/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs index 527a4586fd7e..06c3d9ad434e 100644 --- a/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs +++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs @@ -4,16 +4,19 @@ use std::fmt::Debug; fn a() -> impl Fn(&u8) -> (impl Debug + '_) { //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet |x| x + //~^ ERROR lifetime may not live long enough } fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) { //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet |x| x + //~^ ERROR lifetime may not live long enough } fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) { //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet |x| x + //~^ ERROR lifetime may not live long enough } fn d() -> impl Fn() -> (impl Debug + '_) { diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr index a5982a5542a5..ebab99404931 100644 --- a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr +++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifier - --> $DIR/impl-fn-hrtb-bounds.rs:19:38 + --> $DIR/impl-fn-hrtb-bounds.rs:22:38 | LL | fn d() -> impl Fn() -> (impl Debug + '_) { | ^^ expected named lifetime parameter @@ -23,29 +23,56 @@ LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) { | ^ error: higher kinded lifetime bounds on nested opaque types are not supported yet - --> $DIR/impl-fn-hrtb-bounds.rs:9:52 + --> $DIR/impl-fn-hrtb-bounds.rs:10:52 | LL | fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) { | ^^ | note: lifetime declared here - --> $DIR/impl-fn-hrtb-bounds.rs:9:20 + --> $DIR/impl-fn-hrtb-bounds.rs:10:20 | LL | fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) { | ^^ error: higher kinded lifetime bounds on nested opaque types are not supported yet - --> $DIR/impl-fn-hrtb-bounds.rs:14:52 + --> $DIR/impl-fn-hrtb-bounds.rs:16:52 | LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) { | ^^ | note: lifetime declared here - --> $DIR/impl-fn-hrtb-bounds.rs:14:20 + --> $DIR/impl-fn-hrtb-bounds.rs:16:20 | LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) { | ^^ -error: aborting due to 4 previous errors +error: lifetime may not live long enough + --> $DIR/impl-fn-hrtb-bounds.rs:6:9 + | +LL | |x| x + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is impl Debug + '2 + | has type `&'1 u8` + +error: lifetime may not live long enough + --> $DIR/impl-fn-hrtb-bounds.rs:12:9 + | +LL | |x| x + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is impl Debug + '2 + | has type `&'1 u8` + +error: lifetime may not live long enough + --> $DIR/impl-fn-hrtb-bounds.rs:18:9 + | +LL | |x| x + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is impl Debug + '2 + | has type `&'1 u8` + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs index 61303a5b2cb4..a4a1f1dcee12 100644 --- a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs +++ b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs @@ -5,6 +5,7 @@ fn a() -> impl Fn(&u8) -> impl Debug + '_ { //~^ ERROR ambiguous `+` in a type //~| ERROR higher kinded lifetime bounds on nested opaque types are not supported yet |x| x + //~^ ERROR lifetime may not live long enough } fn b() -> impl Fn() -> impl Debug + Send { diff --git a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr index cf6e5ef7bace..e18e89700b4e 100644 --- a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr +++ b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr @@ -5,7 +5,7 @@ LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ { | ^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + '_)` error: ambiguous `+` in a type - --> $DIR/impl-fn-parsing-ambiguities.rs:10:24 + --> $DIR/impl-fn-parsing-ambiguities.rs:11:24 | LL | fn b() -> impl Fn() -> impl Debug + Send { | ^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + Send)` @@ -22,5 +22,14 @@ note: lifetime declared here LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ { | ^ -error: aborting due to 3 previous errors +error: lifetime may not live long enough + --> $DIR/impl-fn-parsing-ambiguities.rs:7:9 + | +LL | |x| x + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is impl Debug + '2 + | has type `&'1 u8` + +error: aborting due to 4 previous errors diff --git a/tests/ui/impl-trait/impl_trait_projections.rs b/tests/ui/impl-trait/impl_trait_projections.rs index b3ff2ce5a7bf..365ac85e2f66 100644 --- a/tests/ui/impl-trait/impl_trait_projections.rs +++ b/tests/ui/impl-trait/impl_trait_projections.rs @@ -15,7 +15,7 @@ fn projection_is_disallowed(x: impl Iterator) -> ::Item { x.next().unwrap() } -fn projection_with_named_trait_is_disallowed(x: impl Iterator) +fn projection_with_named_trait_is_disallowed(mut x: impl Iterator) -> ::Item //~^ ERROR `impl Trait` is not allowed in path parameters { @@ -25,7 +25,9 @@ fn projection_with_named_trait_is_disallowed(x: impl Iterator) fn projection_with_named_trait_inside_path_is_disallowed() -> <::std::ops::Range as Iterator>::Item //~^ ERROR `impl Trait` is not allowed in path parameters +//~| ERROR `impl Debug: Step` is not satisfied { + //~^ ERROR `impl Debug: Step` is not satisfied (1i32..100).next().unwrap() } diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr index 4deb24731bc0..700aff36aa50 100644 --- a/tests/ui/impl-trait/impl_trait_projections.stderr +++ b/tests/ui/impl-trait/impl_trait_projections.stderr @@ -17,7 +17,7 @@ LL | -> <::std::ops::Range as Iterator>::Item | ^^^^^^^^^^ error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:33:29 + --> $DIR/impl_trait_projections.rs:35:29 | LL | -> as Iterator>::Item | ^^^^^^^^^^ @@ -28,6 +28,46 @@ error[E0667]: `impl Trait` is not allowed in path parameters LL | fn projection_is_disallowed(x: impl Iterator) -> ::Item { | ^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error[E0277]: the trait bound `impl Debug: Step` is not satisfied + --> $DIR/impl_trait_projections.rs:26:8 + | +LL | -> <::std::ops::Range as Iterator>::Item + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `impl Debug` + | + = help: the following other types implement trait `Step`: + char + isize + i8 + i16 + i32 + i64 + i128 + usize + and 8 others + = note: required for `std::ops::Range` to implement `Iterator` -For more information about this error, try `rustc --explain E0667`. +error[E0277]: the trait bound `impl Debug: Step` is not satisfied + --> $DIR/impl_trait_projections.rs:29:1 + | +LL | / { +LL | | +LL | | (1i32..100).next().unwrap() +LL | | } + | |_^ the trait `Step` is not implemented for `impl Debug` + | + = help: the following other types implement trait `Step`: + char + isize + i8 + i16 + i32 + i64 + i128 + usize + and 8 others + = note: required for `std::ops::Range` to implement `Iterator` + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0277, E0667. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/implicit-capture-late.stderr b/tests/ui/impl-trait/implicit-capture-late.stderr index 9b3a4ff5f425..2fb5ebb65418 100644 --- a/tests/ui/impl-trait/implicit-capture-late.stderr +++ b/tests/ui/impl-trait/implicit-capture-late.stderr @@ -4,6 +4,12 @@ error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl le LL | fn foo(x: Vec) -> Box Deref> { | ^^ -error: aborting due to 1 previous error +error: [o] + --> $DIR/implicit-capture-late.rs:10:55 + | +LL | fn foo(x: Vec) -> Box Deref> { + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0657`. diff --git a/tests/ui/impl-trait/issues/issue-54600.rs b/tests/ui/impl-trait/issues/issue-54600.rs index ccf2767012e6..62bfd7cd9688 100644 --- a/tests/ui/impl-trait/issues/issue-54600.rs +++ b/tests/ui/impl-trait/issues/issue-54600.rs @@ -2,6 +2,6 @@ use std::fmt::Debug; fn main() { let x: Option = Some(44_u32); - //~^ `impl Trait` only allowed in function and inherent method argument and return types + //~^ `impl Trait` is not allowed in the type of variable bindings println!("{:?}", x); } diff --git a/tests/ui/impl-trait/issues/issue-54600.stderr b/tests/ui/impl-trait/issues/issue-54600.stderr index 946ad74b8722..c75c0fa0f055 100644 --- a/tests/ui/impl-trait/issues/issue-54600.stderr +++ b/tests/ui/impl-trait/issues/issue-54600.stderr @@ -1,8 +1,10 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in variable bindings +error[E0562]: `impl Trait` is not allowed in the type of variable bindings --> $DIR/issue-54600.rs:4:19 | LL | let x: Option = Some(44_u32); | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-54840.rs b/tests/ui/impl-trait/issues/issue-54840.rs index 910d23f1d938..65257d2f7f1d 100644 --- a/tests/ui/impl-trait/issues/issue-54840.rs +++ b/tests/ui/impl-trait/issues/issue-54840.rs @@ -3,5 +3,5 @@ use std::ops::Add; fn main() { let i: i32 = 0; let j: &impl Add = &i; - //~^ `impl Trait` only allowed in function and inherent method argument and return types + //~^ `impl Trait` is not allowed in the type of variable bindings } diff --git a/tests/ui/impl-trait/issues/issue-54840.stderr b/tests/ui/impl-trait/issues/issue-54840.stderr index c4ab79f110dd..de75256d5a93 100644 --- a/tests/ui/impl-trait/issues/issue-54840.stderr +++ b/tests/ui/impl-trait/issues/issue-54840.stderr @@ -1,8 +1,10 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in variable bindings +error[E0562]: `impl Trait` is not allowed in the type of variable bindings --> $DIR/issue-54840.rs:5:13 | LL | let j: &impl Add = &i; | ^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-58504.rs b/tests/ui/impl-trait/issues/issue-58504.rs index 03b51ae92d18..4f7a35e81b80 100644 --- a/tests/ui/impl-trait/issues/issue-58504.rs +++ b/tests/ui/impl-trait/issues/issue-58504.rs @@ -8,5 +8,5 @@ fn mk_gen() -> impl Coroutine { fn main() { let gens: [impl Coroutine;2] = [ mk_gen(), mk_gen() ]; - //~^ `impl Trait` only allowed in function and inherent method argument and return types + //~^ `impl Trait` is not allowed in the type of variable bindings } diff --git a/tests/ui/impl-trait/issues/issue-58504.stderr b/tests/ui/impl-trait/issues/issue-58504.stderr index e67e48728ed0..8231732bba1c 100644 --- a/tests/ui/impl-trait/issues/issue-58504.stderr +++ b/tests/ui/impl-trait/issues/issue-58504.stderr @@ -1,8 +1,10 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in variable bindings +error[E0562]: `impl Trait` is not allowed in the type of variable bindings --> $DIR/issue-58504.rs:10:16 | LL | let gens: [impl Coroutine;2] = [ mk_gen(), mk_gen() ]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-58956.rs b/tests/ui/impl-trait/issues/issue-58956.rs index 5d5566860c0f..a59de2379d8f 100644 --- a/tests/ui/impl-trait/issues/issue-58956.rs +++ b/tests/ui/impl-trait/issues/issue-58956.rs @@ -5,9 +5,9 @@ impl Lam for B {} pub struct Wrap(T); const _A: impl Lam = { - //~^ `impl Trait` only allowed in function and inherent method argument and return types + //~^ `impl Trait` is not allowed in const types let x: Wrap = Wrap(B); - //~^ `impl Trait` only allowed in function and inherent method argument and return types + //~^ `impl Trait` is not allowed in the type of variable bindings x.0 }; diff --git a/tests/ui/impl-trait/issues/issue-58956.stderr b/tests/ui/impl-trait/issues/issue-58956.stderr index 5ee33352afa2..0c81c69def3a 100644 --- a/tests/ui/impl-trait/issues/issue-58956.stderr +++ b/tests/ui/impl-trait/issues/issue-58956.stderr @@ -1,14 +1,18 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in const types +error[E0562]: `impl Trait` is not allowed in const types --> $DIR/issue-58956.rs:7:11 | LL | const _A: impl Lam = { | ^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in variable bindings +error[E0562]: `impl Trait` is not allowed in the type of variable bindings --> $DIR/issue-58956.rs:9:17 | LL | let x: Wrap = Wrap(B); | ^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/issues/issue-67830.rs b/tests/ui/impl-trait/issues/issue-67830.rs index 92f7e005dbf0..6dc8935c7770 100644 --- a/tests/ui/impl-trait/issues/issue-67830.rs +++ b/tests/ui/impl-trait/issues/issue-67830.rs @@ -21,6 +21,8 @@ struct A; fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> { //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet Wrap(|a| Some(a).into_iter()) + //~^ ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough } fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-67830.stderr b/tests/ui/impl-trait/issues/issue-67830.stderr index 17cfa151a686..546198b8a103 100644 --- a/tests/ui/impl-trait/issues/issue-67830.stderr +++ b/tests/ui/impl-trait/issues/issue-67830.stderr @@ -10,5 +10,24 @@ note: lifetime declared here LL | fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> { | ^^ -error: aborting due to 1 previous error +error: implementation of `FnOnce` is not general enough + --> $DIR/issue-67830.rs:23:5 + | +LL | Wrap(|a| Some(a).into_iter()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2` + +error: implementation of `FnOnce` is not general enough + --> $DIR/issue-67830.rs:23:5 + | +LL | Wrap(|a| Some(a).into_iter()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors diff --git a/tests/ui/impl-trait/issues/issue-70971.rs b/tests/ui/impl-trait/issues/issue-70971.rs index c24259a71eb2..2f2c2e8f441a 100644 --- a/tests/ui/impl-trait/issues/issue-70971.rs +++ b/tests/ui/impl-trait/issues/issue-70971.rs @@ -1,4 +1,4 @@ fn main() { let x : (impl Copy,) = (true,); - //~^ `impl Trait` only allowed in function and inherent method argument and return types + //~^ `impl Trait` is not allowed in the type of variable bindings } diff --git a/tests/ui/impl-trait/issues/issue-70971.stderr b/tests/ui/impl-trait/issues/issue-70971.stderr index fcc67291e4d2..28c463cea850 100644 --- a/tests/ui/impl-trait/issues/issue-70971.stderr +++ b/tests/ui/impl-trait/issues/issue-70971.stderr @@ -1,8 +1,10 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in variable bindings +error[E0562]: `impl Trait` is not allowed in the type of variable bindings --> $DIR/issue-70971.rs:2:14 | LL | let x : (impl Copy,) = (true,); | ^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-79099.rs b/tests/ui/impl-trait/issues/issue-79099.rs index 22c66491ce98..757e61fb631e 100644 --- a/tests/ui/impl-trait/issues/issue-79099.rs +++ b/tests/ui/impl-trait/issues/issue-79099.rs @@ -1,7 +1,7 @@ struct Bug { V1: [(); { let f: impl core::future::Future = async { 1 }; - //~^ `impl Trait` only allowed in function and inherent method argument and return types + //~^ `impl Trait` is not allowed in the type of variable bindings //~| expected identifier 1 }], diff --git a/tests/ui/impl-trait/issues/issue-79099.stderr b/tests/ui/impl-trait/issues/issue-79099.stderr index 82fc03c61b3b..6c26d5bd1b74 100644 --- a/tests/ui/impl-trait/issues/issue-79099.stderr +++ b/tests/ui/impl-trait/issues/issue-79099.stderr @@ -9,11 +9,13 @@ LL | let f: impl core::future::Future = async { 1 }; = help: pass `--edition 2021` to `rustc` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in variable bindings +error[E0562]: `impl Trait` is not allowed in the type of variable bindings --> $DIR/issue-79099.rs:3:16 | LL | let f: impl core::future::Future = async { 1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs b/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs index 3224145bffeb..771b29f3c7e1 100644 --- a/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs +++ b/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs @@ -1,8 +1,8 @@ struct Foo(T); -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in generic parameter defaults type Result = std::result::Result; -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in generic parameter defaults // should not cause ICE fn x() -> Foo { diff --git a/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr b/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr index 56be4577d51a..07d6c5b6b1c8 100644 --- a/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr +++ b/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr @@ -1,14 +1,18 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults +error[E0562]: `impl Trait` is not allowed in generic parameter defaults --> $DIR/issue-83929-impl-trait-in-generic-default.rs:1:16 | LL | struct Foo(T); | ^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults +error[E0562]: `impl Trait` is not allowed in generic parameter defaults --> $DIR/issue-83929-impl-trait-in-generic-default.rs:4:20 | LL | type Result = std::result::Result; | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/issues/issue-84919.rs b/tests/ui/impl-trait/issues/issue-84919.rs index 77d27d7c06b6..0f911ba23ae2 100644 --- a/tests/ui/impl-trait/issues/issue-84919.rs +++ b/tests/ui/impl-trait/issues/issue-84919.rs @@ -3,7 +3,7 @@ impl Trait for () {} fn foo<'a: 'a>() { let _x: impl Trait = (); - //~^ `impl Trait` only allowed in function and inherent method argument and return types + //~^ `impl Trait` is not allowed in the type of variable bindings } fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-84919.stderr b/tests/ui/impl-trait/issues/issue-84919.stderr index 963865efa69f..02d2ce28fb3e 100644 --- a/tests/ui/impl-trait/issues/issue-84919.stderr +++ b/tests/ui/impl-trait/issues/issue-84919.stderr @@ -1,8 +1,10 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in variable bindings +error[E0562]: `impl Trait` is not allowed in the type of variable bindings --> $DIR/issue-84919.rs:5:13 | LL | let _x: impl Trait = (); | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-86642.rs b/tests/ui/impl-trait/issues/issue-86642.rs index 49f8944ac4af..74be8779d445 100644 --- a/tests/ui/impl-trait/issues/issue-86642.rs +++ b/tests/ui/impl-trait/issues/issue-86642.rs @@ -1,5 +1,5 @@ static x: impl Fn(&str) -> Result<&str, ()> = move |source| { - //~^ `impl Trait` only allowed in function and inherent method argument and return types + //~^ `impl Trait` is not allowed in static types let res = (move |source| Ok(source))(source); let res = res.or((move |source| Ok(source))(source)); res diff --git a/tests/ui/impl-trait/issues/issue-86642.stderr b/tests/ui/impl-trait/issues/issue-86642.stderr index 3ad18a13290a..19fd5bc0c1ca 100644 --- a/tests/ui/impl-trait/issues/issue-86642.stderr +++ b/tests/ui/impl-trait/issues/issue-86642.stderr @@ -1,8 +1,10 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in const types +error[E0562]: `impl Trait` is not allowed in static types --> $DIR/issue-86642.rs:1:11 | LL | static x: impl Fn(&str) -> Result<&str, ()> = move |source| { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-87295.rs b/tests/ui/impl-trait/issues/issue-87295.rs index eb44020ac0e7..a765e14884b0 100644 --- a/tests/ui/impl-trait/issues/issue-87295.rs +++ b/tests/ui/impl-trait/issues/issue-87295.rs @@ -14,5 +14,5 @@ impl Struct { fn main() { let _do_not_waste: Struct> = Struct::new(()); - //~^ `impl Trait` only allowed in function and inherent method argument and return types + //~^ `impl Trait` is not allowed in the type of variable bindings } diff --git a/tests/ui/impl-trait/issues/issue-87295.stderr b/tests/ui/impl-trait/issues/issue-87295.stderr index e9a635f244bc..78274a056ec6 100644 --- a/tests/ui/impl-trait/issues/issue-87295.stderr +++ b/tests/ui/impl-trait/issues/issue-87295.stderr @@ -1,8 +1,10 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in variable bindings +error[E0562]: `impl Trait` is not allowed in the type of variable bindings --> $DIR/issue-87295.rs:16:31 | LL | let _do_not_waste: Struct> = Struct::new(()); | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-88236-2.rs b/tests/ui/impl-trait/issues/issue-88236-2.rs index fde8a6704cc4..f4354d1b2aef 100644 --- a/tests/ui/impl-trait/issues/issue-88236-2.rs +++ b/tests/ui/impl-trait/issues/issue-88236-2.rs @@ -18,11 +18,16 @@ fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet &() + //~^ ERROR implementation of `Hrtb` is not general enough + //~| ERROR implementation of `Hrtb` is not general enough } fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet x + //~^ ERROR implementation of `Hrtb` is not general enough + //~| ERROR implementation of `Hrtb` is not general enough + //~| ERROR lifetime may not live long enough } fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-88236-2.stderr b/tests/ui/impl-trait/issues/issue-88236-2.stderr index 8605d07abe94..1e63338d6d19 100644 --- a/tests/ui/impl-trait/issues/issue-88236-2.stderr +++ b/tests/ui/impl-trait/issues/issue-88236-2.stderr @@ -23,16 +23,70 @@ LL | fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Sen | ^^ error: higher kinded lifetime bounds on nested opaque types are not supported yet - --> $DIR/issue-88236-2.rs:23:78 + --> $DIR/issue-88236-2.rs:25:78 | LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { | ^^ | note: lifetime declared here - --> $DIR/issue-88236-2.rs:23:45 + --> $DIR/issue-88236-2.rs:25:45 | LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { | ^^ -error: aborting due to 3 previous errors +error: implementation of `Hrtb` is not general enough + --> $DIR/issue-88236-2.rs:20:5 + | +LL | &() + | ^^^ implementation of `Hrtb` is not general enough + | + = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`... + = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` + +error: implementation of `Hrtb` is not general enough + --> $DIR/issue-88236-2.rs:20:5 + | +LL | &() + | ^^^ implementation of `Hrtb` is not general enough + | + = note: `Hrtb<'a>` would have to be implemented for the type `&()` + = note: ...but `Hrtb<'0>` is actually implemented for the type `&'0 ()`, for some specific lifetime `'0` + +error: lifetime may not live long enough + --> $DIR/issue-88236-2.rs:27:5 + | +LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { + | -- lifetime `'b` defined here +LL | +LL | x + | ^ returning this value requires that `'b` must outlive `'static` + | +help: to declare that `impl for<'a> Hrtb<'a, Assoc = impl Send + '_>` captures data from argument `x`, you can add an explicit `'b` lifetime bound + | +LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> + 'b { + | ++++ +help: to declare that `impl Send + 'a` captures data from argument `x`, you can add an explicit `'b` lifetime bound + | +LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a + 'b> { + | ++++ + +error: implementation of `Hrtb` is not general enough + --> $DIR/issue-88236-2.rs:27:5 + | +LL | x + | ^ implementation of `Hrtb` is not general enough + | + = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`... + = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` + +error: implementation of `Hrtb` is not general enough + --> $DIR/issue-88236-2.rs:27:5 + | +LL | x + | ^ implementation of `Hrtb` is not general enough + | + = note: `Hrtb<'a>` would have to be implemented for the type `&()` + = note: ...but `Hrtb<'0>` is actually implemented for the type `&'0 ()`, for some specific lifetime `'0` + +error: aborting due to 8 previous errors diff --git a/tests/ui/impl-trait/issues/issue-92305.rs b/tests/ui/impl-trait/issues/issue-92305.rs index 4a89238d07e6..e16199caaaa2 100644 --- a/tests/ui/impl-trait/issues/issue-92305.rs +++ b/tests/ui/impl-trait/issues/issue-92305.rs @@ -5,6 +5,7 @@ use std::iter; fn f(data: &[T]) -> impl Iterator { //~^ ERROR: missing generics for struct `Vec` [E0107] iter::empty() + //~^ ERROR: type annotations needed } fn g(data: &[T], target: T) -> impl Iterator> { diff --git a/tests/ui/impl-trait/issues/issue-92305.stderr b/tests/ui/impl-trait/issues/issue-92305.stderr index 88fb1fb27070..55e966bd7bfd 100644 --- a/tests/ui/impl-trait/issues/issue-92305.stderr +++ b/tests/ui/impl-trait/issues/issue-92305.stderr @@ -9,6 +9,18 @@ help: add missing generic argument LL | fn f(data: &[T]) -> impl Iterator> { | +++ -error: aborting due to 1 previous error +error[E0282]: type annotations needed + --> $DIR/issue-92305.rs:7:5 + | +LL | iter::empty() + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` + | +help: consider specifying the generic argument + | +LL | iter::empty::() + | +++++ -For more information about this error, try `rustc --explain E0107`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0282. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.rs b/tests/ui/impl-trait/nested-rpit-hrtb.rs index a5db10d3a220..a3eca741daad 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.rs +++ b/tests/ui/impl-trait/nested-rpit-hrtb.rs @@ -31,9 +31,11 @@ fn one_hrtb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl Qux<'a>> {} fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {} //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet +//~| ERROR implementation of `Bar` is not general enough fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet +//~| ERROR: the trait bound `for<'a> &'a (): Qux<'_>` is not satisfied // This should resolve. fn one_hrtb_mention_fn_trait_param<'b>() -> impl for<'a> Foo<'a, Assoc = impl Qux<'b>> {} @@ -43,9 +45,11 @@ fn one_hrtb_mention_fn_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl Sized // This should resolve. fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {} +//~^ ERROR: the trait bound `for<'a> &'a (): Qux<'b>` is not satisfied // This should resolve. fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {} +//~^ ERROR implementation of `Bar` is not general enough // This should resolve. fn two_htrb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Qux<'b>> {} @@ -56,9 +60,11 @@ fn two_htrb_outlives() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> // This should resolve. fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Qux<'b>> {} +//~^ ERROR: the trait bound `for<'a, 'b> &'a (): Qux<'b>` is not satisfied // `'b` is not in scope for the outlives bound. fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} //~^ ERROR use of undeclared lifetime name `'b` [E0261] +//~| ERROR implementation of `Bar` is not general enough fn main() {} diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.stderr b/tests/ui/impl-trait/nested-rpit-hrtb.stderr index 3dbe6ebadfbf..0e0f76874e3a 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.stderr +++ b/tests/ui/impl-trait/nested-rpit-hrtb.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/nested-rpit-hrtb.rs:54:77 + --> $DIR/nested-rpit-hrtb.rs:58:77 | LL | fn two_htrb_outlives() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {} | ^^ undeclared lifetime @@ -15,7 +15,7 @@ LL | fn two_htrb_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Siz | ++++ error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/nested-rpit-hrtb.rs:61:82 + --> $DIR/nested-rpit-hrtb.rs:66:82 | LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} | ^^ undeclared lifetime @@ -66,17 +66,72 @@ LL | fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a | ^^ error: higher kinded lifetime bounds on nested opaque types are not supported yet - --> $DIR/nested-rpit-hrtb.rs:35:73 + --> $DIR/nested-rpit-hrtb.rs:36:73 | LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} | ^^ | note: lifetime declared here - --> $DIR/nested-rpit-hrtb.rs:35:44 + --> $DIR/nested-rpit-hrtb.rs:36:44 | LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} | ^^ -error: aborting due to 6 previous errors +error: implementation of `Bar` is not general enough + --> $DIR/nested-rpit-hrtb.rs:32:78 + | +LL | fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {} + | ^^ implementation of `Bar` is not general enough + | + = note: `()` must implement `Bar<'a>` + = note: ...but it actually implements `Bar<'0>`, for some specific lifetime `'0` -For more information about this error, try `rustc --explain E0261`. +error[E0277]: the trait bound `for<'a> &'a (): Qux<'_>` is not satisfied + --> $DIR/nested-rpit-hrtb.rs:36:64 + | +LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} + | ^^^^^^^^^^^^ the trait `for<'a> Qux<'_>` is not implemented for `&'a ()` + | + = help: the trait `Qux<'_>` is implemented for `()` + = help: for that trait implementation, expected `()`, found `&'a ()` + +error[E0277]: the trait bound `for<'a> &'a (): Qux<'b>` is not satisfied + --> $DIR/nested-rpit-hrtb.rs:47:79 + | +LL | fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {} + | ^^^^^^^^^^^^ the trait `for<'a> Qux<'b>` is not implemented for `&'a ()` + | + = help: the trait `Qux<'_>` is implemented for `()` + = help: for that trait implementation, expected `()`, found `&'a ()` + +error: implementation of `Bar` is not general enough + --> $DIR/nested-rpit-hrtb.rs:51:93 + | +LL | fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {} + | ^^ implementation of `Bar` is not general enough + | + = note: `()` must implement `Bar<'a>` + = note: ...but it actually implements `Bar<'0>`, for some specific lifetime `'0` + +error[E0277]: the trait bound `for<'a, 'b> &'a (): Qux<'b>` is not satisfied + --> $DIR/nested-rpit-hrtb.rs:62:64 + | +LL | fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Qux<'b>> {} + | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a, 'b> Qux<'b>` is not implemented for `&'a ()` + | + = help: the trait `Qux<'_>` is implemented for `()` + = help: for that trait implementation, expected `()`, found `&'a ()` + +error: implementation of `Bar` is not general enough + --> $DIR/nested-rpit-hrtb.rs:66:86 + | +LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} + | ^^ implementation of `Bar` is not general enough + | + = note: `()` must implement `Bar<'a>` + = note: ...but it actually implements `Bar<'0>`, for some specific lifetime `'0` + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0261, E0277. +For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/impl-trait/nested_impl_trait.rs b/tests/ui/impl-trait/nested_impl_trait.rs index c036b9e367a1..760102794c34 100644 --- a/tests/ui/impl-trait/nested_impl_trait.rs +++ b/tests/ui/impl-trait/nested_impl_trait.rs @@ -9,7 +9,7 @@ fn bad_in_ret_position(x: impl Into) -> impl Into { x } fn bad_in_fn_syntax(x: fn() -> impl Into) {} //~^ ERROR nested `impl Trait` is not allowed -//~| `impl Trait` only allowed in function and inherent method argument and return types +//~| `impl Trait` is not allowed in `fn` pointer fn bad_in_arg_position(_: impl Into) { } //~^ ERROR nested `impl Trait` is not allowed diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr index f1cafd958b05..31c3e0c90136 100644 --- a/tests/ui/impl-trait/nested_impl_trait.stderr +++ b/tests/ui/impl-trait/nested_impl_trait.stderr @@ -34,11 +34,13 @@ LL | fn bad(x: impl Into) -> impl Into { x } | | nested `impl Trait` here | outer `impl Trait` -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `fn` pointer return types +error[E0562]: `impl Trait` is not allowed in `fn` pointer return types --> $DIR/nested_impl_trait.rs:10:32 | LL | fn bad_in_fn_syntax(x: fn() -> impl Into) {} | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0277]: the trait bound `impl Debug: From>` is not satisfied --> $DIR/nested_impl_trait.rs:6:46 diff --git a/tests/ui/impl-trait/recursive-coroutine.rs b/tests/ui/impl-trait/recursive-coroutine-boxed.rs similarity index 72% rename from tests/ui/impl-trait/recursive-coroutine.rs rename to tests/ui/impl-trait/recursive-coroutine-boxed.rs index b82fe134a406..b9291f07e213 100644 --- a/tests/ui/impl-trait/recursive-coroutine.rs +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.rs @@ -1,3 +1,4 @@ +// check-pass // revisions: current next //[next] compile-flags: -Znext-solver #![feature(coroutines, coroutine_trait)] @@ -5,12 +6,8 @@ use std::ops::{Coroutine, CoroutineState}; fn foo() -> impl Coroutine { - //~^ ERROR cannot resolve opaque type - //~| NOTE recursive opaque type - //~| NOTE in this expansion of desugaring of || { let mut gen = Box::pin(foo()); - //~^ NOTE coroutine captures itself here let mut r = gen.as_mut().resume(()); while let CoroutineState::Yielded(v) = r { yield v; diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr b/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr new file mode 100644 index 000000000000..11b3c4ef0078 --- /dev/null +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr @@ -0,0 +1,11 @@ +error[E0733]: recursion in a coroutine requires boxing + --> $DIR/recursive-coroutine-indirect.rs:6:5 + | +LL | move || { + | ^^^^^^^ +LL | let x = coroutine_hold(); + | - recursive call here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr b/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr new file mode 100644 index 000000000000..11b3c4ef0078 --- /dev/null +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr @@ -0,0 +1,11 @@ +error[E0733]: recursion in a coroutine requires boxing + --> $DIR/recursive-coroutine-indirect.rs:6:5 + | +LL | move || { + | ^^^^^^^ +LL | let x = coroutine_hold(); + | - recursive call here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.rs b/tests/ui/impl-trait/recursive-coroutine-indirect.rs new file mode 100644 index 000000000000..4f8d4d330505 --- /dev/null +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.rs @@ -0,0 +1,13 @@ +// revisions: current next +//[next] compile-flags: -Znext-solver +#![feature(coroutines)] +#![allow(unconditional_recursion)] +fn coroutine_hold() -> impl Sized { + move || { //~ ERROR recursion in a coroutine requires boxing + let x = coroutine_hold(); + yield; + x; + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/recursive-coroutine.current.stderr b/tests/ui/impl-trait/recursive-coroutine.current.stderr deleted file mode 100644 index e838634ed087..000000000000 --- a/tests/ui/impl-trait/recursive-coroutine.current.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0720]: cannot resolve opaque type - --> $DIR/recursive-coroutine.rs:7:13 - | -LL | fn foo() -> impl Coroutine { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type -... -LL | let mut gen = Box::pin(foo()); - | ------- coroutine captures itself here - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-coroutine.next.stderr b/tests/ui/impl-trait/recursive-coroutine.next.stderr deleted file mode 100644 index e838634ed087..000000000000 --- a/tests/ui/impl-trait/recursive-coroutine.next.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0720]: cannot resolve opaque type - --> $DIR/recursive-coroutine.rs:7:13 - | -LL | fn foo() -> impl Coroutine { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type -... -LL | let mut gen = Box::pin(foo()); - | ------- coroutine captures itself here - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs index 8331eec906e1..432f80a1763e 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs @@ -1,6 +1,5 @@ // Test that impl trait does not allow creating recursive types that are // otherwise forbidden. - #![feature(coroutines)] #![allow(unconditional_recursion)] @@ -69,15 +68,6 @@ fn substs_change() -> impl Sized { (substs_change::<&T>(),) } -fn coroutine_hold() -> impl Sized { - //~^ ERROR - move || { - let x = coroutine_hold(); - yield; - x; - } -} - fn use_fn_ptr() -> impl Sized { // OK, error already reported fn_ptr() diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index 8e9aa8ad0a69..d5b8c531fd6e 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -1,5 +1,5 @@ error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:7:22 + --> $DIR/recursive-impl-trait-type-indirect.rs:6:22 | LL | fn option(i: i32) -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -10,7 +10,7 @@ LL | if i < 0 { None } else { Some((option(i - 1), i)) } | returning here with type `Option<(impl Sized, i32)>` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:12:15 + --> $DIR/recursive-impl-trait-type-indirect.rs:11:15 | LL | fn tuple() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -19,7 +19,7 @@ LL | (tuple(),) | ---------- returning here with type `(impl Sized,)` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:17:15 + --> $DIR/recursive-impl-trait-type-indirect.rs:16:15 | LL | fn array() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -28,7 +28,7 @@ LL | [array()] | --------- returning here with type `[impl Sized; 1]` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:22:13 + --> $DIR/recursive-impl-trait-type-indirect.rs:21:13 | LL | fn ptr() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -37,7 +37,7 @@ LL | &ptr() as *const _ | ------------------ returning here with type `*const impl Sized` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:27:16 + --> $DIR/recursive-impl-trait-type-indirect.rs:26:16 | LL | fn fn_ptr() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -46,7 +46,7 @@ LL | fn_ptr as fn() -> _ | ------------------- returning here with type `fn() -> impl Sized` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:32:25 + --> $DIR/recursive-impl-trait-type-indirect.rs:31:25 | LL | fn closure_capture() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -55,10 +55,10 @@ LL | / move || { LL | | x; | | - closure captures itself here LL | | } - | |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 35:12}` + | |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:34:5: 34:12}` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:40:29 + --> $DIR/recursive-impl-trait-type-indirect.rs:39:29 | LL | fn closure_ref_capture() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -67,28 +67,28 @@ LL | / move || { LL | | &x; | | - closure captures itself here LL | | } - | |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 43:12}` + | |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:42:5: 42:12}` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:48:21 + --> $DIR/recursive-impl-trait-type-indirect.rs:47:21 | LL | fn closure_sig() -> impl Sized { | ^^^^^^^^^^ recursive opaque type LL | LL | || closure_sig() - | ---------------- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:7}` + | ---------------- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:49:5: 49:7}` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:53:23 + --> $DIR/recursive-impl-trait-type-indirect.rs:52:23 | LL | fn coroutine_sig() -> impl Sized { | ^^^^^^^^^^ recursive opaque type LL | LL | || coroutine_sig() - | ------------------ returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:7}` + | ------------------ returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:54:5: 54:7}` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:58:27 + --> $DIR/recursive-impl-trait-type-indirect.rs:57:27 | LL | fn coroutine_capture() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -98,10 +98,10 @@ LL | | yield; LL | | x; | | - coroutine captures itself here LL | | } - | |_____- returning here with type `{coroutine@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 61:12}` + | |_____- returning here with type `{coroutine@$DIR/recursive-impl-trait-type-indirect.rs:60:5: 60:12}` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:67:35 + --> $DIR/recursive-impl-trait-type-indirect.rs:66:35 | LL | fn substs_change() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -110,16 +110,7 @@ LL | (substs_change::<&T>(),) | ------------------------ returning here with type `(impl Sized,)` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:72:24 - | -LL | fn coroutine_hold() -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -... -LL | let x = coroutine_hold(); - | - coroutine captures itself here - -error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:86:26 + --> $DIR/recursive-impl-trait-type-indirect.rs:76:26 | LL | fn mutual_recursion() -> impl Sync { | ^^^^^^^^^ recursive opaque type @@ -131,7 +122,7 @@ LL | fn mutual_recursion_b() -> impl Sized { | ---------- returning this opaque type `impl Sized` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:91:28 + --> $DIR/recursive-impl-trait-type-indirect.rs:81:28 | LL | fn mutual_recursion() -> impl Sync { | --------- returning this opaque type `impl Sync` @@ -142,6 +133,6 @@ LL | LL | mutual_recursion() | ------------------ returning here with type `impl Sync` -error: aborting due to 14 previous errors +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/where-allowed.rs b/tests/ui/impl-trait/where-allowed.rs index 158dc5ab9745..5ce63db684f3 100644 --- a/tests/ui/impl-trait/where-allowed.rs +++ b/tests/ui/impl-trait/where-allowed.rs @@ -16,47 +16,47 @@ fn in_adt_in_parameters(_: Vec) { panic!() } // Disallowed fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in `fn` pointer // Disallowed fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in `fn` pointer // Disallowed fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in `fn` pointer // Disallowed fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in `fn` pointer // Disallowed fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in the parameters of `Fn` trait bounds // Disallowed fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in the return type of `Fn` trait bounds // Disallowed fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in the parameters of `Fn` trait bounds // Allowed fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } // Disallowed fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in the parameters of `Fn` trait bounds //~^^ ERROR nested `impl Trait` is not allowed // Disallowed fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in the return type of `Fn` trait bounds // Disallowed fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in the parameters of `Fn` trait bounds //~| ERROR nested `impl Trait` is not allowed // Allowed @@ -64,11 +64,11 @@ fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() // Disallowed fn in_Fn_parameter_in_generics (_: F) { panic!() } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in the parameters of `Fn` trait bounds // Disallowed fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in the return type of `Fn` trait bounds // Allowed @@ -81,22 +81,22 @@ fn in_impl_Trait_in_return() -> impl IntoIterator { // Disallowed struct InBraceStructField { x: impl Debug } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in field types // Disallowed struct InAdtInBraceStructField { x: Vec } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in field types // Disallowed struct InTupleStructField(impl Debug); -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in field types // Disallowed enum InEnum { InBraceVariant { x: impl Debug }, - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in field types InTupleVariant(impl Debug), - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in field types } // Allowed @@ -136,10 +136,10 @@ impl DummyType { // Disallowed extern "C" { fn in_foreign_parameters(_: impl Debug); - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in `extern fn` fn in_foreign_return() -> impl Debug; - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in `extern fn` } // Allowed @@ -155,97 +155,97 @@ type InTypeAlias = impl Debug; //~^ ERROR `impl Trait` in type aliases is unstable type InReturnInTypeAlias = fn() -> impl Debug; -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in `fn` pointer //~| ERROR `impl Trait` in type aliases is unstable // Disallowed in impl headers impl PartialEq for () { - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in traits } // Disallowed in impl headers impl PartialEq<()> for impl Debug { - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in impl headers } // Disallowed in inherent impls impl impl Debug { - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in impl headers } // Disallowed in inherent impls struct InInherentImplAdt { t: T } impl InInherentImplAdt { - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in impl headers } // Disallowed in where clauses fn in_fn_where_clause() where impl Debug: Debug -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in bounds { } // Disallowed in where clauses fn in_adt_in_fn_where_clause() where Vec: Debug -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in bounds { } // Disallowed fn in_trait_parameter_in_fn_where_clause() where T: PartialEq -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in bounds { } // Disallowed fn in_Fn_parameter_in_fn_where_clause() where T: Fn(impl Debug) -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in the parameters of `Fn` trait bounds { } // Disallowed fn in_Fn_return_in_fn_where_clause() where T: Fn() -> impl Debug -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in the return type of `Fn` trait bounds { } // Disallowed struct InStructGenericParamDefault(T); -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in generic parameter defaults // Disallowed enum InEnumGenericParamDefault { Variant(T) } -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in generic parameter defaults // Disallowed trait InTraitGenericParamDefault {} -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in generic parameter defaults // Disallowed type InTypeAliasGenericParamDefault = T; -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in generic parameter defaults // Disallowed impl T {} //~^ ERROR defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions //~| WARNING this was previously accepted by the compiler but is being phased out -//~| ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~| ERROR `impl Trait` is not allowed in generic parameter defaults //~| ERROR no nominal type found // Disallowed fn in_method_generic_param_default(_: T) {} //~^ ERROR defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions //~| WARNING this was previously accepted by the compiler but is being phased out -//~| ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~| ERROR `impl Trait` is not allowed in generic parameter defaults fn main() { let _in_local_variable: impl Fn() = || {}; - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in the type of variable bindings let _in_return_in_local_variable = || -> impl Fn() { || {} }; - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in closure return types } diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index 2d8895030f2f..5e8a8637d048 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -43,227 +43,301 @@ LL | type InReturnInTypeAlias = fn() -> impl Debug; = note: see issue #63063 for more information = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `fn` pointer params +error[E0562]: `impl Trait` is not allowed in `fn` pointer parameters --> $DIR/where-allowed.rs:18:40 | LL | fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `fn` pointer return types +error[E0562]: `impl Trait` is not allowed in `fn` pointer return types --> $DIR/where-allowed.rs:22:42 | LL | fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `fn` pointer params +error[E0562]: `impl Trait` is not allowed in `fn` pointer parameters --> $DIR/where-allowed.rs:26:38 | LL | fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `fn` pointer return types +error[E0562]: `impl Trait` is not allowed in `fn` pointer return types --> $DIR/where-allowed.rs:30:40 | LL | fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait params +error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds --> $DIR/where-allowed.rs:34:49 | LL | fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait return types +error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds --> $DIR/where-allowed.rs:38:51 | LL | fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait params +error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds --> $DIR/where-allowed.rs:42:55 | LL | fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait params +error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds --> $DIR/where-allowed.rs:49:51 | LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait return types +error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds --> $DIR/where-allowed.rs:54:53 | LL | fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait params +error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds --> $DIR/where-allowed.rs:58:57 | LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait params +error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds --> $DIR/where-allowed.rs:66:38 | LL | fn in_Fn_parameter_in_generics (_: F) { panic!() } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait return types +error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds --> $DIR/where-allowed.rs:70:40 | LL | fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in field types +error[E0562]: `impl Trait` is not allowed in field types --> $DIR/where-allowed.rs:83:32 | LL | struct InBraceStructField { x: impl Debug } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in field types +error[E0562]: `impl Trait` is not allowed in field types --> $DIR/where-allowed.rs:87:41 | LL | struct InAdtInBraceStructField { x: Vec } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in field types +error[E0562]: `impl Trait` is not allowed in field types --> $DIR/where-allowed.rs:91:27 | LL | struct InTupleStructField(impl Debug); | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in field types +error[E0562]: `impl Trait` is not allowed in field types --> $DIR/where-allowed.rs:96:25 | LL | InBraceVariant { x: impl Debug }, | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in field types +error[E0562]: `impl Trait` is not allowed in field types --> $DIR/where-allowed.rs:98:20 | LL | InTupleVariant(impl Debug), | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `extern fn` params +error[E0562]: `impl Trait` is not allowed in `extern fn` parameters --> $DIR/where-allowed.rs:138:33 | LL | fn in_foreign_parameters(_: impl Debug); | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `extern fn` return types +error[E0562]: `impl Trait` is not allowed in `extern fn` return types --> $DIR/where-allowed.rs:141:31 | LL | fn in_foreign_return() -> impl Debug; | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `fn` pointer return types +error[E0562]: `impl Trait` is not allowed in `fn` pointer return types --> $DIR/where-allowed.rs:157:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in traits +error[E0562]: `impl Trait` is not allowed in traits --> $DIR/where-allowed.rs:162:16 | LL | impl PartialEq for () { | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in impl headers +error[E0562]: `impl Trait` is not allowed in impl headers --> $DIR/where-allowed.rs:167:24 | LL | impl PartialEq<()> for impl Debug { | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in impl headers +error[E0562]: `impl Trait` is not allowed in impl headers --> $DIR/where-allowed.rs:172:6 | LL | impl impl Debug { | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in impl headers +error[E0562]: `impl Trait` is not allowed in impl headers --> $DIR/where-allowed.rs:178:24 | LL | impl InInherentImplAdt { | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in bounds +error[E0562]: `impl Trait` is not allowed in bounds --> $DIR/where-allowed.rs:184:11 | LL | where impl Debug: Debug | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in bounds +error[E0562]: `impl Trait` is not allowed in bounds --> $DIR/where-allowed.rs:191:15 | LL | where Vec: Debug | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in bounds +error[E0562]: `impl Trait` is not allowed in bounds --> $DIR/where-allowed.rs:198:24 | LL | where T: PartialEq | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait params +error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds --> $DIR/where-allowed.rs:205:17 | LL | where T: Fn(impl Debug) | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait return types +error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds --> $DIR/where-allowed.rs:212:22 | LL | where T: Fn() -> impl Debug | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults +error[E0562]: `impl Trait` is not allowed in generic parameter defaults --> $DIR/where-allowed.rs:218:40 | LL | struct InStructGenericParamDefault(T); | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults +error[E0562]: `impl Trait` is not allowed in generic parameter defaults --> $DIR/where-allowed.rs:222:36 | LL | enum InEnumGenericParamDefault { Variant(T) } | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults +error[E0562]: `impl Trait` is not allowed in generic parameter defaults --> $DIR/where-allowed.rs:226:38 | LL | trait InTraitGenericParamDefault {} | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults +error[E0562]: `impl Trait` is not allowed in generic parameter defaults --> $DIR/where-allowed.rs:230:41 | LL | type InTypeAliasGenericParamDefault = T; | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults +error[E0562]: `impl Trait` is not allowed in generic parameter defaults --> $DIR/where-allowed.rs:234:11 | LL | impl T {} | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults +error[E0562]: `impl Trait` is not allowed in generic parameter defaults --> $DIR/where-allowed.rs:241:40 | LL | fn in_method_generic_param_default(_: T) {} | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in variable bindings +error[E0562]: `impl Trait` is not allowed in the type of variable bindings --> $DIR/where-allowed.rs:247:29 | LL | let _in_local_variable: impl Fn() = || {}; | ^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in closure return types +error[E0562]: `impl Trait` is not allowed in closure return types --> $DIR/where-allowed.rs:249:46 | LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | ^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions --> $DIR/where-allowed.rs:234:7 diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs index 50e12eaeb5cc..b0688e530ae7 100644 --- a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs +++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs @@ -3,9 +3,11 @@ extern "rust-intrinsic" { fn size_of() -> usize; //~ ERROR intrinsic safety mismatch + //~^ ERROR intrinsic safety mismatch #[rustc_safe_intrinsic] fn assume(b: bool); //~ ERROR intrinsic safety mismatch + //~^ ERROR intrinsic safety mismatch } fn main() {} diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr index 0c2f3be491dd..b6961275e188 100644 --- a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr +++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr @@ -5,10 +5,26 @@ LL | fn size_of() -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `assume` - --> $DIR/safe-intrinsic-mismatch.rs:8:5 + --> $DIR/safe-intrinsic-mismatch.rs:9:5 | LL | fn assume(b: bool); | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of` + --> $DIR/safe-intrinsic-mismatch.rs:5:5 + | +LL | fn size_of() -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `assume` + --> $DIR/safe-intrinsic-mismatch.rs:9:5 + | +LL | fn assume(b: bool); + | ^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors diff --git a/tests/ui/issues/issue-23611-enum-swap-in-drop.rs b/tests/ui/issues/issue-23611-enum-swap-in-drop.rs index cdb130d600c5..b967e6aecdd4 100644 --- a/tests/ui/issues/issue-23611-enum-swap-in-drop.rs +++ b/tests/ui/issues/issue-23611-enum-swap-in-drop.rs @@ -37,11 +37,9 @@ pub fn main() { // | | | +-- Make D(g_b_5, 50000005) // | | | | in g_B(b4b2) from GaspB::drop // | | | +-- Drop D(g_b_5, 50000005) - 50000005, - // | | | + 50000005, // | | | // | | +-- Drop D(GaspB::drop_3, 30000004) - 30000004, - // | | + 30000004, // | | // +-- Drop D(test_1, 10000000) 10000000, // | @@ -49,15 +47,13 @@ pub fn main() { // | | +-- Make D(f_a_4, 40000007) // | | | in f_A(a3a0) from GaspA::drop // | | +-- Drop D(f_a_4, 40000007) - 40000007, - // | | + 40000007, // | | // +-- Drop D(GaspA::drop_2, 20000006) - 20000006, - // | + 20000006, // | // +-- Drop D(drop_6, 60000002) - 60000002 - // - ]); + 60000002 // + ] + ); // For reference purposes, the old (incorrect) behavior would produce the following // output, which you can compare to the above: @@ -106,8 +102,8 @@ fn test<'a>(log: d::Log<'a>) { let _e = E::B(GaspB(g_b, 0xB4B0, log, D::new("test", 1, log)), true); } -struct GaspA<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>); -struct GaspB<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>); +struct GaspA<'a>(for<'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>); +struct GaspB<'a>(for<'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>); impl<'a> Drop for GaspA<'a> { fn drop(&mut self) { @@ -124,7 +120,8 @@ impl<'a> Drop for GaspB<'a> { } enum E<'a> { - A(GaspA<'a>, bool), B(GaspB<'a>, bool), + A(GaspA<'a>, bool), + B(GaspB<'a>, bool), } fn f_a(x: u32, ctxt: &str, log: d::Log) { @@ -174,9 +171,9 @@ const PREF_INDENT: u32 = 20; pub mod d { #![allow(unused_parens)] + use std::cell::RefCell; use std::fmt; use std::mem; - use std::cell::RefCell; static mut counter: u16 = 0; static mut trails: u64 = 0; @@ -189,7 +186,8 @@ pub mod d { pub fn max_width() -> u32 { unsafe { - (mem::size_of_val(&trails)*8) as u32 + (mem::size_of_val(&trails) * 8) as u32 + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] } } @@ -223,7 +221,11 @@ pub mod d { } pub struct D<'a> { - name: &'static str, i: u8, uid: u32, trail: u32, log: Log<'a> + name: &'static str, + i: u8, + uid: u32, + trail: u32, + log: Log<'a>, } impl<'a> fmt::Display for D<'a> { @@ -239,9 +241,7 @@ pub mod d { let ctr = ((i as u32) * 10_000_000) + (counter as u32); counter += 1; trails |= (1 << trail); - let ret = D { - name: name, i: i, log: log, uid: ctr, trail: trail - }; + let ret = D { name: name, i: i, log: log, uid: ctr, trail: trail }; indent_println(trail, &format!("+-- Make {}", ret)); ret } @@ -250,7 +250,9 @@ pub mod d { impl<'a> Drop for D<'a> { fn drop(&mut self) { - unsafe { trails &= !(1 << self.trail); }; + unsafe { + trails &= !(1 << self.trail); + }; self.log.borrow_mut().push(self.uid); indent_println(self.trail, &format!("+-- Drop {}", self)); indent_println(::PREF_INDENT, ""); diff --git a/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr b/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr new file mode 100644 index 000000000000..14a986a33326 --- /dev/null +++ b/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr @@ -0,0 +1,17 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/issue-23611-enum-swap-in-drop.rs:189:31 + | +LL | (mem::size_of_val(&trails) * 8) as u32 + | ^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | (mem::size_of_val(addr_of!(trails)) * 8) as u32 + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-31910.rs b/tests/ui/issues/issue-31910.rs index e0655d3f6dbf..19cfc4627c75 100644 --- a/tests/ui/issues/issue-31910.rs +++ b/tests/ui/issues/issue-31910.rs @@ -1,4 +1,5 @@ enum Enum { + //~^ ERROR: `T` is never used X = Trait::Number, //~^ ERROR mismatched types //~| expected `isize`, found `i32` diff --git a/tests/ui/issues/issue-31910.stderr b/tests/ui/issues/issue-31910.stderr index 6ef84d7daef5..89a6d5574a1e 100644 --- a/tests/ui/issues/issue-31910.stderr +++ b/tests/ui/issues/issue-31910.stderr @@ -1,9 +1,18 @@ error[E0308]: mismatched types - --> $DIR/issue-31910.rs:2:9 + --> $DIR/issue-31910.rs:3:9 | LL | X = Trait::Number, | ^^^^^^^^^^^^^ expected `isize`, found `i32` -error: aborting due to 1 previous error +error[E0392]: parameter `T` is never used + --> $DIR/issue-31910.rs:1:11 + | +LL | enum Enum { + | ^ unused parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` -For more information about this error, try `rustc --explain E0308`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0392. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/issues/issue-3214.rs b/tests/ui/issues/issue-3214.rs index b2c27f5be957..03d8d6ba2465 100644 --- a/tests/ui/issues/issue-3214.rs +++ b/tests/ui/issues/issue-3214.rs @@ -5,6 +5,7 @@ fn foo() { impl Drop for Foo { //~^ ERROR struct takes 0 generic arguments but 1 generic argument + //~| ERROR `T` is not constrained fn drop(&mut self) {} } } diff --git a/tests/ui/issues/issue-3214.stderr b/tests/ui/issues/issue-3214.stderr index 5b57c1baf90b..26ac6d39f601 100644 --- a/tests/ui/issues/issue-3214.stderr +++ b/tests/ui/issues/issue-3214.stderr @@ -22,7 +22,13 @@ note: struct defined here, with 0 generic parameters LL | struct Foo { | ^^^ -error: aborting due to 2 previous errors +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-3214.rs:6:10 + | +LL | impl Drop for Foo { + | ^ unconstrained type parameter -Some errors have detailed explanations: E0107, E0401. +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0107, E0207, E0401. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/issues/issue-34373.rs b/tests/ui/issues/issue-34373.rs index ca24e37d9bb1..dc20c5589b33 100644 --- a/tests/ui/issues/issue-34373.rs +++ b/tests/ui/issues/issue-34373.rs @@ -5,6 +5,8 @@ trait Trait { } pub struct Foo>>; //~ ERROR cycle detected +//~^ ERROR `T` is never used +//~| ERROR `Trait` cannot be made into an object type DefaultFoo = Foo; fn main() { diff --git a/tests/ui/issues/issue-34373.stderr b/tests/ui/issues/issue-34373.stderr index c6906734b2de..1a1cfc925b77 100644 --- a/tests/ui/issues/issue-34373.stderr +++ b/tests/ui/issues/issue-34373.stderr @@ -5,7 +5,7 @@ LL | pub struct Foo>>; | ^^^^^^^^^^ | note: ...which requires expanding type alias `DefaultFoo`... - --> $DIR/issue-34373.rs:8:19 + --> $DIR/issue-34373.rs:10:19 | LL | type DefaultFoo = Foo; | ^^^ @@ -23,6 +23,38 @@ LL | | } | |_^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 1 previous error +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/issue-34373.rs:7:24 + | +LL | pub struct Foo>>; + | ^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/issue-34373.rs:4:8 + | +LL | trait Trait { + | ----- this trait cannot be made into an object... +LL | fn foo(_: T) {} + | ^^^ ...because associated function `foo` has no `self` parameter +help: consider turning `foo` into a method by giving it a `&self` argument + | +LL | fn foo(&self, _: T) {} + | ++++++ +help: alternatively, consider constraining `foo` so it does not apply to trait objects + | +LL | fn foo(_: T) where Self: Sized {} + | +++++++++++++++++ -For more information about this error, try `rustc --explain E0391`. +error[E0392]: parameter `T` is never used + --> $DIR/issue-34373.rs:7:16 + | +LL | pub struct Foo>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unused parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: usize` instead + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0038, E0391, E0392. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/issues/issue-47715.rs b/tests/ui/issues/issue-47715.rs index 0a770593bc9c..bf2b03351b29 100644 --- a/tests/ui/issues/issue-47715.rs +++ b/tests/ui/issues/issue-47715.rs @@ -7,22 +7,22 @@ trait Iterable { } struct Container> { - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in generics field: T } enum Enum> { - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in generics A(T), } union Union + Copy> { - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in generics x: T, } type Type> = T; -//~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR `impl Trait` is not allowed in generics fn main() { } diff --git a/tests/ui/issues/issue-47715.stderr b/tests/ui/issues/issue-47715.stderr index 2ded98781c64..8ed9ff439521 100644 --- a/tests/ui/issues/issue-47715.stderr +++ b/tests/ui/issues/issue-47715.stderr @@ -1,26 +1,34 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generics +error[E0562]: `impl Trait` is not allowed in generics --> $DIR/issue-47715.rs:9:37 | LL | struct Container> { | ^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generics +error[E0562]: `impl Trait` is not allowed in generics --> $DIR/issue-47715.rs:14:30 | LL | enum Enum> { | ^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generics +error[E0562]: `impl Trait` is not allowed in generics --> $DIR/issue-47715.rs:19:32 | LL | union Union + Copy> { | ^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generics +error[E0562]: `impl Trait` is not allowed in generics --> $DIR/issue-47715.rs:24:30 | LL | type Type> = T; | ^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 4 previous errors diff --git a/tests/ui/lang-items/lang-item-generic-requirements.rs b/tests/ui/lang-items/lang-item-generic-requirements.rs index 21bd7187e15b..697790023d6c 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.rs +++ b/tests/ui/lang-items/lang-item-generic-requirements.rs @@ -22,8 +22,8 @@ trait MyIndex<'a, T> {} #[lang = "phantom_data"] //~^ ERROR `phantom_data` language item must be applied to a struct with 1 generic argument struct MyPhantomData; -//~^ ERROR parameter `T` is never used -//~| ERROR parameter `U` is never used +//~^ ERROR `T` is never used +//~| ERROR `U` is never used #[lang = "owned_box"] //~^ ERROR `owned_box` language item must be applied to a struct with at least 1 generic argument @@ -41,8 +41,7 @@ fn ice() { // Use add let r = 5; let a = 6; - r + a; - //~^ ERROR cannot add `{integer}` to `{integer}` + r + a; //~ ERROR cannot add // Use drop in place my_ptr_drop(); diff --git a/tests/ui/lifetimes/issue-95023.rs b/tests/ui/lifetimes/issue-95023.rs index 3fba8c00c572..e35f1a36e2a2 100644 --- a/tests/ui/lifetimes/issue-95023.rs +++ b/tests/ui/lifetimes/issue-95023.rs @@ -3,7 +3,9 @@ struct Error(ErrorKind); impl Fn(&isize) for Error { //~^ ERROR manual implementations of `Fn` are experimental [E0183] //~^^ ERROR associated type bindings are not allowed here [E0229] - fn foo(&self) -> Self::B<{N}>; + //~| ERROR not all trait items implemented + //~| ERROR expected a `FnMut(&isize)` closure, found `Error` + fn foo(&self) -> Self::B<{ N }>; //~^ ERROR associated function in `impl` without body //~^^ ERROR method `foo` is not a member of trait `Fn` [E0407] //~^^^ ERROR associated type `B` not found for `Self` [E0220] diff --git a/tests/ui/lifetimes/issue-95023.stderr b/tests/ui/lifetimes/issue-95023.stderr index 6361d8ad30bd..b9c95d3e49a4 100644 --- a/tests/ui/lifetimes/issue-95023.stderr +++ b/tests/ui/lifetimes/issue-95023.stderr @@ -1,16 +1,16 @@ error: associated function in `impl` without body - --> $DIR/issue-95023.rs:6:5 + --> $DIR/issue-95023.rs:8:5 | -LL | fn foo(&self) -> Self::B<{N}>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | help: provide a definition for the function: `{ }` +LL | fn foo(&self) -> Self::B<{ N }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the function: `{ }` error[E0407]: method `foo` is not a member of trait `Fn` - --> $DIR/issue-95023.rs:6:5 + --> $DIR/issue-95023.rs:8:5 | -LL | fn foo(&self) -> Self::B<{N}>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `Fn` +LL | fn foo(&self) -> Self::B<{ N }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `Fn` error[E0183]: manual implementations of `Fn` are experimental --> $DIR/issue-95023.rs:3:6 @@ -33,12 +33,30 @@ LL | impl Fn(&isize) for Error { | ^^^^^^^^^^ error[E0220]: associated type `B` not found for `Self` - --> $DIR/issue-95023.rs:6:44 + --> $DIR/issue-95023.rs:8:44 | -LL | fn foo(&self) -> Self::B<{N}>; +LL | fn foo(&self) -> Self::B<{ N }>; | ^ help: `Self` has the following associated type: `Output` -error: aborting due to 5 previous errors +error[E0277]: expected a `FnMut(&isize)` closure, found `Error` + --> $DIR/issue-95023.rs:3:21 + | +LL | impl Fn(&isize) for Error { + | ^^^^^ expected an `FnMut(&isize)` closure, found `Error` + | + = help: the trait `FnMut<(&isize,)>` is not implemented for `Error` +note: required by a bound in `Fn` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL -Some errors have detailed explanations: E0183, E0220, E0229, E0407. -For more information about an error, try `rustc --explain E0183`. +error[E0046]: not all trait items implemented, missing: `call` + --> $DIR/issue-95023.rs:3:1 + | +LL | impl Fn(&isize) for Error { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing `call` in implementation + | + = help: implement the missing item: `fn call(&self, _: (&isize,)) -> >::Output { todo!() }` + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0046, E0183, E0220, E0229, E0277, E0407. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/lifetimes/missing-lifetime-in-alias.rs b/tests/ui/lifetimes/missing-lifetime-in-alias.rs index 51c564c011a8..a0887b36b8a9 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-alias.rs +++ b/tests/ui/lifetimes/missing-lifetime-in-alias.rs @@ -4,6 +4,7 @@ trait Trait<'a> { type Bar<'b> //~^ NOTE associated type defined here, with 1 lifetime parameter //~| NOTE + //~| NOTE where Self: 'b; } @@ -13,6 +14,8 @@ struct Impl<'a>(&'a ()); impl<'a> Trait<'a> for Impl<'a> { type Foo = &'a (); type Bar<'b> = &'b (); + //~^ ERROR: does not fulfill the required lifetime + //~| NOTE: type must outlive the lifetime `'b` } type A<'a> = Impl<'a>; diff --git a/tests/ui/lifetimes/missing-lifetime-in-alias.stderr b/tests/ui/lifetimes/missing-lifetime-in-alias.stderr index 20159e144072..9183e6302eef 100644 --- a/tests/ui/lifetimes/missing-lifetime-in-alias.stderr +++ b/tests/ui/lifetimes/missing-lifetime-in-alias.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-alias.rs:20:24 + --> $DIR/missing-lifetime-in-alias.rs:23:24 | LL | type B<'a> = as Trait>::Foo; | ^^^^^ expected named lifetime parameter @@ -10,13 +10,13 @@ LL | type B<'a> = as Trait<'a>>::Foo; | ++++ error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-alias.rs:24:28 + --> $DIR/missing-lifetime-in-alias.rs:27:28 | LL | type C<'a, 'b> = as Trait>::Bar; | ^^^^^ expected named lifetime parameter | note: these named lifetimes are available to use - --> $DIR/missing-lifetime-in-alias.rs:24:8 + --> $DIR/missing-lifetime-in-alias.rs:27:8 | LL | type C<'a, 'b> = as Trait>::Bar; | ^^ ^^ @@ -26,7 +26,7 @@ LL | type C<'a, 'b> = as Trait<'lifetime>>::Bar; | +++++++++++ error[E0107]: missing generics for associated type `Trait::Bar` - --> $DIR/missing-lifetime-in-alias.rs:24:36 + --> $DIR/missing-lifetime-in-alias.rs:27:36 | LL | type C<'a, 'b> = as Trait>::Bar; | ^^^ expected 1 lifetime argument @@ -41,7 +41,26 @@ help: add missing lifetime argument LL | type C<'a, 'b> = as Trait>::Bar<'a>; | ++++ -error: aborting due to 3 previous errors +error[E0477]: the type `Impl<'a>` does not fulfill the required lifetime + --> $DIR/missing-lifetime-in-alias.rs:16:20 + | +LL | type Bar<'b> + | ------------ definition of `Bar` from trait +... +LL | type Bar<'b> = &'b (); + | ^^^^^^ + | +note: type must outlive the lifetime `'b` as defined here + --> $DIR/missing-lifetime-in-alias.rs:16:14 + | +LL | type Bar<'b> = &'b (); + | ^^ +help: copy the `where` clause predicates from the trait + | +LL | type Bar<'b> = &'b () where Self: 'b; + | ++++++++++++++ -Some errors have detailed explanations: E0106, E0107. +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0106, E0107, E0477. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/lint/let_underscore/issue-119696-err-on-fn.rs b/tests/ui/lint/let_underscore/issue-119696-err-on-fn.rs new file mode 100644 index 000000000000..8e15b4da35a4 --- /dev/null +++ b/tests/ui/lint/let_underscore/issue-119696-err-on-fn.rs @@ -0,0 +1,21 @@ +// edition: 2021 + +#![deny(let_underscore_drop)] +fn main() { + let _ = foo(); //~ ERROR non-binding let on a type that implements `Drop` +} + +async fn from_config(_: Config) {} + +async fn foo() { + from_config(Config { + nickname: None, + ..Default::default() + }) + .await; +} + +#[derive(Default)] +struct Config { + nickname: Option>, +} diff --git a/tests/ui/lint/let_underscore/issue-119696-err-on-fn.stderr b/tests/ui/lint/let_underscore/issue-119696-err-on-fn.stderr new file mode 100644 index 000000000000..86e521580b87 --- /dev/null +++ b/tests/ui/lint/let_underscore/issue-119696-err-on-fn.stderr @@ -0,0 +1,22 @@ +error: non-binding let on a type that implements `Drop` + --> $DIR/issue-119696-err-on-fn.rs:5:5 + | +LL | let _ = foo(); + | ^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-119696-err-on-fn.rs:3:9 + | +LL | #![deny(let_underscore_drop)] + | ^^^^^^^^^^^^^^^^^^^ +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL | let _unused = foo(); + | ~~~~~~~ +help: consider immediately dropping the value + | +LL | drop(foo()); + | ~~~~~ + + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/let_underscore/issue-119697-extra-let.rs b/tests/ui/lint/let_underscore/issue-119697-extra-let.rs new file mode 100644 index 000000000000..1dc80a123f61 --- /dev/null +++ b/tests/ui/lint/let_underscore/issue-119697-extra-let.rs @@ -0,0 +1,21 @@ +#![deny(let_underscore_drop)] +#![feature(type_alias_impl_trait)] + +pub struct Foo { + /// This type must have nontrivial drop glue + field: String, +} + +pub type Tait = impl Sized; + +pub fn ice_cold(beverage: Tait) { + // Must destructure at least one field of `Foo` + let Foo { field } = beverage; + // boom + _ = field; //~ ERROR non-binding let on a type that implements `Drop` + + let _ = field; //~ ERROR non-binding let on a type that implements `Drop` +} + + +pub fn main() {} diff --git a/tests/ui/lint/let_underscore/issue-119697-extra-let.stderr b/tests/ui/lint/let_underscore/issue-119697-extra-let.stderr new file mode 100644 index 000000000000..16df2c720eaf --- /dev/null +++ b/tests/ui/lint/let_underscore/issue-119697-extra-let.stderr @@ -0,0 +1,37 @@ +error: non-binding let on a type that implements `Drop` + --> $DIR/issue-119697-extra-let.rs:15:5 + | +LL | _ = field; + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-119697-extra-let.rs:1:9 + | +LL | #![deny(let_underscore_drop)] + | ^^^^^^^^^^^^^^^^^^^ +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL | let _unused = field; + | ~~~~~~~~~~~ +help: consider immediately dropping the value + | +LL | drop(field); + | ~~~~~ + + +error: non-binding let on a type that implements `Drop` + --> $DIR/issue-119697-extra-let.rs:17:5 + | +LL | let _ = field; + | ^^^^^^^^^^^^^^ + | +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL | let _unused = field; + | ~~~~~~~ +help: consider immediately dropping the value + | +LL | drop(field); + | ~~~~~ + + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/wide_pointer_comparisons.rs b/tests/ui/lint/wide_pointer_comparisons.rs index 8334575cf529..961b998c9566 100644 --- a/tests/ui/lint/wide_pointer_comparisons.rs +++ b/tests/ui/lint/wide_pointer_comparisons.rs @@ -107,6 +107,15 @@ fn main() { //~^ WARN ambiguous wide pointer comparison } + { + macro_rules! cmp { + ($a:tt, $b:tt) => { $a == $b } + //~^ WARN ambiguous wide pointer comparison + } + + cmp!(a, b); + } + { macro_rules! cmp { ($a:ident, $b:ident) => { $a == $b } diff --git a/tests/ui/lint/wide_pointer_comparisons.stderr b/tests/ui/lint/wide_pointer_comparisons.stderr index 926b8775902c..349ff467d0fb 100644 --- a/tests/ui/lint/wide_pointer_comparisons.stderr +++ b/tests/ui/lint/wide_pointer_comparisons.stderr @@ -421,7 +421,18 @@ LL | std::ptr::eq(*a, *b) | ~~~~~~~~~~~~~ ~ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:112:39 + --> $DIR/wide_pointer_comparisons.rs:112:33 + | +LL | ($a:tt, $b:tt) => { $a == $b } + | ^^^^^^^^ + | +help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses + | +LL | ($a:tt, $b:tt) => { std::ptr::addr_eq($a, $b) } + | ++++++++++++++++++ ~ + + +warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected + --> $DIR/wide_pointer_comparisons.rs:121:39 | LL | ($a:ident, $b:ident) => { $a == $b } | ^^^^^^^^ @@ -436,7 +447,7 @@ LL | ($a:ident, $b:ident) => { std::ptr::addr_eq($a, $b) } | ++++++++++++++++++ ~ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:122:37 + --> $DIR/wide_pointer_comparisons.rs:131:37 | LL | ($a:expr, $b:expr) => { $a == $b } | ^^ @@ -448,5 +459,5 @@ LL | cmp!(&a, &b); = help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses = note: this warning originates in the macro `cmp` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: 37 warnings emitted +warning: 38 warnings emitted diff --git a/tests/ui/methods/method-on-ambiguous-numeric-type.rs b/tests/ui/methods/method-on-ambiguous-numeric-type.rs index 82f47438d505..f42b72e9f9c1 100644 --- a/tests/ui/methods/method-on-ambiguous-numeric-type.rs +++ b/tests/ui/methods/method-on-ambiguous-numeric-type.rs @@ -5,6 +5,9 @@ macro_rules! local_mac { ($ident:ident) => { let $ident = 42; } } +macro_rules! local_mac_tt { + ($tt:tt) => { let $tt = 42; } +} fn main() { let x = 2.0.neg(); @@ -23,6 +26,10 @@ fn main() { local_mac!(local_bar); local_bar.pow(2); //~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}` + + local_mac_tt!(local_bar_tt); + local_bar_tt.pow(2); + //~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}` } fn qux() { diff --git a/tests/ui/methods/method-on-ambiguous-numeric-type.stderr b/tests/ui/methods/method-on-ambiguous-numeric-type.stderr index 91733411637d..060595e1d406 100644 --- a/tests/ui/methods/method-on-ambiguous-numeric-type.stderr +++ b/tests/ui/methods/method-on-ambiguous-numeric-type.stderr @@ -1,5 +1,5 @@ error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` - --> $DIR/method-on-ambiguous-numeric-type.rs:10:17 + --> $DIR/method-on-ambiguous-numeric-type.rs:13:17 | LL | let x = 2.0.neg(); | ^^^ @@ -10,7 +10,7 @@ LL | let x = 2.0_f32.neg(); | ~~~~~~~ error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` - --> $DIR/method-on-ambiguous-numeric-type.rs:14:15 + --> $DIR/method-on-ambiguous-numeric-type.rs:17:15 | LL | let x = y.neg(); | ^^^ @@ -21,7 +21,7 @@ LL | let y: f32 = 2.0; | +++++ error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` - --> $DIR/method-on-ambiguous-numeric-type.rs:19:26 + --> $DIR/method-on-ambiguous-numeric-type.rs:22:26 | LL | for i in 0..100 { | - you must specify a type for this binding, like `i32` @@ -29,7 +29,7 @@ LL | println!("{}", i.pow(2)); | ^^^ error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` - --> $DIR/method-on-ambiguous-numeric-type.rs:24:15 + --> $DIR/method-on-ambiguous-numeric-type.rs:27:15 | LL | local_bar.pow(2); | ^^^ @@ -40,7 +40,18 @@ LL | ($ident:ident) => { let $ident: i32 = 42; } | +++++ error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` - --> $DIR/method-on-ambiguous-numeric-type.rs:30:9 + --> $DIR/method-on-ambiguous-numeric-type.rs:31:18 + | +LL | local_bar_tt.pow(2); + | ^^^ + | +help: you must specify a type for this binding, like `i32` + | +LL | ($tt:tt) => { let $tt: i32 = 42; } + | +++++ + +error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` + --> $DIR/method-on-ambiguous-numeric-type.rs:37:9 | LL | bar.pow(2); | ^^^ @@ -51,6 +62,6 @@ help: you must specify a type for this binding, like `i32` LL | ($ident:ident) => { let $ident: i32 = 42; } | +++++ -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0689`. diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs index 7d3b00dfc716..8eb544e8ab9d 100644 --- a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs +++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs @@ -14,9 +14,8 @@ struct S1 { impl S1 { fn new(_x: u64) -> S1 { - S1 { - a: unsafe { &mut X1 }, - } + S1 { a: unsafe { &mut X1 } } + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] } } diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr new file mode 100644 index 000000000000..17217cd5859d --- /dev/null +++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr @@ -0,0 +1,17 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/borrowck-thread-local-static-mut-borrow-outlives-fn.rs:17:26 + | +LL | S1 { a: unsafe { &mut X1 } } + | ^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | S1 { a: unsafe { addr_of_mut!(X1) } } + | ~~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/nll/issue-54302.stderr b/tests/ui/nll/issue-54302.stderr index 269739af6026..a1e2d4014290 100644 --- a/tests/ui/nll/issue-54302.stderr +++ b/tests/ui/nll/issue-54302.stderr @@ -4,7 +4,7 @@ error: implementation of `Deserialize` is not general enough LL | assert_deserialize_owned::<&'static str>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough | - = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`... + = note: `&str` must implement `Deserialize<'0>`, for any lifetime `'0`... = note: ...but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1` error: aborting due to 1 previous error diff --git a/tests/ui/numbers-arithmetic/overflowing-rsh-6.rs b/tests/ui/numbers-arithmetic/overflowing-rsh-6.rs deleted file mode 100644 index f75e779ed158..000000000000 --- a/tests/ui/numbers-arithmetic/overflowing-rsh-6.rs +++ /dev/null @@ -1,9 +0,0 @@ -// build-fail -// compile-flags: -C debug-assertions - -#![deny(arithmetic_overflow)] - -fn main() { - let _n = 1i64 >> [64][0]; - //~^ ERROR: this arithmetic operation will overflow -} diff --git a/tests/ui/numbers-arithmetic/overflowing-rsh-6.stderr b/tests/ui/numbers-arithmetic/overflowing-rsh-6.stderr deleted file mode 100644 index 005f7378226c..000000000000 --- a/tests/ui/numbers-arithmetic/overflowing-rsh-6.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: this arithmetic operation will overflow - --> $DIR/overflowing-rsh-6.rs:7:14 - | -LL | let _n = 1i64 >> [64][0]; - | ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow - | -note: the lint level is defined here - --> $DIR/overflowing-rsh-6.rs:4:9 - | -LL | #![deny(arithmetic_overflow)] - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs index 51be999a6329..345c8a25f79f 100644 --- a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs +++ b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs @@ -15,6 +15,7 @@ fn is_static(_: T) where T: 'static { } // code forces us into a conservative, hacky path. fn bar(x: &str) -> &dyn Foo { &() } //~^ ERROR please supply an explicit bound +//~| ERROR `(): Foo<'_>` is not satisfied fn main() { let s = format!("foo"); diff --git a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr index 688f8af0822b..d227c8778fe5 100644 --- a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr +++ b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr @@ -4,6 +4,20 @@ error[E0228]: the lifetime bound for this object type cannot be deduced from con LL | fn bar(x: &str) -> &dyn Foo { &() } | ^^^^^^^ -error: aborting due to 1 previous error +error[E0277]: the trait bound `(): Foo<'_>` is not satisfied + --> $DIR/object-lifetime-default-dyn-binding-nonstatic3.rs:16:47 + | +LL | fn bar(x: &str) -> &dyn Foo { &() } + | ^^^ the trait `Foo<'_>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/object-lifetime-default-dyn-binding-nonstatic3.rs:4:1 + | +LL | trait Foo<'a> { + | ^^^^^^^^^^^^^ + = note: required for the cast from `&()` to `&dyn Foo<'_, Item = dyn Bar>` -For more information about this error, try `rustc --explain E0228`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0228, E0277. +For more information about an error, try `rustc --explain E0228`. diff --git a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.rs b/tests/ui/object-safety/object-safety-supertrait-mentions-Self.rs index 2445b33c8144..d96c7ba72a3c 100644 --- a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.rs +++ b/tests/ui/object-safety/object-safety-supertrait-mentions-Self.rs @@ -6,6 +6,7 @@ trait Bar { } trait Baz : Bar { + //~^ ERROR the size for values of type `Self` cannot be known } fn make_bar>(t: &T) -> &dyn Bar { diff --git a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr b/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr index fc476691d014..22adc19c8029 100644 --- a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr +++ b/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Baz` cannot be made into an object - --> $DIR/object-safety-supertrait-mentions-Self.rs:15:31 + --> $DIR/object-safety-supertrait-mentions-Self.rs:16:31 | LL | fn make_baz(t: &T) -> &dyn Baz { | ^^^^^^^ `Baz` cannot be made into an object @@ -16,6 +16,27 @@ help: consider using an opaque type instead LL | fn make_baz(t: &T) -> &impl Baz { | ~~~~ -error: aborting due to 1 previous error +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/object-safety-supertrait-mentions-Self.rs:8:13 + | +LL | trait Baz : Bar { + | ^^^^^^^^^ doesn't have a size known at compile-time + | +note: required by a bound in `Bar` + --> $DIR/object-safety-supertrait-mentions-Self.rs:4:11 + | +LL | trait Bar { + | ^ required by this bound in `Bar` +help: consider further restricting `Self` + | +LL | trait Baz : Bar + Sized { + | +++++++ +help: consider relaxing the implicit `Sized` restriction + | +LL | trait Bar { + | ++++++++ -For more information about this error, try `rustc --explain E0038`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0038, E0277. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/parser/impl-item-type-no-body-semantic-fail.rs b/tests/ui/parser/impl-item-type-no-body-semantic-fail.rs index 1291a021bef5..5582e82d11d0 100644 --- a/tests/ui/parser/impl-item-type-no-body-semantic-fail.rs +++ b/tests/ui/parser/impl-item-type-no-body-semantic-fail.rs @@ -17,4 +17,5 @@ impl X { type W where Self: Eq; //~^ ERROR associated type in `impl` without body //~| ERROR inherent associated types are unstable + //~| ERROR duplicate definitions } diff --git a/tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr b/tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr index 3856754e080a..5bcbbb9deb75 100644 --- a/tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr +++ b/tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr @@ -78,6 +78,16 @@ LL | type W where Self: Eq; = note: see issue #8995 for more information = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable -error: aborting due to 10 previous errors +error[E0592]: duplicate definitions with name `W` + --> $DIR/impl-item-type-no-body-semantic-fail.rs:17:5 + | +LL | type W: Ord where Self: Eq; + | ------ other definition for `W` +... +LL | type W where Self: Eq; + | ^^^^^^ duplicate definitions for `W` -For more information about this error, try `rustc --explain E0658`. +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0592, E0658. +For more information about an error, try `rustc --explain E0592`. diff --git a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs index 5f731f8db775..cf754a6854ec 100644 --- a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs +++ b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs @@ -16,4 +16,5 @@ fn y<'a>(y: &mut 'a + Send) { //~| ERROR at least one trait is required for an object type let z = y as &mut 'a + Send; //~^ ERROR expected value, found trait `Send` + //~| ERROR at least one trait is required for an object type } diff --git a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr index 799bc16bd6ab..652aeff5dd44 100644 --- a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr +++ b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr @@ -33,7 +33,13 @@ error[E0224]: at least one trait is required for an object type LL | fn y<'a>(y: &mut 'a + Send) { | ^^ -error: aborting due to 5 previous errors +error[E0224]: at least one trait is required for an object type + --> $DIR/issue-73568-lifetime-after-mut.rs:17:23 + | +LL | let z = y as &mut 'a + Send; + | ^^ + +error: aborting due to 6 previous errors Some errors have detailed explanations: E0178, E0224, E0423. For more information about an error, try `rustc --explain E0178`. diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout index 6d10cc604c27..3672a3590fd7 100644 --- a/tests/ui/proc-macro/meta-macro-hygiene.stdout +++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout @@ -50,6 +50,9 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") +crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") +crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") +crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index 5c70e780f748..d3c2c46ac75c 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -73,6 +73,9 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #3, kind: Macro(Bang, "inner") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") +crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") +crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") +crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") diff --git a/tests/ui/resolve/auxiliary/suggest-constructor-cycle-error.rs b/tests/ui/resolve/auxiliary/suggest-constructor-cycle-error.rs new file mode 100644 index 000000000000..8de68c38bc34 --- /dev/null +++ b/tests/ui/resolve/auxiliary/suggest-constructor-cycle-error.rs @@ -0,0 +1,12 @@ +mod m { + pub struct Uuid(()); + + impl Uuid { + pub fn encode_buffer() -> [u8; LENGTH] { + [] + } + } + const LENGTH: usize = 0; +} + +pub use m::Uuid; diff --git a/tests/ui/resolve/suggest-constructor-cycle-error.rs b/tests/ui/resolve/suggest-constructor-cycle-error.rs new file mode 100644 index 000000000000..e36fffd97d1b --- /dev/null +++ b/tests/ui/resolve/suggest-constructor-cycle-error.rs @@ -0,0 +1,10 @@ +// aux-build:suggest-constructor-cycle-error.rs + +// Regression test for https://github.com/rust-lang/rust/issues/119625 + +extern crate suggest_constructor_cycle_error as a; + +const CONST_NAME: a::Uuid = a::Uuid(()); +//~^ ERROR: cannot initialize a tuple struct which contains private fields [E0423] + +fn main() {} diff --git a/tests/ui/resolve/suggest-constructor-cycle-error.stderr b/tests/ui/resolve/suggest-constructor-cycle-error.stderr new file mode 100644 index 000000000000..c6ec2465a432 --- /dev/null +++ b/tests/ui/resolve/suggest-constructor-cycle-error.stderr @@ -0,0 +1,15 @@ +error[E0423]: cannot initialize a tuple struct which contains private fields + --> $DIR/suggest-constructor-cycle-error.rs:7:29 + | +LL | const CONST_NAME: a::Uuid = a::Uuid(()); + | ^^^^^^^ + | +note: constructor is not visible here due to private fields + --> $DIR/auxiliary/suggest-constructor-cycle-error.rs:2:21 + | +LL | pub struct Uuid(()); + | ^^ private field + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs index f41c1051fcea..16b717bc1813 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs @@ -9,7 +9,7 @@ trait Foo { } const fn foo() { - ::Assoc::foo(); + ::Assoc::foo(); } fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr index 1b88839984f4..268e337ee93e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr @@ -6,15 +6,17 @@ LL | type Assoc: ~const Foo; | = note: this item cannot have `~const` trait bounds -error[E0308]: mismatched types - --> $DIR/assoc-type-const-bound-usage.rs:12:5 +error[E0277]: the trait bound `T: Foo` is not satisfied + --> $DIR/assoc-type-const-bound-usage.rs:12:6 | -LL | ::Assoc::foo(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `host`, found `true` +LL | ::Assoc::foo(); + | ^ the trait `Foo` is not implemented for `T` | - = note: expected constant `host` - found constant `true` +help: consider further restricting this bound + | +LL | const fn foo() { + | +++++ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs new file mode 100644 index 000000000000..f3480fcc9eed --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs @@ -0,0 +1,86 @@ +// check-pass + +#![crate_type = "lib"] +#![allow(internal_features)] +#![no_std] +#![no_core] +#![feature( + auto_traits, + const_trait_impl, + effects, + lang_items, + no_core, + staged_api, + unboxed_closures +)] +#![stable(feature = "minicore", since = "1.0.0")] + +fn test() { + fn is_const_fn(_: F) + where + F: const FnOnce<()>, + { + } + + const fn foo() {} + + is_const_fn(foo); +} + +/// ---------------------------------------------------------------------- /// +/// Const fn trait definitions + +#[const_trait] +#[lang = "fn"] +#[rustc_paren_sugar] +trait Fn: ~const FnMut { + extern "rust-call" fn call(&self, args: Args) -> Self::Output; +} + +#[const_trait] +#[lang = "fn_mut"] +#[rustc_paren_sugar] +trait FnMut: ~const FnOnce { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +#[const_trait] +#[lang = "fn_once"] +#[rustc_paren_sugar] +trait FnOnce { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +/// ---------------------------------------------------------------------- /// +/// All this other stuff needed for core. Unrelated to test. + +#[lang = "destruct"] +#[const_trait] +trait Destruct {} + +#[lang = "freeze"] +unsafe auto trait Freeze {} + +#[lang = "drop"] +#[const_trait] +trait Drop { + fn drop(&mut self); +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +#[lang = "tuple_trait"] +trait Tuple {} + +#[lang = "receiver"] +trait Receiver {} + +impl Receiver for &T {} + +impl Receiver for &mut T {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr index f0b6e2b1c255..d20404e63b3f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr @@ -10,5 +10,15 @@ LL | impl const A for () {} = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error: aborting due to 1 previous error +error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates + --> $DIR/const-impl-requires-const-trait.rs:8:6 + | +LL | impl const A for () {} + | ^^^^^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs index 14d306fc31f6..9d579e67a4be 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs @@ -1,4 +1,6 @@ // known-bug: #110395 +// Broken until we have `&T: const Deref` impl in stdlib + #![allow(incomplete_features)] #![feature( associated_type_bounds, diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr index ddedf8f1d8d2..d4be71f2f466 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr @@ -1,28 +1,28 @@ -error[E0277]: can't compare `impl PartialEq + Destruct + Copy` with `impl PartialEq + Destruct + Copy` - --> $DIR/const-impl-trait.rs:28:17 +error[E0277]: can't compare `()` with `()` + --> $DIR/const-impl-trait.rs:37:17 | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `impl PartialEq + Destruct + Copy == impl PartialEq + Destruct + Copy` +LL | assert!(cmp(&())); + | --- ^^^ no implementation for `() == ()` + | | + | required by a bound introduced by this call | - = help: the trait `~const PartialEq` is not implemented for `impl PartialEq + Destruct + Copy` -note: required by a bound in `Foo::{opaque#0}` - --> $DIR/const-impl-trait.rs:24:22 + = help: the trait `const PartialEq` is not implemented for `()` + = help: the trait `PartialEq` is implemented for `()` +note: required by a bound in `cmp` + --> $DIR/const-impl-trait.rs:14:23 | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^^^^^^^^^ required by this bound in `Foo::{opaque#0}` +LL | const fn cmp(a: &impl ~const PartialEq) -> bool { + | ^^^^^^^^^^^^^^^^ required by this bound in `cmp` -error[E0277]: can't drop `impl PartialEq + Destruct + Copy` - --> $DIR/const-impl-trait.rs:28:17 +error[E0369]: binary operation `==` cannot be applied to type `&impl ~const PartialEq` + --> $DIR/const-impl-trait.rs:15:7 | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `impl PartialEq + Destruct + Copy` - | -note: required by a bound in `Foo::{opaque#0}` - --> $DIR/const-impl-trait.rs:24:41 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^^^^^^^^ required by this bound in `Foo::{opaque#0}` +LL | a == a + | - ^^ - &impl ~const PartialEq + | | + | &impl ~const PartialEq error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0369. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr index dfe8fa79e264..4b009446dbc0 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr @@ -8,5 +8,11 @@ LL | #[derive_const(Default)] = note: adding a non-const method body in the future would be a breaking change = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error +error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr index c561f80653c9..8f374bc4d8f2 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr @@ -23,6 +23,21 @@ LL | #[derive_const(Default, PartialEq)] = note: adding a non-const method body in the future would be a breaking change = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates + --> $DIR/derive-const-use.rs:7:6 + | +LL | impl const Default for A { + | ^^^^^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported -For more information about this error, try `rustc --explain E0635`. +error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0207, E0635. +For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs index c6be75a6a2f0..7d817d09c7f0 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs @@ -1,12 +1,14 @@ #![feature(const_trait_impl, effects)] const fn test() -> impl ~const Fn() { //~ ERROR `~const` can only be applied to `#[const_trait]` traits + //~^ ERROR cycle detected const move || { //~ ERROR const closures are experimental let sl: &[u8] = b"foo"; match sl { [first, remainder @ ..] => { assert_eq!(first, &b'f'); + //~^ ERROR can't compare `&u8` with `&u8` } [] => panic!(), } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr index fe6b613d1549..7e268f50dca3 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr @@ -1,5 +1,5 @@ error[E0658]: const closures are experimental - --> $DIR/ice-112822-expected-type-for-param.rs:4:5 + --> $DIR/ice-112822-expected-type-for-param.rs:5:5 | LL | const move || { | ^^^^^ @@ -13,6 +13,47 @@ error: `~const` can only be applied to `#[const_trait]` traits LL | const fn test() -> impl ~const Fn() { | ^^^^ -error: aborting due to 2 previous errors +error[E0277]: can't compare `&u8` with `&u8` + --> $DIR/ice-112822-expected-type-for-param.rs:10:17 + | +LL | assert_eq!(first, &b'f'); + | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&u8 == &u8` + | + = help: the trait `~const PartialEq<&u8>` is not implemented for `&u8` + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) -For more information about this error, try `rustc --explain E0658`. +error[E0391]: cycle detected when computing type of opaque `test::{opaque#0}` + --> $DIR/ice-112822-expected-type-for-param.rs:3:20 + | +LL | const fn test() -> impl ~const Fn() { + | ^^^^^^^^^^^^^^^^ + | +note: ...which requires borrow-checking `test`... + --> $DIR/ice-112822-expected-type-for-param.rs:3:1 + | +LL | const fn test() -> impl ~const Fn() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `test`... + --> $DIR/ice-112822-expected-type-for-param.rs:3:1 + | +LL | const fn test() -> impl ~const Fn() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const checking `test`... + --> $DIR/ice-112822-expected-type-for-param.rs:3:1 + | +LL | const fn test() -> impl ~const Fn() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing whether `test::{opaque#0}` is freeze... + = note: ...which requires evaluating trait selection obligation `test::{opaque#0}: core::marker::Freeze`... + = note: ...which again requires computing type of opaque `test::{opaque#0}`, completing the cycle +note: cycle used when computing type of `test::{opaque#0}` + --> $DIR/ice-112822-expected-type-for-param.rs:3:20 + | +LL | const fn test() -> impl ~const Fn() { + | ^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0391, E0658. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs index 59fb48e794cc..84d9bcd7ac9f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs @@ -40,7 +40,7 @@ const fn bar() { #[lang = "Try"] #[const_trait] -trait Try: FromResidual { +trait Try: FromResidual { type Output; type Residual; @@ -53,7 +53,7 @@ trait Try: FromResidual { // FIXME // #[const_trait] -trait FromResidual::Residual> { +trait FromResidual::Residual> { #[lang = "from_residual"] fn from_residual(residual: R) -> Self; } @@ -519,9 +519,14 @@ extern "rust-intrinsic" { called_in_const: F, called_at_rt: G, ) -> RET - /* where clauses enforced by built-in method confirmation: where - F: const FnOnce, - G: FnOnce, - */; + F: const FnOnce, + G: FnOnce; +} + +fn test_const_eval_select() { + const fn const_fn() {} + fn rt_fn() {} + + unsafe { const_eval_select((), const_fn, rt_fn); } } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs index b30d7743edfc..e22eed3e0ef5 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs @@ -1,7 +1,12 @@ -// check-pass +// known-bug: #110395 +// FIXME: effects + #![feature(const_trait_impl, effects)] -pub trait Owo::T> {} +// This fails because `~const Uwu` doesn't imply (non-const) `Uwu`. + +// FIXME: #[const_trait] +pub trait Owo::T> {} #[const_trait] pub trait Uwu: Owo { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.stderr new file mode 100644 index 000000000000..eac3ee9e4e22 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.stderr @@ -0,0 +1,65 @@ +error[E0277]: the trait bound `Self: Uwu` is not satisfied + --> $DIR/project.rs:12:1 + | +LL | pub trait Uwu: Owo { + | ^^^^^^^^^^^^^^^^^^ the trait `Uwu` is not implemented for `Self` + | +help: consider further restricting `Self` + | +LL | pub trait Uwu: Owo + Uwu { + | +++++ + +error[E0277]: the trait bound `Self: Uwu` is not satisfied + --> $DIR/project.rs:12:1 + | +LL | / pub trait Uwu: Owo { +LL | | type T; +LL | | } + | |_^ the trait `Uwu` is not implemented for `Self` + | +help: consider further restricting `Self` + | +LL | pub trait Uwu: Owo + Uwu { + | +++++ + +error[E0277]: the trait bound `Self: Uwu` is not satisfied + --> $DIR/project.rs:12:16 + | +LL | pub trait Uwu: Owo { + | ^^^ the trait `Uwu` is not implemented for `Self` + | +note: required by a bound in `Owo` + --> $DIR/project.rs:9:15 + | +LL | pub trait Owo::T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Owo` +help: consider further restricting `Self` + | +LL | pub trait Uwu: Owo + Uwu { + | +++++ + +error[E0277]: the trait bound `Self: Uwu` is not satisfied + --> $DIR/project.rs:13:5 + | +LL | type T; + | ^^^^^^ the trait `Uwu` is not implemented for `Self` + | +help: consider further restricting `Self` + | +LL | pub trait Uwu: Owo + Uwu { + | +++++ + +error[E0277]: the trait bound `Self: Uwu` is not satisfied + --> $DIR/project.rs:13:5 + | +LL | type T; + | ^^^^^^^ the trait `Uwu` is not implemented for `Self` + | +help: consider further restricting `Self` + | +LL | pub trait Uwu: Owo + Uwu { + | +++++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr index eae313ef0874..ac25812c42df 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr @@ -24,5 +24,13 @@ LL | trait Bar: ~const Foo {} | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 3 previous errors +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-2.rs:10:19 + | +LL | trait Bar: ~const Foo {} + | ^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr index be3153d6a081..5273f7e48eb8 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr @@ -12,5 +12,13 @@ LL | trait Bar: ~const Foo {} | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 2 previous errors +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-2.rs:10:19 + | +LL | trait Bar: ~const Foo {} + | ^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs index abdf0feee038..120399f0c787 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs @@ -10,7 +10,8 @@ trait Foo { trait Bar: ~const Foo {} //[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]` //[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` -//[yn,nn]~^^^ ERROR: `~const` is not allowed here +//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` +//[yn,nn]~^^^^ ERROR: `~const` is not allowed here const fn foo(x: &T) { x.a(); diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr index c05c4d50a33d..53445d255903 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr @@ -11,7 +11,7 @@ LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/super-traits-fail-2.rs:16:5 + --> $DIR/super-traits-fail-2.rs:17:5 | LL | x.a(); | ^^^^^ expected `host`, found `true` diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr index 852c02cad5ca..681647945d0a 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/super-traits-fail-2.rs:16:5 + --> $DIR/super-traits-fail-2.rs:17:5 | LL | x.a(); | ^^^^^ expected `host`, found `true` diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr index 834d6f4dcf38..2c63c0217aba 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr @@ -25,10 +25,18 @@ LL | trait Bar: ~const Foo {} = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:17:24 + --> $DIR/super-traits-fail-3.rs:18:24 | LL | const fn foo(x: &T) { | ^^^ -error: aborting due to 4 previous errors +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:12:19 + | +LL | trait Bar: ~const Foo {} + | ^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 5 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr index 4fdd2284c475..f737cb243df4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr @@ -12,5 +12,13 @@ LL | trait Bar: ~const Foo {} | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 2 previous errors +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:12:19 + | +LL | trait Bar: ~const Foo {} + | ^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs index 30131d5849c8..745668c4dd43 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs @@ -12,11 +12,13 @@ trait Foo { trait Bar: ~const Foo {} //[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]` //[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` -//[yn,nn]~^^^ ERROR: `~const` is not allowed here +//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` +//[yn,nn]~^^^^ ERROR: `~const` is not allowed here const fn foo(x: &T) { //[yn,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]` x.a(); + //[yn]~^ ERROR: mismatched types } fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr index ab7c814eb498..de7a11cf1551 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr @@ -11,10 +11,20 @@ LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:17:24 + --> $DIR/super-traits-fail-3.rs:18:24 | LL | const fn foo(x: &T) { | ^^^ -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/super-traits-fail-3.rs:20:5 + | +LL | x.a(); + | ^^^^^ expected `host`, found `true` + | + = note: expected constant `host` + found constant `true` +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-assoc-fn-in-trait-impl.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-assoc-fn-in-trait-impl.rs new file mode 100644 index 000000000000..a848b6d2fc9f --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-assoc-fn-in-trait-impl.rs @@ -0,0 +1,29 @@ +// Regression test for issue #119700. +// check-pass + +#![feature(const_trait_impl, effects)] + +#[const_trait] +trait Main { + fn compute() -> u32; +} + +impl const Main for () { + fn compute() -> u32 { + T::generate() + } +} + +#[const_trait] +trait Aux { + fn generate() -> u32; +} + +impl const Aux for () { + fn generate() -> u32 { 1024 } +} + +fn main() { + const _: u32 = <()>::compute::<()>(); + let _ = <()>::compute::<()>(); +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-inherent-assoc-const-fn.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs rename to tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-inherent-assoc-const-fn.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs index 5ecb75094f03..9d220686771e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs @@ -9,10 +9,12 @@ fn non_const_function() {} //~ ERROR `~const` is not allowed struct Struct { field: T } //~ ERROR `~const` is not allowed here struct TupleStruct(T); //~ ERROR `~const` is not allowed here struct UnitStruct; //~ ERROR `~const` is not allowed here +//~^ ERROR parameter `T` is never used enum Enum { Variant(T) } //~ ERROR `~const` is not allowed here union Union { field: T } //~ ERROR `~const` is not allowed here +//~^ ERROR field must implement `Copy` type Type = T; //~ ERROR `~const` is not allowed here @@ -30,6 +32,7 @@ trait NonConstTrait { impl NonConstTrait for () { type Type = (); //~ ERROR `~const` is not allowed + //~^ ERROR overflow evaluating the requirement `(): Trait` fn non_const_function() {} //~ ERROR `~const` is not allowed const CONSTANT: () = (); //~ ERROR `~const` is not allowed //~^ ERROR generic const items are experimental diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr index 497ec5bcf84d..a54ba7a94b4a 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr @@ -35,7 +35,7 @@ LL | struct UnitStruct; = note: this item cannot have `~const` trait bounds error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:13:14 + --> $DIR/tilde-const-invalid-places.rs:14:14 | LL | enum Enum { Variant(T) } | ^^^^^^ @@ -43,7 +43,7 @@ LL | enum Enum { Variant(T) } = note: this item cannot have `~const` trait bounds error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:15:16 + --> $DIR/tilde-const-invalid-places.rs:16:16 | LL | union Union { field: T } | ^^^^^^ @@ -51,7 +51,7 @@ LL | union Union { field: T } = note: this item cannot have `~const` trait bounds error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:17:14 + --> $DIR/tilde-const-invalid-places.rs:19:14 | LL | type Type = T; | ^^^^^^ @@ -59,7 +59,7 @@ LL | type Type = T; = note: this item cannot have `~const` trait bounds error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:19:19 + --> $DIR/tilde-const-invalid-places.rs:21:19 | LL | const CONSTANT: () = (); | ^^^^^^ @@ -67,7 +67,7 @@ LL | const CONSTANT: () = (); = note: this item cannot have `~const` trait bounds error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:23:18 + --> $DIR/tilde-const-invalid-places.rs:25:18 | LL | type Type: ~const Trait; | ^^^^^^ @@ -75,7 +75,7 @@ LL | type Type: ~const Trait; = note: this item cannot have `~const` trait bounds error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:23:33 + --> $DIR/tilde-const-invalid-places.rs:25:33 | LL | type Type: ~const Trait; | ^^^^^^ @@ -83,19 +83,19 @@ LL | type Type: ~const Trait; = note: this item cannot have `~const` trait bounds error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:26:30 + --> $DIR/tilde-const-invalid-places.rs:28:30 | LL | fn non_const_function(); | ^^^^^^ | note: this function is not `const`, so it cannot have `~const` trait bounds - --> $DIR/tilde-const-invalid-places.rs:26:8 + --> $DIR/tilde-const-invalid-places.rs:28:8 | LL | fn non_const_function(); | ^^^^^^^^^^^^^^^^^^ error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:27:23 + --> $DIR/tilde-const-invalid-places.rs:29:23 | LL | const CONSTANT: (); | ^^^^^^ @@ -103,7 +103,7 @@ LL | const CONSTANT: (); = note: this item cannot have `~const` trait bounds error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:32:18 + --> $DIR/tilde-const-invalid-places.rs:34:18 | LL | type Type = (); | ^^^^^^ @@ -111,19 +111,19 @@ LL | type Type = (); = note: this item cannot have `~const` trait bounds error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:33:30 + --> $DIR/tilde-const-invalid-places.rs:36:30 | LL | fn non_const_function() {} | ^^^^^^ | note: this function is not `const`, so it cannot have `~const` trait bounds - --> $DIR/tilde-const-invalid-places.rs:33:8 + --> $DIR/tilde-const-invalid-places.rs:36:8 | LL | fn non_const_function() {} | ^^^^^^^^^^^^^^^^^^ error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:34:23 + --> $DIR/tilde-const-invalid-places.rs:37:23 | LL | const CONSTANT: () = (); | ^^^^^^ @@ -131,7 +131,7 @@ LL | const CONSTANT: () = (); = note: this item cannot have `~const` trait bounds error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:41:18 + --> $DIR/tilde-const-invalid-places.rs:44:18 | LL | type Type = (); | ^^^^^^ @@ -139,19 +139,19 @@ LL | type Type = (); = note: this item cannot have `~const` trait bounds error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:43:30 + --> $DIR/tilde-const-invalid-places.rs:46:30 | LL | fn non_const_function() {} | ^^^^^^ | note: this function is not `const`, so it cannot have `~const` trait bounds - --> $DIR/tilde-const-invalid-places.rs:43:8 + --> $DIR/tilde-const-invalid-places.rs:46:8 | LL | fn non_const_function() {} | ^^^^^^^^^^^^^^^^^^ error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:44:23 + --> $DIR/tilde-const-invalid-places.rs:47:23 | LL | const CONSTANT: () = (); | ^^^^^^ @@ -159,55 +159,55 @@ LL | const CONSTANT: () = (); = note: this item cannot have `~const` trait bounds error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:49:15 + --> $DIR/tilde-const-invalid-places.rs:52:15 | LL | trait Child0: ~const Trait {} | ^^^^^^ | note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - --> $DIR/tilde-const-invalid-places.rs:49:1 + --> $DIR/tilde-const-invalid-places.rs:52:1 | LL | trait Child0: ~const Trait {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:50:26 + --> $DIR/tilde-const-invalid-places.rs:53:26 | LL | trait Child1 where Self: ~const Trait {} | ^^^^^^ | note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - --> $DIR/tilde-const-invalid-places.rs:50:1 + --> $DIR/tilde-const-invalid-places.rs:53:1 | LL | trait Child1 where Self: ~const Trait {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:53:9 + --> $DIR/tilde-const-invalid-places.rs:56:9 | LL | impl Trait for T {} | ^^^^^^ | note: this impl is not `const`, so it cannot have `~const` trait bounds - --> $DIR/tilde-const-invalid-places.rs:53:1 + --> $DIR/tilde-const-invalid-places.rs:56:1 | LL | impl Trait for T {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `~const` is not allowed here - --> $DIR/tilde-const-invalid-places.rs:56:9 + --> $DIR/tilde-const-invalid-places.rs:59:9 | LL | impl Struct {} | ^^^^^^ | note: inherent impls cannot have `~const` trait bounds - --> $DIR/tilde-const-invalid-places.rs:56:1 + --> $DIR/tilde-const-invalid-places.rs:59:1 | LL | impl Struct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0658]: generic const items are experimental - --> $DIR/tilde-const-invalid-places.rs:19:15 + --> $DIR/tilde-const-invalid-places.rs:21:15 | LL | const CONSTANT: () = (); | ^^^^^^^^^^^^^^^^^ @@ -216,7 +216,7 @@ LL | const CONSTANT: () = (); = help: add `#![feature(generic_const_items)]` to the crate attributes to enable error[E0658]: generic const items are experimental - --> $DIR/tilde-const-invalid-places.rs:27:19 + --> $DIR/tilde-const-invalid-places.rs:29:19 | LL | const CONSTANT: (); | ^^^^^^^^^^^^^^^^^ @@ -225,7 +225,7 @@ LL | const CONSTANT: (); = help: add `#![feature(generic_const_items)]` to the crate attributes to enable error[E0658]: generic const items are experimental - --> $DIR/tilde-const-invalid-places.rs:34:19 + --> $DIR/tilde-const-invalid-places.rs:37:19 | LL | const CONSTANT: () = (); | ^^^^^^^^^^^^^^^^^ @@ -234,7 +234,7 @@ LL | const CONSTANT: () = (); = help: add `#![feature(generic_const_items)]` to the crate attributes to enable error[E0658]: generic const items are experimental - --> $DIR/tilde-const-invalid-places.rs:44:19 + --> $DIR/tilde-const-invalid-places.rs:47:19 | LL | const CONSTANT: () = (); | ^^^^^^^^^^^^^^^^^ @@ -243,7 +243,7 @@ LL | const CONSTANT: () = (); = help: add `#![feature(generic_const_items)]` to the crate attributes to enable error[E0658]: inherent associated types are unstable - --> $DIR/tilde-const-invalid-places.rs:41:5 + --> $DIR/tilde-const-invalid-places.rs:44:5 | LL | type Type = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -251,6 +251,39 @@ LL | type Type = (); = note: see issue #8995 for more information = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable -error: aborting due to 27 previous errors +error[E0392]: parameter `T` is never used + --> $DIR/tilde-const-invalid-places.rs:11:19 + | +LL | struct UnitStruct; + | ^ unused parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` -For more information about this error, try `rustc --explain E0658`. +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/tilde-const-invalid-places.rs:16:32 + | +LL | union Union { field: T } + | ^^^^^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | union Union { field: std::mem::ManuallyDrop } + | +++++++++++++++++++++++ + + +error[E0275]: overflow evaluating the requirement `(): Trait` + --> $DIR/tilde-const-invalid-places.rs:34:34 + | +LL | type Type = (); + | ^^ + | +note: required by a bound in `NonConstTrait::Type` + --> $DIR/tilde-const-invalid-places.rs:25:33 + | +LL | type Type: ~const Trait; + | ^^^^^^^^^^^^ required by this bound in `NonConstTrait::Type` + +error: aborting due to 30 previous errors + +Some errors have detailed explanations: E0275, E0392, E0658, E0740. +For more information about an error, try `rustc --explain E0275`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr index 2a9647da7823..0141dcfb06f6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr @@ -1,21 +1,35 @@ -error[E0308]: mismatched types +error[E0277]: the trait bound `T: ~const Bar` is not satisfied --> $DIR/trait-where-clause-const.rs:21:5 | LL | T::b(); - | ^^^^^^ expected `host`, found `true` + | ^ the trait `~const Bar` is not implemented for `T` | - = note: expected constant `host` - found constant `true` +note: required by a bound in `Foo::b` + --> $DIR/trait-where-clause-const.rs:15:24 + | +LL | fn b() where Self: ~const Bar; + | ^^^^^^^^^^ required by this bound in `Foo::b` +help: consider further restricting this bound + | +LL | const fn test1() { + | ++++++++++++ -error[E0308]: mismatched types - --> $DIR/trait-where-clause-const.rs:23:5 +error[E0277]: the trait bound `T: ~const Bar` is not satisfied + --> $DIR/trait-where-clause-const.rs:23:12 | LL | T::c::(); - | ^^^^^^^^^^^ expected `host`, found `true` + | ^ the trait `~const Bar` is not implemented for `T` | - = note: expected constant `host` - found constant `true` +note: required by a bound in `Foo::c` + --> $DIR/trait-where-clause-const.rs:16:13 + | +LL | fn c(); + | ^^^^^^^^^^ required by this bound in `Foo::c` +help: consider further restricting this bound + | +LL | const fn test1() { + | ++++++++++++ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs index 62a7b3123784..8f441410c178 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs @@ -30,4 +30,4 @@ fn accept0(_: Container<{ T::make() }>) {} // FIXME(effects): Instead of suggesting `+ const Trait`, suggest // changing `~const Trait` to `const Trait`. const fn accept1(_: Container<{ T::make() }>) {} -//~^ ERROR the trait bound `T: const Trait` is not satisfied +//~^ ERROR mismatched types diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr index 2fb4fc1aa2b8..258f95b5c4a8 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr @@ -7,16 +7,14 @@ LL | fn accept0(_: Container<{ T::make() }>) {} = note: expected constant `false` found constant `true` -error[E0277]: the trait bound `T: const Trait` is not satisfied +error[E0308]: mismatched types --> $DIR/unsatisfied-const-trait-bound.rs:32:50 | LL | const fn accept1(_: Container<{ T::make() }>) {} - | ^ the trait `const Trait` is not implemented for `T` + | ^^^^^^^^^ expected `false`, found `host` | -help: consider further restricting this bound - | -LL | const fn accept1(_: Container<{ T::make() }>) {} - | +++++++++++++ + = note: expected constant `false` + found constant `host` error[E0277]: the trait bound `Ty: const Trait` is not satisfied --> $DIR/unsatisfied-const-trait-bound.rs:20:15 diff --git a/tests/ui/self/arbitrary_self_types_pin_needing_borrow.stderr b/tests/ui/self/arbitrary_self_types_pin_needing_borrow.stderr index ec985b254b34..1811cd6753ff 100644 --- a/tests/ui/self/arbitrary_self_types_pin_needing_borrow.stderr +++ b/tests/ui/self/arbitrary_self_types_pin_needing_borrow.stderr @@ -6,7 +6,7 @@ LL | Pin::new(S).x(); | | | required by a bound introduced by this call | -note: required by a bound in `Pin::

::new` +note: required by a bound in `Pin::::new` --> $SRC_DIR/core/src/pin.rs:LL:COL help: consider borrowing here | diff --git a/tests/ui/shell-argfiles/shell-argfiles-badquotes-windows.rs b/tests/ui/shell-argfiles/shell-argfiles-badquotes-windows.rs new file mode 100644 index 000000000000..800735cf3a76 --- /dev/null +++ b/tests/ui/shell-argfiles/shell-argfiles-badquotes-windows.rs @@ -0,0 +1,11 @@ +// Check to see if we can get parameters from an @argsfile file +// +// Path replacement in .stderr files (i.e. `$DIR`) doesn't handle mixed path +// separators. This test uses backslash as the path separator for the command +// line arguments and is only run on windows. +// +// only-windows +// compile-flags: --cfg cmdline_set -Z shell-argfiles @shell:{{src-base}}\shell-argfiles\shell-argfiles-badquotes.args + +fn main() { +} diff --git a/tests/ui/shell-argfiles/shell-argfiles-badquotes-windows.stderr b/tests/ui/shell-argfiles/shell-argfiles-badquotes-windows.stderr new file mode 100644 index 000000000000..14adb1f740ab --- /dev/null +++ b/tests/ui/shell-argfiles/shell-argfiles-badquotes-windows.stderr @@ -0,0 +1,2 @@ +error: Failed to load argument file: Invalid shell-style arguments in $DIR/shell-argfiles-badquotes.args + diff --git a/tests/ui/shell-argfiles/shell-argfiles-badquotes.args b/tests/ui/shell-argfiles/shell-argfiles-badquotes.args new file mode 100644 index 000000000000..c0d531adf3ff --- /dev/null +++ b/tests/ui/shell-argfiles/shell-argfiles-badquotes.args @@ -0,0 +1 @@ +"--cfg" "unquoted_set diff --git a/tests/ui/shell-argfiles/shell-argfiles-badquotes.rs b/tests/ui/shell-argfiles/shell-argfiles-badquotes.rs new file mode 100644 index 000000000000..f9160143a041 --- /dev/null +++ b/tests/ui/shell-argfiles/shell-argfiles-badquotes.rs @@ -0,0 +1,12 @@ +// Check to see if we can get parameters from an @argsfile file +// +// Path replacement in .stderr files (i.e. `$DIR`) doesn't handle mixed path +// separators. We have a duplicated version of this test that uses backslash as +// the path separator for the command line arguments that is only run on +// windows. +// +// ignore-windows +// compile-flags: --cfg cmdline_set -Z shell-argfiles @shell:{{src-base}}/shell-argfiles/shell-argfiles-badquotes.args + +fn main() { +} diff --git a/tests/ui/shell-argfiles/shell-argfiles-badquotes.stderr b/tests/ui/shell-argfiles/shell-argfiles-badquotes.stderr new file mode 100644 index 000000000000..14adb1f740ab --- /dev/null +++ b/tests/ui/shell-argfiles/shell-argfiles-badquotes.stderr @@ -0,0 +1,2 @@ +error: Failed to load argument file: Invalid shell-style arguments in $DIR/shell-argfiles-badquotes.args + diff --git a/tests/ui/shell-argfiles/shell-argfiles-via-argfile-shell.args b/tests/ui/shell-argfiles/shell-argfiles-via-argfile-shell.args new file mode 100644 index 000000000000..4e66d5a03952 --- /dev/null +++ b/tests/ui/shell-argfiles/shell-argfiles-via-argfile-shell.args @@ -0,0 +1 @@ +"--cfg" "shell_args_set" \ No newline at end of file diff --git a/tests/ui/shell-argfiles/shell-argfiles-via-argfile.args b/tests/ui/shell-argfiles/shell-argfiles-via-argfile.args new file mode 100644 index 000000000000..d0af54e24e33 --- /dev/null +++ b/tests/ui/shell-argfiles/shell-argfiles-via-argfile.args @@ -0,0 +1 @@ +-Zshell-argfiles \ No newline at end of file diff --git a/tests/ui/shell-argfiles/shell-argfiles-via-argfile.rs b/tests/ui/shell-argfiles/shell-argfiles-via-argfile.rs new file mode 100644 index 000000000000..d71e3218f53b --- /dev/null +++ b/tests/ui/shell-argfiles/shell-argfiles-via-argfile.rs @@ -0,0 +1,10 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-pass +// compile-flags: @{{src-base}}/shell-argfiles/shell-argfiles-via-argfile.args @shell:{{src-base}}/shell-argfiles/shell-argfiles-via-argfile-shell.args + +#[cfg(not(shell_args_set))] +compile_error!("shell_args_set not set"); + +fn main() { +} diff --git a/tests/ui/shell-argfiles/shell-argfiles.args b/tests/ui/shell-argfiles/shell-argfiles.args new file mode 100644 index 000000000000..e5bb4b807ec4 --- /dev/null +++ b/tests/ui/shell-argfiles/shell-argfiles.args @@ -0,0 +1,3 @@ +--cfg unquoted_set +'--cfg' 'single_quoted_set' +"--cfg" "double_quoted_set" diff --git a/tests/ui/shell-argfiles/shell-argfiles.rs b/tests/ui/shell-argfiles/shell-argfiles.rs new file mode 100644 index 000000000000..9bc252ea628a --- /dev/null +++ b/tests/ui/shell-argfiles/shell-argfiles.rs @@ -0,0 +1,19 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-pass +// compile-flags: --cfg cmdline_set -Z shell-argfiles @shell:{{src-base}}/shell-argfiles/shell-argfiles.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unquoted_set))] +compile_error!("unquoted_set not set"); + +#[cfg(not(single_quoted_set))] +compile_error!("single_quoted_set not set"); + +#[cfg(not(double_quoted_set))] +compile_error!("double_quoted_set not set"); + +fn main() { +} diff --git a/tests/ui/stability-attribute/generics-default-stability-where.rs b/tests/ui/stability-attribute/generics-default-stability-where.rs index 4afbca262649..142de12e1529 100644 --- a/tests/ui/stability-attribute/generics-default-stability-where.rs +++ b/tests/ui/stability-attribute/generics-default-stability-where.rs @@ -5,6 +5,7 @@ extern crate unstable_generic_param; use unstable_generic_param::*; impl Trait3 for T where T: Trait2 { //~ ERROR use of unstable library feature 'unstable_default' +//~^ ERROR `T` must be used as the type parameter for some local type fn foo() -> usize { T::foo() } } diff --git a/tests/ui/stability-attribute/generics-default-stability-where.stderr b/tests/ui/stability-attribute/generics-default-stability-where.stderr index ce34f96771c4..16b560e8a4be 100644 --- a/tests/ui/stability-attribute/generics-default-stability-where.stderr +++ b/tests/ui/stability-attribute/generics-default-stability-where.stderr @@ -6,6 +6,16 @@ LL | impl Trait3 for T where T: Trait2 { | = help: add `#![feature(unstable_default)]` to the crate attributes to enable -error: aborting due to 1 previous error +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/generics-default-stability-where.rs:7:6 + | +LL | impl Trait3 for T where T: Trait2 { + | ^ type parameter `T` must be used as the type parameter for some local type + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local + = note: only traits defined in the current crate can be implemented for a type parameter -For more information about this error, try `rustc --explain E0658`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0210, E0658. +For more information about an error, try `rustc --explain E0210`. diff --git a/tests/ui/static/reference-of-mut-static-safe.e2021.stderr b/tests/ui/static/reference-of-mut-static-safe.e2021.stderr new file mode 100644 index 000000000000..16f47ace3a93 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-safe.e2021.stderr @@ -0,0 +1,26 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static-safe.rs:9:14 + | +LL | let _x = &X; + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _x = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/reference-of-mut-static-safe.rs:9:15 + | +LL | let _x = &X; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/static/reference-of-mut-static-safe.e2024.stderr b/tests/ui/static/reference-of-mut-static-safe.e2024.stderr new file mode 100644 index 000000000000..53f81179de55 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-safe.e2024.stderr @@ -0,0 +1,15 @@ +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-safe.rs:9:14 + | +LL | let _x = &X; + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _x = addr_of!(X); + | ~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0796`. diff --git a/tests/ui/static/reference-of-mut-static-safe.rs b/tests/ui/static/reference-of-mut-static-safe.rs new file mode 100644 index 000000000000..5cb1a03bef51 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-safe.rs @@ -0,0 +1,13 @@ +// revisions: e2021 e2024 + +// [e2021] edition:2021 +// [e2024] compile-flags: --edition 2024 -Z unstable-options + +fn main() { + static mut X: i32 = 1; + + let _x = &X; + //[e2024]~^ reference of mutable static is disallowed [E0796] + //[e2021]~^^ use of mutable static is unsafe and requires unsafe function or block [E0133] + //[e2021]~^^^ shared reference of mutable static is discouraged [static_mut_ref] +} diff --git a/tests/ui/static/reference-of-mut-static-unsafe-fn.rs b/tests/ui/static/reference-of-mut-static-unsafe-fn.rs new file mode 100644 index 000000000000..6b1e77850e50 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-unsafe-fn.rs @@ -0,0 +1,23 @@ +// compile-flags: --edition 2024 -Z unstable-options + +fn main() {} + +unsafe fn _foo() { + static mut X: i32 = 1; + static mut Y: i32 = 1; + + let _y = &X; + //~^ ERROR reference of mutable static is disallowed + + let ref _a = X; + //~^ ERROR reference of mutable static is disallowed + + let (_b, _c) = (&X, &Y); + //~^ ERROR reference of mutable static is disallowed + //~^^ ERROR reference of mutable static is disallowed + + foo(&X); + //~^ ERROR reference of mutable static is disallowed +} + +fn foo<'a>(_x: &'a i32) {} diff --git a/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr b/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr new file mode 100644 index 000000000000..5c6fdedfa96f --- /dev/null +++ b/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr @@ -0,0 +1,63 @@ +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:9:14 + | +LL | let _y = &X; + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _y = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:12:18 + | +LL | let ref _a = X; + | ^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let ref _a = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:15:21 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (addr_of!(X), &Y); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:15:25 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (&X, addr_of!(Y)); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static-unsafe-fn.rs:19:9 + | +LL | foo(&X); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | foo(addr_of!(X)); + | ~~~~~~~~~~~ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0796`. diff --git a/tests/ui/static/reference-of-mut-static.e2021.stderr b/tests/ui/static/reference-of-mut-static.e2021.stderr new file mode 100644 index 000000000000..77a6b3d304bd --- /dev/null +++ b/tests/ui/static/reference-of-mut-static.e2021.stderr @@ -0,0 +1,91 @@ +error: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static.rs:16:18 + | +LL | let _y = &X; + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +note: the lint level is defined here + --> $DIR/reference-of-mut-static.rs:6:9 + | +LL | #![deny(static_mut_ref)] + | ^^^^^^^^^^^^^^ +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _y = addr_of!(X); + | ~~~~~~~~~~~ + +error: mutable reference of mutable static is discouraged + --> $DIR/reference-of-mut-static.rs:20:18 + | +LL | let _y = &mut X; + | ^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let _y = addr_of_mut!(X); + | ~~~~~~~~~~~~~~~ + +error: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static.rs:28:22 + | +LL | let ref _a = X; + | ^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let ref _a = addr_of!(X); + | ~~~~~~~~~~~ + +error: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static.rs:32:25 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (addr_of!(X), &Y); + | ~~~~~~~~~~~ + +error: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static.rs:32:29 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (&X, addr_of!(Y)); + | ~~~~~~~~~~~ + +error: shared reference of mutable static is discouraged + --> $DIR/reference-of-mut-static.rs:38:13 + | +LL | foo(&X); + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | foo(addr_of!(X)); + | ~~~~~~~~~~~ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/static/reference-of-mut-static.e2024.stderr b/tests/ui/static/reference-of-mut-static.e2024.stderr new file mode 100644 index 000000000000..f445ec65a5d2 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static.e2024.stderr @@ -0,0 +1,75 @@ +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:16:18 + | +LL | let _y = &X; + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let _y = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:20:18 + | +LL | let _y = &mut X; + | ^^^^^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | let _y = addr_of_mut!(X); + | ~~~~~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:28:22 + | +LL | let ref _a = X; + | ^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let ref _a = addr_of!(X); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:32:25 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (addr_of!(X), &Y); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:32:29 + | +LL | let (_b, _c) = (&X, &Y); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let (_b, _c) = (&X, addr_of!(Y)); + | ~~~~~~~~~~~ + +error[E0796]: reference of mutable static is disallowed + --> $DIR/reference-of-mut-static.rs:38:13 + | +LL | foo(&X); + | ^^ reference of mutable static + | + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | foo(addr_of!(X)); + | ~~~~~~~~~~~ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0796`. diff --git a/tests/ui/static/reference-of-mut-static.rs b/tests/ui/static/reference-of-mut-static.rs new file mode 100644 index 000000000000..01a3b1fbd9b5 --- /dev/null +++ b/tests/ui/static/reference-of-mut-static.rs @@ -0,0 +1,50 @@ +// revisions: e2021 e2024 + +// [e2021] edition:2021 +// [e2024] compile-flags: --edition 2024 -Z unstable-options + +#![deny(static_mut_ref)] + +use std::ptr::{addr_of, addr_of_mut}; + +fn main() { + static mut X: i32 = 1; + + static mut Y: i32 = 1; + + unsafe { + let _y = &X; + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + + let _y = &mut X; + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR mutable reference of mutable static is discouraged [static_mut_ref] + + let _z = addr_of_mut!(X); + + let _p = addr_of!(X); + + let ref _a = X; + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + + let (_b, _c) = (&X, &Y); + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + //[e2024]~^^^ ERROR reference of mutable static is disallowed + //[e2021]~^^^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + + foo(&X); + //[e2024]~^ ERROR reference of mutable static is disallowed + //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref] + + static mut Z: &[i32; 3] = &[0, 1, 2]; + + let _ = Z.len(); + let _ = Z[0]; + let _ = format!("{:?}", Z); + } +} + +fn foo<'a>(_x: &'a i32) {} diff --git a/tests/ui/static/safe-extern-statics-mut.rs b/tests/ui/static/safe-extern-statics-mut.rs index 324fa443aa50..1c0662e0a6ce 100644 --- a/tests/ui/static/safe-extern-statics-mut.rs +++ b/tests/ui/static/safe-extern-statics-mut.rs @@ -10,6 +10,8 @@ extern "C" { fn main() { let b = B; //~ ERROR use of mutable static is unsafe let rb = &B; //~ ERROR use of mutable static is unsafe + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] let xb = XB; //~ ERROR use of mutable static is unsafe let xrb = &XB; //~ ERROR use of mutable static is unsafe + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] } diff --git a/tests/ui/static/safe-extern-statics-mut.stderr b/tests/ui/static/safe-extern-statics-mut.stderr index e390625f20a9..eda353ce6736 100644 --- a/tests/ui/static/safe-extern-statics-mut.stderr +++ b/tests/ui/static/safe-extern-statics-mut.stderr @@ -1,3 +1,32 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/safe-extern-statics-mut.rs:12:14 + | +LL | let rb = &B; + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let rb = addr_of!(B); + | ~~~~~~~~~~~ + +warning: shared reference of mutable static is discouraged + --> $DIR/safe-extern-statics-mut.rs:15:15 + | +LL | let xrb = &XB; + | ^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | let xrb = addr_of!(XB); + | ~~~~~~~~~~~~ + error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/safe-extern-statics-mut.rs:11:13 | @@ -15,7 +44,7 @@ LL | let rb = &B; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:13:14 + --> $DIR/safe-extern-statics-mut.rs:14:14 | LL | let xb = XB; | ^^ use of mutable static @@ -23,13 +52,13 @@ LL | let xb = XB; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:14:16 + --> $DIR/safe-extern-statics-mut.rs:15:16 | LL | let xrb = &XB; | ^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/statics/issue-15261.rs b/tests/ui/statics/issue-15261.rs index ec413f6d1d2b..14422329b7dc 100644 --- a/tests/ui/statics/issue-15261.rs +++ b/tests/ui/statics/issue-15261.rs @@ -6,6 +6,7 @@ static mut n_mut: usize = 0; -static n: &'static usize = unsafe{ &n_mut }; +static n: &'static usize = unsafe { &n_mut }; +//~^ WARN shared reference of mutable static is discouraged [static_mut_ref] fn main() {} diff --git a/tests/ui/statics/issue-15261.stderr b/tests/ui/statics/issue-15261.stderr new file mode 100644 index 000000000000..72d88ce1b383 --- /dev/null +++ b/tests/ui/statics/issue-15261.stderr @@ -0,0 +1,17 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/issue-15261.rs:9:37 + | +LL | static n: &'static usize = unsafe { &n_mut }; + | ^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | static n: &'static usize = unsafe { addr_of!(n_mut) }; + | ~~~~~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/statics/static-mut-xc.rs b/tests/ui/statics/static-mut-xc.rs index 1d172d26a594..2fc265e02eaa 100644 --- a/tests/ui/statics/static-mut-xc.rs +++ b/tests/ui/statics/static-mut-xc.rs @@ -7,7 +7,6 @@ // aux-build:static_mut_xc.rs - extern crate static_mut_xc; unsafe fn static_bound(_: &'static isize) {} @@ -27,7 +26,9 @@ unsafe fn run() { static_mut_xc::a = -3; assert_eq!(static_mut_xc::a, -3); static_bound(&static_mut_xc::a); + //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] static_bound_set(&mut static_mut_xc::a); + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] } pub fn main() { diff --git a/tests/ui/statics/static-mut-xc.stderr b/tests/ui/statics/static-mut-xc.stderr new file mode 100644 index 000000000000..37aa336bc50f --- /dev/null +++ b/tests/ui/statics/static-mut-xc.stderr @@ -0,0 +1,31 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/static-mut-xc.rs:28:18 + | +LL | static_bound(&static_mut_xc::a); + | ^^^^^^^^^^^^^^^^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | static_bound(addr_of!(static_mut_xc::a)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: mutable reference of mutable static is discouraged + --> $DIR/static-mut-xc.rs:30:22 + | +LL | static_bound_set(&mut static_mut_xc::a); + | ^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | static_bound_set(addr_of_mut!(static_mut_xc::a)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +warning: 2 warnings emitted + diff --git a/tests/ui/statics/static-recursive.rs b/tests/ui/statics/static-recursive.rs index 95dadc81f811..216beb0206d9 100644 --- a/tests/ui/statics/static-recursive.rs +++ b/tests/ui/statics/static-recursive.rs @@ -1,36 +1,43 @@ // run-pass + static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 }; +//~^ WARN shared reference of mutable static is discouraged [static_mut_ref] struct StaticDoubleLinked { prev: &'static StaticDoubleLinked, next: &'static StaticDoubleLinked, data: i32, - head: bool + head: bool, } -static L1: StaticDoubleLinked = StaticDoubleLinked{prev: &L3, next: &L2, data: 1, head: true}; -static L2: StaticDoubleLinked = StaticDoubleLinked{prev: &L1, next: &L3, data: 2, head: false}; -static L3: StaticDoubleLinked = StaticDoubleLinked{prev: &L2, next: &L1, data: 3, head: false}; - +static L1: StaticDoubleLinked = StaticDoubleLinked { prev: &L3, next: &L2, data: 1, head: true }; +static L2: StaticDoubleLinked = StaticDoubleLinked { prev: &L1, next: &L3, data: 2, head: false }; +static L3: StaticDoubleLinked = StaticDoubleLinked { prev: &L2, next: &L1, data: 3, head: false }; pub fn main() { - unsafe { assert_eq!(S, *(S as *const *const u8)); } + unsafe { + assert_eq!(S, *(S as *const *const u8)); + } let mut test_vec = Vec::new(); let mut cur = &L1; loop { test_vec.push(cur.data); cur = cur.next; - if cur.head { break } + if cur.head { + break; + } } - assert_eq!(&test_vec, &[1,2,3]); + assert_eq!(&test_vec, &[1, 2, 3]); let mut test_vec = Vec::new(); let mut cur = &L1; loop { cur = cur.prev; test_vec.push(cur.data); - if cur.head { break } + if cur.head { + break; + } } - assert_eq!(&test_vec, &[3,2,1]); + assert_eq!(&test_vec, &[3, 2, 1]); } diff --git a/tests/ui/statics/static-recursive.stderr b/tests/ui/statics/static-recursive.stderr new file mode 100644 index 000000000000..15888e5c68d8 --- /dev/null +++ b/tests/ui/statics/static-recursive.stderr @@ -0,0 +1,17 @@ +warning: shared reference of mutable static is discouraged + --> $DIR/static-recursive.rs:3:36 + | +LL | static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 }; + | ^^ shared reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + | +LL | static mut S: *const u8 = unsafe { addr_of!(S) as *const *const u8 as *const u8 }; + | ~~~~~~~~~~~ + +warning: 1 warning emitted + diff --git a/tests/ui/suggestions/bad-infer-in-trait-impl.rs b/tests/ui/suggestions/bad-infer-in-trait-impl.rs index 87db2636fb24..f38b168037b6 100644 --- a/tests/ui/suggestions/bad-infer-in-trait-impl.rs +++ b/tests/ui/suggestions/bad-infer-in-trait-impl.rs @@ -5,6 +5,7 @@ trait Foo { impl Foo for () { fn bar(s: _) {} //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions + //~| ERROR has 1 parameter but the declaration in trait `Foo::bar` has 0 } fn main() {} diff --git a/tests/ui/suggestions/bad-infer-in-trait-impl.stderr b/tests/ui/suggestions/bad-infer-in-trait-impl.stderr index d96ee33a9146..50c398de2b08 100644 --- a/tests/ui/suggestions/bad-infer-in-trait-impl.stderr +++ b/tests/ui/suggestions/bad-infer-in-trait-impl.stderr @@ -9,6 +9,16 @@ help: use type parameters instead LL | fn bar(s: T) {} | +++ ~ -error: aborting due to 1 previous error +error[E0050]: method `bar` has 1 parameter but the declaration in trait `Foo::bar` has 0 + --> $DIR/bad-infer-in-trait-impl.rs:6:15 + | +LL | fn bar(); + | --------- trait requires 0 parameters +... +LL | fn bar(s: _) {} + | ^ expected 0 parameters, found 1 -For more information about this error, try `rustc --explain E0121`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0050, E0121. +For more information about an error, try `rustc --explain E0050`. diff --git a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr index 7c81825e5764..60ab392f55de 100644 --- a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -52,7 +52,7 @@ LL | Pin::new(x) | = note: consider using the `pin!` macro consider using `Box::pin` if you need to access the pinned value outside of the current scope -note: required by a bound in `Pin::

::new` +note: required by a bound in `Pin::::new` --> $SRC_DIR/core/src/pin.rs:LL:COL error[E0277]: `dyn Future + Send` cannot be unpinned @@ -65,7 +65,7 @@ LL | Pin::new(Box::new(x)) | = note: consider using the `pin!` macro consider using `Box::pin` if you need to access the pinned value outside of the current scope -note: required by a bound in `Pin::

::new` +note: required by a bound in `Pin::::new` --> $SRC_DIR/core/src/pin.rs:LL:COL error[E0308]: mismatched types diff --git a/tests/ui/suggestions/fn-trait-notation.fixed b/tests/ui/suggestions/fn-trait-notation.fixed index cf940f4e9267..6cb97df4a859 100644 --- a/tests/ui/suggestions/fn-trait-notation.fixed +++ b/tests/ui/suggestions/fn-trait-notation.fixed @@ -2,6 +2,7 @@ fn e0658(f: F, g: G, h: H) -> i32 where F: Fn(i32) -> i32, //~ ERROR E0658 + //~^ ERROR E0059 G: Fn(i32, i32) -> (i32, i32), //~ ERROR E0658 H: Fn(i32) -> i32, //~ ERROR E0658 { diff --git a/tests/ui/suggestions/fn-trait-notation.rs b/tests/ui/suggestions/fn-trait-notation.rs index f0bb03315d98..912516149301 100644 --- a/tests/ui/suggestions/fn-trait-notation.rs +++ b/tests/ui/suggestions/fn-trait-notation.rs @@ -2,6 +2,7 @@ fn e0658(f: F, g: G, h: H) -> i32 where F: Fn, //~ ERROR E0658 + //~^ ERROR E0059 G: Fn<(i32, i32, ), Output = (i32, i32)>, //~ ERROR E0658 H: Fn<(i32,), Output = i32>, //~ ERROR E0658 { diff --git a/tests/ui/suggestions/fn-trait-notation.stderr b/tests/ui/suggestions/fn-trait-notation.stderr index 3e3b54174401..ed79b3d512cd 100644 --- a/tests/ui/suggestions/fn-trait-notation.stderr +++ b/tests/ui/suggestions/fn-trait-notation.stderr @@ -8,7 +8,7 @@ LL | F: Fn, = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change - --> $DIR/fn-trait-notation.rs:5:8 + --> $DIR/fn-trait-notation.rs:6:8 | LL | G: Fn<(i32, i32, ), Output = (i32, i32)>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(i32, i32) -> (i32, i32)` @@ -17,7 +17,7 @@ LL | G: Fn<(i32, i32, ), Output = (i32, i32)>, = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change - --> $DIR/fn-trait-notation.rs:6:8 + --> $DIR/fn-trait-notation.rs:7:8 | LL | H: Fn<(i32,), Output = i32>, | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(i32) -> i32` @@ -25,6 +25,16 @@ LL | H: Fn<(i32,), Output = i32>, = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable -error: aborting due to 3 previous errors +error[E0059]: type parameter to bare `Fn` trait must be a tuple + --> $DIR/fn-trait-notation.rs:4:8 + | +LL | F: Fn, + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `i32` + | +note: required by a bound in `Fn` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL -For more information about this error, try `rustc --explain E0658`. +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0059, E0658. +For more information about an error, try `rustc --explain E0059`. diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs index a1a51c4814e8..afde5ee97d78 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs @@ -18,6 +18,7 @@ mod elided { // But that lifetime does not participate in resolution. async fn i(mut x: impl Iterator) -> Option<&()> { x.next() } //~^ ERROR missing lifetime specifier + //~| ERROR lifetime may not live long enough } mod underscore { @@ -36,6 +37,7 @@ mod underscore { // But that lifetime does not participate in resolution. async fn i(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } //~^ ERROR missing lifetime specifier + //~| ERROR lifetime may not live long enough } mod alone_in_path { @@ -61,8 +63,8 @@ mod in_path { } // This must not err, as the `&` actually resolves to `'a`. -fn resolved_anonymous<'a, T>(f: impl Fn(&'a str) -> &T) { - f("f") +fn resolved_anonymous<'a, T: 'a>(f: impl Fn(&'a str) -> &T) { + f("f"); } fn main() {} diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr index 2dfaa7311948..fee4c7268fae 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr @@ -41,7 +41,7 @@ LL + async fn i(mut x: impl Iterator) -> Option<()> { x.next() } | error[E0106]: missing lifetime specifier - --> $DIR/impl-trait-missing-lifetime-gated.rs:27:58 + --> $DIR/impl-trait-missing-lifetime-gated.rs:28:58 | LL | fn g(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } | ^^ expected named lifetime parameter @@ -62,7 +62,7 @@ LL + fn g(mut x: impl Iterator) -> Option<()> { x.next() } | error[E0106]: missing lifetime specifier - --> $DIR/impl-trait-missing-lifetime-gated.rs:37:64 + --> $DIR/impl-trait-missing-lifetime-gated.rs:38:64 | LL | async fn i(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } | ^^ expected named lifetime parameter @@ -83,7 +83,7 @@ LL + async fn i(mut x: impl Iterator) -> Option<()> { x.next( | error[E0106]: missing lifetime specifier - --> $DIR/impl-trait-missing-lifetime-gated.rs:47:37 + --> $DIR/impl-trait-missing-lifetime-gated.rs:49:37 | LL | fn g(mut x: impl Foo) -> Option<&()> { x.next() } | ^ expected named lifetime parameter @@ -104,7 +104,7 @@ LL + fn g(mut x: impl Foo) -> Option<()> { x.next() } | error[E0106]: missing lifetime specifier - --> $DIR/impl-trait-missing-lifetime-gated.rs:58:41 + --> $DIR/impl-trait-missing-lifetime-gated.rs:60:41 | LL | fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() } | ^ expected named lifetime parameter @@ -149,7 +149,7 @@ LL | fn g<'a>(mut x: impl Iterator) -> Option<&()> { x.next() | ++++ ++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:24:35 + --> $DIR/impl-trait-missing-lifetime-gated.rs:25:35 | LL | fn f(_: impl Iterator) {} | ^^ expected named lifetime parameter @@ -161,7 +161,7 @@ LL | fn f<'a>(_: impl Iterator) {} | ++++ ~~ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:27:39 + --> $DIR/impl-trait-missing-lifetime-gated.rs:28:39 | LL | fn g(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } | ^^ expected named lifetime parameter @@ -173,7 +173,7 @@ LL | fn g<'a>(mut x: impl Iterator) -> Option<&'_ ()> { x.nex | ++++ ~~ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:44:18 + --> $DIR/impl-trait-missing-lifetime-gated.rs:46:18 | LL | fn f(_: impl Foo) {} | ^^^ expected named lifetime parameter @@ -185,7 +185,7 @@ LL | fn f<'a>(_: impl Foo<'a>) {} | ++++ ++++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:47:22 + --> $DIR/impl-trait-missing-lifetime-gated.rs:49:22 | LL | fn g(mut x: impl Foo) -> Option<&()> { x.next() } | ^^^ expected named lifetime parameter @@ -197,7 +197,7 @@ LL | fn g<'a>(mut x: impl Foo<'a>) -> Option<&()> { x.next() } | ++++ ++++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:55:22 + --> $DIR/impl-trait-missing-lifetime-gated.rs:57:22 | LL | fn f(_: impl Foo<()>) {} | ^ expected named lifetime parameter @@ -209,7 +209,7 @@ LL | fn f<'a>(_: impl Foo<'a, ()>) {} | ++++ +++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:58:26 + --> $DIR/impl-trait-missing-lifetime-gated.rs:60:26 | LL | fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() } | ^ expected named lifetime parameter @@ -220,7 +220,23 @@ help: consider introducing a named lifetime parameter LL | fn g<'a>(mut x: impl Foo<'a, ()>) -> Option<&()> { x.next() } | ++++ +++ -error: aborting due to 14 previous errors +error: lifetime may not live long enough + --> $DIR/impl-trait-missing-lifetime-gated.rs:19:67 + | +LL | async fn i(mut x: impl Iterator) -> Option<&()> { x.next() } + | ----------------------------------------------------------- ^^^^^^^^ returning this value requires that `'1` must outlive `'static` + | | + | return type `impl Future>` contains a lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/impl-trait-missing-lifetime-gated.rs:38:73 + | +LL | async fn i(mut x: impl Iterator) -> Option<&'_ ()> { x.next() } + | ----------------------------------------------------------------- ^^^^^^^^ returning this value requires that `'1` must outlive `'static` + | | + | return type `impl Future>` contains a lifetime `'1` + +error: aborting due to 16 previous errors Some errors have detailed explanations: E0106, E0658. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/suggestions/missing-lifetime-specifier.rs b/tests/ui/suggestions/missing-lifetime-specifier.rs index cb734e8ba857..01dcc94f7476 100644 --- a/tests/ui/suggestions/missing-lifetime-specifier.rs +++ b/tests/ui/suggestions/missing-lifetime-specifier.rs @@ -1,6 +1,9 @@ +// different number of duplicated diagnostics on different targets +// compile-flags: -Zdeduplicate-diagnostics=yes + #![allow(bare_trait_objects)] -use std::collections::HashMap; use std::cell::RefCell; +use std::collections::HashMap; pub union Foo<'t, 'k> { i: &'t i64, @@ -38,18 +41,10 @@ thread_local! { thread_local! { static e: RefCell>>>> = RefCell::new(HashMap::new()); //~^ ERROR union takes 2 lifetime arguments but 1 lifetime argument - //~| ERROR union takes 2 lifetime arguments but 1 lifetime argument was supplied - //~| ERROR union takes 2 lifetime arguments but 1 lifetime argument was supplied - //~| ERROR union takes 2 lifetime arguments but 1 lifetime argument was supplied - //~| ERROR union takes 2 lifetime arguments but 1 lifetime argument was supplied } thread_local! { static f: RefCell>>>> = RefCell::new(HashMap::new()); //~^ ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied - //~| ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied - //~| ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied - //~| ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied - //~| ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied //~| ERROR missing lifetime //~| ERROR missing lifetime } diff --git a/tests/ui/suggestions/missing-lifetime-specifier.stderr b/tests/ui/suggestions/missing-lifetime-specifier.stderr index e41f547ce9b2..7a7ef47c35b7 100644 --- a/tests/ui/suggestions/missing-lifetime-specifier.stderr +++ b/tests/ui/suggestions/missing-lifetime-specifier.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:18:44 + --> $DIR/missing-lifetime-specifier.rs:21:44 | LL | static a: RefCell>>> = RefCell::new(HashMap::new()); | ^^^ expected 2 lifetime parameters @@ -11,7 +11,7 @@ LL | static a: RefCell>>>> = RefC | ++++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:18:44 + --> $DIR/missing-lifetime-specifier.rs:21:44 | LL | / thread_local! { LL | | static a: RefCell>>> = RefCell::new(HashMap::new()); @@ -24,7 +24,7 @@ LL | | } = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:23:44 + --> $DIR/missing-lifetime-specifier.rs:26:44 | LL | static b: RefCell>>> = RefCell::new(HashMap::new()); | ^^^^ expected 2 lifetime parameters @@ -38,7 +38,7 @@ LL | static b: RefCell>> | +++++++ ++++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:23:44 + --> $DIR/missing-lifetime-specifier.rs:26:44 | LL | / thread_local! { LL | | static b: RefCell>>> = RefCell::new(HashMap::new()); @@ -53,7 +53,7 @@ LL | | } = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:28:47 + --> $DIR/missing-lifetime-specifier.rs:31:47 | LL | static c: RefCell>>>> = RefCell::new(HashMap::new()); | ^ expected 2 lifetime parameters @@ -65,7 +65,7 @@ LL | static c: RefCell>>>> = | +++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:28:47 + --> $DIR/missing-lifetime-specifier.rs:31:47 | LL | / thread_local! { LL | | static c: RefCell>>>> = RefCell::new(HashMap::new()); @@ -78,7 +78,7 @@ LL | | } = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:33:44 + --> $DIR/missing-lifetime-specifier.rs:36:44 | LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); | ^ ^ expected 2 lifetime parameters @@ -92,7 +92,7 @@ LL | static d: RefCell $DIR/missing-lifetime-specifier.rs:33:44 + --> $DIR/missing-lifetime-specifier.rs:36:44 | LL | / thread_local! { LL | | static d: RefCell>>>> = RefCell::new(HashMap::new()); @@ -107,7 +107,7 @@ LL | | } = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:47:44 + --> $DIR/missing-lifetime-specifier.rs:46:44 | LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^ expected named lifetime parameter @@ -119,14 +119,13 @@ LL | static f: RefCell>>>> = | +++++++ error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:47:44 + --> $DIR/missing-lifetime-specifier.rs:46:44 | LL | / thread_local! { LL | | static f: RefCell>>>> = RefCell::new(HashMap::new()); | | ^ expected named lifetime parameter LL | | LL | | -... | LL | | LL | | } | |_- @@ -134,7 +133,7 @@ LL | | } = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:39:44 + --> $DIR/missing-lifetime-specifier.rs:42:44 | LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -142,7 +141,7 @@ LL | static e: RefCell>>>> = RefCell: | expected 2 lifetime arguments | note: union defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:11:11 + --> $DIR/missing-lifetime-specifier.rs:14:11 | LL | pub union Qux<'t, 'k, I> { | ^^^ -- -- @@ -151,84 +150,8 @@ help: add missing lifetime argument LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | +++++++++ -error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:39:44 - | -LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); - | ^^^ ------- supplied 1 lifetime argument - | | - | expected 2 lifetime arguments - | -note: union defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:11:11 - | -LL | pub union Qux<'t, 'k, I> { - | ^^^ -- -- - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: add missing lifetime argument - | -LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++++ - -error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:39:44 - | -LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); - | ^^^ ------- supplied 1 lifetime argument - | | - | expected 2 lifetime arguments - | -note: union defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:11:11 - | -LL | pub union Qux<'t, 'k, I> { - | ^^^ -- -- - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: add missing lifetime argument - | -LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++++ - -error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:39:44 - | -LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); - | ^^^ ------- supplied 1 lifetime argument - | | - | expected 2 lifetime arguments - | -note: union defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:11:11 - | -LL | pub union Qux<'t, 'k, I> { - | ^^^ -- -- - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: add missing lifetime argument - | -LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++++ - -error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:39:44 - | -LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); - | ^^^ ------- supplied 1 lifetime argument - | | - | expected 2 lifetime arguments - | -note: union defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:11:11 - | -LL | pub union Qux<'t, 'k, I> { - | ^^^ -- -- - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: add missing lifetime argument - | -LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++++ - error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:47:45 + --> $DIR/missing-lifetime-specifier.rs:46:45 | LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -236,7 +159,7 @@ LL | static f: RefCell>>>> = RefCell | expected 2 lifetime arguments | note: trait defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:15:7 + --> $DIR/missing-lifetime-specifier.rs:18:7 | LL | trait Tar<'t, 'k, I> {} | ^^^ -- -- @@ -245,83 +168,7 @@ help: add missing lifetime argument LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); | +++++++++ -error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:47:45 - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | ^^^ ------- supplied 1 lifetime argument - | | - | expected 2 lifetime arguments - | -note: trait defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:15:7 - | -LL | trait Tar<'t, 'k, I> {} - | ^^^ -- -- - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: add missing lifetime argument - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++++ - -error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:47:45 - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | ^^^ ------- supplied 1 lifetime argument - | | - | expected 2 lifetime arguments - | -note: trait defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:15:7 - | -LL | trait Tar<'t, 'k, I> {} - | ^^^ -- -- - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: add missing lifetime argument - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++++ - -error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:47:45 - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | ^^^ ------- supplied 1 lifetime argument - | | - | expected 2 lifetime arguments - | -note: trait defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:15:7 - | -LL | trait Tar<'t, 'k, I> {} - | ^^^ -- -- - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: add missing lifetime argument - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++++ - -error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:47:45 - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | ^^^ ------- supplied 1 lifetime argument - | | - | expected 2 lifetime arguments - | -note: trait defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:15:7 - | -LL | trait Tar<'t, 'k, I> {} - | ^^^ -- -- - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: add missing lifetime argument - | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++++ - -error: aborting due to 20 previous errors +error: aborting due to 12 previous errors Some errors have detailed explanations: E0106, E0107. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/tag-type-args.rs b/tests/ui/tag-type-args.rs index 660d860ba772..75a54927443f 100644 --- a/tests/ui/tag-type-args.rs +++ b/tests/ui/tag-type-args.rs @@ -1,4 +1,5 @@ enum Quux { Bar } +//~^ ERROR: parameter `T` is never used fn foo(c: Quux) { assert!((false)); } //~ ERROR missing generics for enum `Quux` diff --git a/tests/ui/tag-type-args.stderr b/tests/ui/tag-type-args.stderr index 49ecf65b7e62..80ffd3a2f050 100644 --- a/tests/ui/tag-type-args.stderr +++ b/tests/ui/tag-type-args.stderr @@ -1,5 +1,5 @@ error[E0107]: missing generics for enum `Quux` - --> $DIR/tag-type-args.rs:3:11 + --> $DIR/tag-type-args.rs:4:11 | LL | fn foo(c: Quux) { assert!((false)); } | ^^^^ expected 1 generic argument @@ -14,6 +14,16 @@ help: add missing generic argument LL | fn foo(c: Quux) { assert!((false)); } | +++ -error: aborting due to 1 previous error +error[E0392]: parameter `T` is never used + --> $DIR/tag-type-args.rs:1:11 + | +LL | enum Quux { Bar } + | ^ unused parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: usize` instead -For more information about this error, try `rustc --explain E0107`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0392. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs index d1b3cf71c15e..f6357bd9eb08 100644 --- a/tests/ui/target-feature/invalid-attribute.rs +++ b/tests/ui/target-feature/invalid-attribute.rs @@ -86,6 +86,8 @@ static A: () = (); //~^ ERROR attribute should be applied to a function impl Quux for u8 {} //~^ NOTE not a function +//~| NOTE missing `foo` in implementation +//~| ERROR missing: `foo` #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function @@ -93,7 +95,7 @@ impl Foo {} //~^ NOTE not a function trait Quux { - fn foo(); + fn foo(); //~ NOTE `foo` from trait } impl Quux for Foo { diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index 29c73921c538..8f981d27c53f 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -117,7 +117,7 @@ LL | impl Quux for u8 {} | ------------------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:90:1 + --> $DIR/invalid-attribute.rs:92:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -126,7 +126,7 @@ LL | impl Foo {} | ----------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:108:5 + --> $DIR/invalid-attribute.rs:110:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,7 +138,7 @@ LL | | } | |_____- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:116:5 + --> $DIR/invalid-attribute.rs:118:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -183,7 +183,7 @@ LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/invalid-attribute.rs:100:5 + --> $DIR/invalid-attribute.rs:102:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -194,6 +194,16 @@ LL | fn foo() {} = note: see issue #69098 for more information = help: add `#![feature(target_feature_11)]` to the crate attributes to enable -error: aborting due to 22 previous errors +error[E0046]: not all trait items implemented, missing: `foo` + --> $DIR/invalid-attribute.rs:87:1 + | +LL | impl Quux for u8 {} + | ^^^^^^^^^^^^^^^^ missing `foo` in implementation +... +LL | fn foo(); + | --------- `foo` from trait -For more information about this error, try `rustc --explain E0658`. +error: aborting due to 23 previous errors + +Some errors have detailed explanations: E0046, E0658. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/thread-local/thread-local-static.rs b/tests/ui/thread-local/thread-local-static.rs index e6cd4839dda7..f5fb09848974 100644 --- a/tests/ui/thread-local/thread-local-static.rs +++ b/tests/ui/thread-local/thread-local-static.rs @@ -8,7 +8,8 @@ static mut STATIC_VAR_2: [u32; 8] = [4; 8]; const fn g(x: &mut [u32; 8]) { //~^ ERROR mutable references are not allowed std::mem::swap(x, &mut STATIC_VAR_2) - //~^ ERROR thread-local statics cannot be accessed + //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] + //~^^ ERROR thread-local statics cannot be accessed //~| ERROR mutable references are not allowed //~| ERROR use of mutable static is unsafe //~| constant functions cannot refer to statics diff --git a/tests/ui/thread-local/thread-local-static.stderr b/tests/ui/thread-local/thread-local-static.stderr index c1777dd60db6..b03f4580c2cf 100644 --- a/tests/ui/thread-local/thread-local-static.stderr +++ b/tests/ui/thread-local/thread-local-static.stderr @@ -1,3 +1,18 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/thread-local-static.rs:10:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | std::mem::swap(x, addr_of_mut!(STATIC_VAR_2)) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/thread-local-static.rs:10:28 | @@ -38,7 +53,7 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2) = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 1 warning emitted Some errors have detailed explanations: E0013, E0133, E0625, E0658. For more information about an error, try `rustc --explain E0013`. diff --git a/tests/ui/thread-local/thread-local-static.thir.stderr b/tests/ui/thread-local/thread-local-static.thir.stderr new file mode 100644 index 000000000000..2043b268c090 --- /dev/null +++ b/tests/ui/thread-local/thread-local-static.thir.stderr @@ -0,0 +1,59 @@ +warning: mutable reference of mutable static is discouraged + --> $DIR/thread-local-static.rs:12:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static + | + = note: for more information, see issue #114447 + = note: reference of mutable static is a hard error from 2024 edition + = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + = note: `#[warn(static_mut_ref)]` on by default +help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + | +LL | std::mem::swap(x, addr_of_mut!(STATIC_VAR_2)) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/thread-local-static.rs:10:12 + | +LL | const fn g(x: &mut [u32; 8]) { + | ^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0625]: thread-local statics cannot be accessed at compile-time + --> $DIR/thread-local-static.rs:12:28 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^ + +error[E0013]: constant functions cannot refer to statics + --> $DIR/thread-local-static.rs:12:28 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/thread-local-static.rs:12:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/thread-local-static.rs:12:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: aborting due to 5 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0013, E0133, E0625, E0658. +For more information about an error, try `rustc --explain E0013`. diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs index e0edd522431a..4cbc36f4650b 100644 --- a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs +++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs @@ -7,12 +7,14 @@ pub trait Trait { } impl Trait for i32 { + //~^ ERROR `S` is not constrained type Assoc = String; } // Should not not trigger suggestion here... impl Trait for () {} //~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied +//~| ERROR `S` is not constrained //... but should do so in all of the below cases except the last one fn func>(t: T) -> impl Trait<(), i32> { @@ -37,6 +39,7 @@ impl> Struct {} trait YetAnotherTrait {} impl, U> YetAnotherTrait for Struct {} //~^ ERROR struct takes 1 generic argument but 2 generic arguments were supplied +//~| ERROR `U` is not constrained fn main() { diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr index 711ccf1b6682..3c2b726fccea 100644 --- a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr +++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr @@ -1,5 +1,5 @@ error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:14:12 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:15:12 | LL | impl Trait for () {} | ^^^^^ expected 1 generic argument @@ -11,7 +11,7 @@ LL | pub trait Trait { | ^^^^^ - error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:12 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:20:12 | LL | fn func>(t: T) -> impl Trait<(), i32> { | ^^^^^ expected 1 generic argument @@ -27,7 +27,7 @@ LL | fn func>(t: T) -> impl Trait<(), i32> { | +++++++ error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:46 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:20:46 | LL | fn func>(t: T) -> impl Trait<(), i32> { | ^^^^^ expected 1 generic argument @@ -43,7 +43,7 @@ LL | fn func>(t: T) -> impl Trait<(), Assoc = i32> { | +++++++ error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:18 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:26:18 | LL | struct Struct> { | ^^^^^ expected 1 generic argument @@ -59,7 +59,7 @@ LL | struct Struct> { | +++++++ error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:29:23 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:31:23 | LL | trait AnotherTrait> {} | ^^^^^ expected 1 generic argument @@ -75,7 +75,7 @@ LL | trait AnotherTrait> {} | +++++++ error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:32:9 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:34:9 | LL | impl> Struct {} | ^^^^^ expected 1 generic argument @@ -91,7 +91,7 @@ LL | impl> Struct {} | +++++++ error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:38:58 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:40:58 | LL | impl, U> YetAnotherTrait for Struct {} | ^^^^^^ - help: remove this generic argument @@ -99,11 +99,30 @@ LL | impl, U> YetAnotherTrait for Struct {} | expected 1 generic argument | note: struct defined here, with 1 generic parameter: `T` - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:8 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:26:8 | LL | struct Struct> { | ^^^^^^ - -error: aborting due to 7 previous errors +error[E0207]: the type parameter `S` is not constrained by the impl trait, self type, or predicates + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:9:9 + | +LL | impl Trait for i32 { + | ^ unconstrained type parameter -For more information about this error, try `rustc --explain E0107`. +error[E0207]: the type parameter `S` is not constrained by the impl trait, self type, or predicates + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:15:9 + | +LL | impl Trait for () {} + | ^ unconstrained type parameter + +error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:40:35 + | +LL | impl, U> YetAnotherTrait for Struct {} + | ^ unconstrained type parameter + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0107, E0207. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/bound/not-on-bare-trait-2021.rs b/tests/ui/traits/bound/not-on-bare-trait-2021.rs index 3d97bddb4a49..4c2e6f0852b6 100644 --- a/tests/ui/traits/bound/not-on-bare-trait-2021.rs +++ b/tests/ui/traits/bound/not-on-bare-trait-2021.rs @@ -7,10 +7,12 @@ trait Foo { fn foo(_x: Foo + Send) { //~^ ERROR trait objects must include the `dyn` keyword + //~| ERROR size for values of type } fn bar(x: Foo) -> Foo { //~^ ERROR trait objects must include the `dyn` keyword //~| ERROR trait objects must include the `dyn` keyword + //~| ERROR size for values of type x } diff --git a/tests/ui/traits/bound/not-on-bare-trait-2021.stderr b/tests/ui/traits/bound/not-on-bare-trait-2021.stderr index 6f41f872e4cf..57d3bc8f1094 100644 --- a/tests/ui/traits/bound/not-on-bare-trait-2021.stderr +++ b/tests/ui/traits/bound/not-on-bare-trait-2021.stderr @@ -1,3 +1,37 @@ +error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time + --> $DIR/not-on-bare-trait-2021.rs:8:8 + | +LL | fn foo(_x: Foo + Send) { + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)` + = help: unsized fn params are gated as an unstable feature +help: you can use `impl Trait` as the argument type + | +LL | fn foo(_x: impl Foo + Send) { + | ++++ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo(_x: &(dyn Foo + Send)) { + | +++++ + + +error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time + --> $DIR/not-on-bare-trait-2021.rs:12:8 + | +LL | fn bar(x: Foo) -> Foo { + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)` + = help: unsized fn params are gated as an unstable feature +help: you can use `impl Trait` as the argument type + | +LL | fn bar(x: impl Foo) -> Foo { + | ++++ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn bar(x: &dyn Foo) -> Foo { + | ++++ + error[E0782]: trait objects must include the `dyn` keyword --> $DIR/not-on-bare-trait-2021.rs:8:12 | @@ -18,7 +52,7 @@ LL | fn foo(_x: &(dyn Foo + Send)) { | +++++ + error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/not-on-bare-trait-2021.rs:11:11 + --> $DIR/not-on-bare-trait-2021.rs:12:11 | LL | fn bar(x: Foo) -> Foo { | ^^^ @@ -37,7 +71,7 @@ LL | fn bar(x: &dyn Foo) -> Foo { | ++++ error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/not-on-bare-trait-2021.rs:11:19 + --> $DIR/not-on-bare-trait-2021.rs:12:19 | LL | fn bar(x: Foo) -> Foo { | ^^^ @@ -51,6 +85,7 @@ help: alternatively, you can return an owned trait object LL | fn bar(x: Foo) -> Box { | +++++++ + -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0782`. +Some errors have detailed explanations: E0277, E0782. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/issue-106072.rs b/tests/ui/traits/issue-106072.rs index b174669545a2..d38d3c3b2865 100644 --- a/tests/ui/traits/issue-106072.rs +++ b/tests/ui/traits/issue-106072.rs @@ -1,4 +1,5 @@ #[derive(Clone)] //~ trait objects must include the `dyn` keyword +//~^ ERROR: the size for values of type `(dyn Foo + 'static)` cannot be known struct Foo; trait Foo {} //~ the name `Foo` is defined multiple times fn main() {} diff --git a/tests/ui/traits/issue-106072.stderr b/tests/ui/traits/issue-106072.stderr index 1037603ceb77..aadadc45f21c 100644 --- a/tests/ui/traits/issue-106072.stderr +++ b/tests/ui/traits/issue-106072.stderr @@ -1,5 +1,5 @@ error[E0428]: the name `Foo` is defined multiple times - --> $DIR/issue-106072.rs:3:1 + --> $DIR/issue-106072.rs:4:1 | LL | struct Foo; | ----------- previous definition of the type `Foo` here @@ -8,6 +8,17 @@ LL | trait Foo {} | = note: `Foo` must be defined only once in the type namespace of this module +error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time + --> $DIR/issue-106072.rs:1:10 + | +LL | #[derive(Clone)] + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)` +note: required by a bound in `Clone` + --> $SRC_DIR/core/src/clone.rs:LL:COL + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0782]: trait objects must include the `dyn` keyword --> $DIR/issue-106072.rs:1:10 | @@ -16,7 +27,7 @@ LL | #[derive(Clone)] | = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0428, E0782. -For more information about an error, try `rustc --explain E0428`. +Some errors have detailed explanations: E0277, E0428, E0782. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/issue-28576.rs b/tests/ui/traits/issue-28576.rs index 972c839b6480..e19bd2635813 100644 --- a/tests/ui/traits/issue-28576.rs +++ b/tests/ui/traits/issue-28576.rs @@ -3,6 +3,8 @@ pub trait Foo { } pub trait Bar: Foo { + //~^ ERROR: the size for values of type `Self` cannot be known + //~| ERROR: the size for values of type `Self` cannot be known fn new(&self, b: & dyn Bar //~ ERROR the trait `Bar` cannot be made into an object diff --git a/tests/ui/traits/issue-28576.stderr b/tests/ui/traits/issue-28576.stderr index 3b45a510341f..96e8aaee23d5 100644 --- a/tests/ui/traits/issue-28576.stderr +++ b/tests/ui/traits/issue-28576.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/issue-28576.rs:7:12 + --> $DIR/issue-28576.rs:9:12 | LL | / dyn Bar LL | | @@ -19,6 +19,47 @@ help: consider using an opaque type instead LL | impl Bar | ~~~~ -error: aborting due to 1 previous error +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/issue-28576.rs:5:16 + | +LL | pub trait Bar: Foo { + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time + | +note: required by a bound in `Foo` + --> $DIR/issue-28576.rs:1:15 + | +LL | pub trait Foo { + | ^^^^^^^^ required by this bound in `Foo` +help: consider further restricting `Self` + | +LL | pub trait Bar: Foo + Sized { + | +++++++ +help: consider relaxing the implicit `Sized` restriction + | +LL | pub trait Foo { + | ++++++++ -For more information about this error, try `rustc --explain E0038`. +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/issue-28576.rs:5:16 + | +LL | pub trait Bar: Foo { + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time + | +note: required by a bound in `Foo` + --> $DIR/issue-28576.rs:1:15 + | +LL | pub trait Foo { + | ^^^^^^^^ required by this bound in `Foo` +help: consider further restricting `Self` + | +LL | ) where Self: Sized; + | +++++++++++++++++ +help: consider relaxing the implicit `Sized` restriction + | +LL | pub trait Foo { + | ++++++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0038, E0277. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/issue-38404.rs b/tests/ui/traits/issue-38404.rs index 05921b2c36e4..9b60116f733d 100644 --- a/tests/ui/traits/issue-38404.rs +++ b/tests/ui/traits/issue-38404.rs @@ -1,7 +1,8 @@ trait A: std::ops::Add + Sized {} trait B: A {} -trait C: A> {} +trait C: A> {} //~^ ERROR the trait `B` cannot be made into an object //~| ERROR the trait `B` cannot be made into an object +//~| ERROR the trait `B` cannot be made into an object fn main() {} diff --git a/tests/ui/traits/issue-38404.stderr b/tests/ui/traits/issue-38404.stderr index a5c258eb36e9..19d4035b54c8 100644 --- a/tests/ui/traits/issue-38404.stderr +++ b/tests/ui/traits/issue-38404.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `B` cannot be made into an object --> $DIR/issue-38404.rs:3:15 | -LL | trait C: A> {} - | ^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object +LL | trait C: A> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-38404.rs:1:13 @@ -15,8 +15,8 @@ LL | trait B: A {} error[E0038]: the trait `B` cannot be made into an object --> $DIR/issue-38404.rs:3:15 | -LL | trait C: A> {} - | ^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object +LL | trait C: A> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-38404.rs:1:13 @@ -27,6 +27,21 @@ LL | trait B: A {} | - this trait cannot be made into an object... = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 2 previous errors +error[E0038]: the trait `B` cannot be made into an object + --> $DIR/issue-38404.rs:3:15 + | +LL | trait C: A> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/issue-38404.rs:1:13 + | +LL | trait A: std::ops::Add + Sized {} + | ^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter +LL | trait B: A {} + | - this trait cannot be made into an object... + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/issue-87558.rs b/tests/ui/traits/issue-87558.rs index c5d86bd637b2..76f0f7453ddd 100644 --- a/tests/ui/traits/issue-87558.rs +++ b/tests/ui/traits/issue-87558.rs @@ -3,6 +3,8 @@ struct Error(ErrorKind); impl Fn(&isize) for Error { //~^ ERROR manual implementations of `Fn` are experimental //~| ERROR associated type bindings are not allowed here + //~| ERROR closure, found `Error` + //~| ERROR not all trait items implemented, missing: `call` fn from() {} //~ ERROR method `from` is not a member of trait `Fn` } diff --git a/tests/ui/traits/issue-87558.stderr b/tests/ui/traits/issue-87558.stderr index b647f9794bd9..1ce273a9f25e 100644 --- a/tests/ui/traits/issue-87558.stderr +++ b/tests/ui/traits/issue-87558.stderr @@ -1,5 +1,5 @@ error[E0407]: method `from` is not a member of trait `Fn` - --> $DIR/issue-87558.rs:6:5 + --> $DIR/issue-87558.rs:8:5 | LL | fn from() {} | ^^^^^^^^^^^^ not a member of trait `Fn` @@ -24,7 +24,25 @@ help: parenthesized trait syntax expands to `Fn<(&isize,), Output=()>` LL | impl Fn(&isize) for Error { | ^^^^^^^^^^ -error: aborting due to 3 previous errors +error[E0277]: expected a `FnMut(&isize)` closure, found `Error` + --> $DIR/issue-87558.rs:3:21 + | +LL | impl Fn(&isize) for Error { + | ^^^^^ expected an `FnMut(&isize)` closure, found `Error` + | + = help: the trait `FnMut<(&isize,)>` is not implemented for `Error` +note: required by a bound in `Fn` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL -Some errors have detailed explanations: E0183, E0229, E0407. -For more information about an error, try `rustc --explain E0183`. +error[E0046]: not all trait items implemented, missing: `call` + --> $DIR/issue-87558.rs:3:1 + | +LL | impl Fn(&isize) for Error { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing `call` in implementation + | + = help: implement the missing item: `fn call(&self, _: (&isize,)) -> >::Output { todo!() }` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0046, E0183, E0229, E0277, E0407. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs index 64f09f823fc2..94733f88c2da 100644 --- a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs +++ b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs @@ -6,6 +6,6 @@ fn foo() -> usize where for [i32; { let _: T = todo!(); 0 }]:, //~^ ERROR cannot capture late-bound type parameter in constant -{} +{ 42 } fn main() {} diff --git a/tests/ui/traits/object/object-unsafe-missing-assoc-type.rs b/tests/ui/traits/object/object-unsafe-missing-assoc-type.rs index 21f7fd92e80d..c83be544c0a1 100644 --- a/tests/ui/traits/object/object-unsafe-missing-assoc-type.rs +++ b/tests/ui/traits/object/object-unsafe-missing-assoc-type.rs @@ -3,5 +3,8 @@ trait Foo { } fn bar(x: &dyn Foo) {} //~ ERROR the trait `Foo` cannot be made into an object +//~^ ERROR the trait `Foo` cannot be made into an object +//~| ERROR the trait `Foo` cannot be made into an object +//~| ERROR the trait `Foo` cannot be made into an object fn main() {} diff --git a/tests/ui/traits/object/object-unsafe-missing-assoc-type.stderr b/tests/ui/traits/object/object-unsafe-missing-assoc-type.stderr index 196e74d39600..4c636c5e922e 100644 --- a/tests/ui/traits/object/object-unsafe-missing-assoc-type.stderr +++ b/tests/ui/traits/object/object-unsafe-missing-assoc-type.stderr @@ -13,6 +13,53 @@ LL | type Bar; | ^^^ ...because it contains the generic associated type `Bar` = help: consider moving `Bar` to another trait -error: aborting due to 1 previous error +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-unsafe-missing-assoc-type.rs:5:16 + | +LL | fn bar(x: &dyn Foo) {} + | ^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-unsafe-missing-assoc-type.rs:2:10 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | type Bar; + | ^^^ ...because it contains the generic associated type `Bar` + = help: consider moving `Bar` to another trait + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-unsafe-missing-assoc-type.rs:5:16 + | +LL | fn bar(x: &dyn Foo) {} + | ^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-unsafe-missing-assoc-type.rs:2:10 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | type Bar; + | ^^^ ...because it contains the generic associated type `Bar` + = help: consider moving `Bar` to another trait + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-unsafe-missing-assoc-type.rs:5:12 + | +LL | fn bar(x: &dyn Foo) {} + | ^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-unsafe-missing-assoc-type.rs:2:10 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | type Bar; + | ^^^ ...because it contains the generic associated type `Bar` + = help: consider moving `Bar` to another trait + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/transmutability/issue-101739-2.rs b/tests/ui/transmutability/issue-101739-2.rs index e5a56ccc9e03..4cde9152032c 100644 --- a/tests/ui/transmutability/issue-101739-2.rs +++ b/tests/ui/transmutability/issue-101739-2.rs @@ -16,6 +16,7 @@ mod assert { >() where Dst: BikeshedIntrinsicFrom< //~ ERROR trait takes at most 3 generic arguments but 6 generic arguments were supplied + //~^ ERROR: the constant `ASSUME_ALIGNMENT` is not of type `Assume` Src, Context, ASSUME_ALIGNMENT, diff --git a/tests/ui/transmutability/issue-101739-2.stderr b/tests/ui/transmutability/issue-101739-2.stderr index d5ed205d14b4..aed47f33f0d9 100644 --- a/tests/ui/transmutability/issue-101739-2.stderr +++ b/tests/ui/transmutability/issue-101739-2.stderr @@ -9,6 +9,22 @@ LL | | ASSUME_VALIDITY, LL | | ASSUME_VISIBILITY, | |_____________________________- help: remove these generic arguments -error: aborting due to 1 previous error +error: the constant `ASSUME_ALIGNMENT` is not of type `Assume` + --> $DIR/issue-101739-2.rs:18:14 + | +LL | Dst: BikeshedIntrinsicFrom< + | ______________^ +LL | | +LL | | Src, +LL | | Context, +... | +LL | | ASSUME_VISIBILITY, +LL | | >, + | |_________^ expected `Assume`, found `bool` + | +note: required by a bound in `BikeshedIntrinsicFrom` + --> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs new file mode 100644 index 000000000000..0be5b41c80bc --- /dev/null +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs @@ -0,0 +1,26 @@ +//~ ERROR: cycle detected +//! Safe transmute did not handle cycle errors that could occur during +//! layout computation. This test checks that we do not ICE in such +//! situations (see #117491). +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom, + { + } +} + +fn should_pad_explicitly_packed_field() { + #[repr(C)] + struct ExplicitlyPadded(ExplicitlyPadded); + //~^ ERROR: recursive type + + assert::is_maybe_transmutable::(); +} diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr new file mode 100644 index 000000000000..0dedd5aaf735 --- /dev/null +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr @@ -0,0 +1,21 @@ +error[E0072]: recursive type `ExplicitlyPadded` has infinite size + --> $DIR/transmute_infinitely_recursive_type.rs:22:5 + | +LL | struct ExplicitlyPadded(ExplicitlyPadded); + | ^^^^^^^^^^^^^^^^^^^^^^^ ---------------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL | struct ExplicitlyPadded(Box); + | ++++ + + +error[E0391]: cycle detected when computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` + | + = note: ...which immediately requires computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` again + = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::BikeshedIntrinsicFrom` + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0072, E0391. +For more information about an error, try `rustc --explain E0072`. diff --git a/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.rs b/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.rs index 6a2ee761e191..e7b23d5f8a1c 100644 --- a/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.rs +++ b/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.rs @@ -20,7 +20,7 @@ impl Recur for () { fn recur(self) -> Self::Recur { async move { recur(self).await; } - //~^ ERROR cycle detected when computing layout of + //~^ ERROR recursion in an async block requires boxing } } diff --git a/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr b/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr index 11d9cd0af081..b62186103c7c 100644 --- a/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr +++ b/tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr @@ -1,27 +1,20 @@ -error[E0391]: cycle detected when computing layout of `{async block@$DIR/indirect-recursion-issue-112047.rs:22:9: 22:42}` - --> $DIR/indirect-recursion-issue-112047.rs:22:22 +error[E0733]: recursion in an async block requires boxing + --> $DIR/indirect-recursion-issue-112047.rs:22:9 | LL | async move { recur(self).await; } - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^-----------------^^^ + | | + | recursive call here | - = note: ...which requires computing layout of `core::mem::maybe_uninit::MaybeUninit<{async fn body@$DIR/indirect-recursion-issue-112047.rs:14:31: 16:2}>`... - = note: ...which requires computing layout of `core::mem::manually_drop::ManuallyDrop<{async fn body@$DIR/indirect-recursion-issue-112047.rs:14:31: 16:2}>`... -note: ...which requires computing layout of `{async fn body@$DIR/indirect-recursion-issue-112047.rs:14:31: 16:2}`... - --> $DIR/indirect-recursion-issue-112047.rs:15:5 +note: which leads to this async fn + --> $DIR/indirect-recursion-issue-112047.rs:14:1 | +LL | async fn recur(t: impl Recur) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | t.recur().await; - | ^^^^^^^^^^^^^^^ - = note: ...which requires computing layout of `core::mem::maybe_uninit::MaybeUninit<<() as Recur>::Recur>`... - = note: ...which requires computing layout of `core::mem::maybe_uninit::MaybeUninit<{async block@$DIR/indirect-recursion-issue-112047.rs:22:9: 22:42}>`... - = note: ...which requires computing layout of `core::mem::manually_drop::ManuallyDrop<{async block@$DIR/indirect-recursion-issue-112047.rs:22:9: 22:42}>`... - = note: ...which again requires computing layout of `{async block@$DIR/indirect-recursion-issue-112047.rs:22:9: 22:42}`, completing the cycle -note: cycle used when elaborating drops for `::recur` - --> $DIR/indirect-recursion-issue-112047.rs:21:5 - | -LL | fn recur(self) -> Self::Recur { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + | --------------- ...leading to this recursive call + = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0391`. +For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/type-alias-impl-trait/issue-77179.rs b/tests/ui/type-alias-impl-trait/issue-77179.rs index e7b04a489755..6e2ce76632fd 100644 --- a/tests/ui/type-alias-impl-trait/issue-77179.rs +++ b/tests/ui/type-alias-impl-trait/issue-77179.rs @@ -1,4 +1,4 @@ -// Regression test for #77179. +// Regression test for the ICE in #77179. #![feature(type_alias_impl_trait)] @@ -6,7 +6,9 @@ type Pointer = impl std::ops::Deref; fn test() -> Pointer<_> { //~^ ERROR: the placeholder `_` is not allowed within types + //~| ERROR: non-defining opaque type use in defining scope Box::new(1) + //~^ ERROR expected generic type parameter, found `i32` } fn main() { diff --git a/tests/ui/type-alias-impl-trait/issue-77179.stderr b/tests/ui/type-alias-impl-trait/issue-77179.stderr index 68dd6570d00c..c5b7c4178e47 100644 --- a/tests/ui/type-alias-impl-trait/issue-77179.stderr +++ b/tests/ui/type-alias-impl-trait/issue-77179.stderr @@ -7,6 +7,28 @@ LL | fn test() -> Pointer<_> { | | not allowed in type signatures | help: replace with the correct return type: `Pointer` -error: aborting due to 1 previous error +error[E0792]: non-defining opaque type use in defining scope + --> $DIR/issue-77179.rs:7:14 + | +LL | fn test() -> Pointer<_> { + | ^^^^^^^^^^ argument `i32` is not a generic parameter + | +note: for this opaque type + --> $DIR/issue-77179.rs:5:19 + | +LL | type Pointer = impl std::ops::Deref; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -For more information about this error, try `rustc --explain E0121`. +error[E0792]: expected generic type parameter, found `i32` + --> $DIR/issue-77179.rs:10:5 + | +LL | type Pointer = impl std::ops::Deref; + | - this generic parameter must be used with a generic type parameter +... +LL | Box::new(1) + | ^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0121, E0792. +For more information about an error, try `rustc --explain E0121`. diff --git a/tests/ui/type-alias-impl-trait/nested-in-anon-const.rs b/tests/ui/type-alias-impl-trait/nested-in-anon-const.rs new file mode 100644 index 000000000000..e9d53c99d041 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/nested-in-anon-const.rs @@ -0,0 +1,21 @@ +// Regression test for issue #119295. + +#![feature(type_alias_impl_trait)] + +type Bar = T; +type S = [i32; A]; + +extern "C" { + pub fn lint_me( + x: Bar< + S< + { //~ ERROR mismatched types + type B = impl Sized; + //~^ ERROR unconstrained opaque type + }, + >, + >, + ); +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr b/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr new file mode 100644 index 000000000000..d0fe920b35f4 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr @@ -0,0 +1,20 @@ +error: unconstrained opaque type + --> $DIR/nested-in-anon-const.rs:13:33 + | +LL | type B = impl Sized; + | ^^^^^^^^^^ + | + = note: `B` must be used in combination with a concrete type within the same item + +error[E0308]: mismatched types + --> $DIR/nested-in-anon-const.rs:12:17 + | +LL | / { +LL | | type B = impl Sized; +LL | | +LL | | }, + | |_________________^ expected `usize`, found `()` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.rs index 9796823a7244..46c2c22cac1c 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.rs +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.rs @@ -4,7 +4,7 @@ // FIXME: this is ruled out for now but should work type Foo = fn() -> impl Send; -//~^ ERROR: `impl Trait` only allowed in function and inherent method argument and return types +//~^ ERROR: `impl Trait` is not allowed in `fn` pointer return types fn make_foo() -> Foo { || 15 diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr index 5641ff301649..0f73c1424704 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr @@ -1,8 +1,10 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `fn` pointer return types +error[E0562]: `impl Trait` is not allowed in `fn` pointer return types --> $DIR/type-alias-impl-trait-fn-type.rs:6:20 | LL | type Foo = fn() -> impl Send; | ^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 1 previous error diff --git a/tests/ui/typeck/escaping_bound_vars.rs b/tests/ui/typeck/escaping_bound_vars.rs index 1fb063d2c268..f886388bfbd7 100644 --- a/tests/ui/typeck/escaping_bound_vars.rs +++ b/tests/ui/typeck/escaping_bound_vars.rs @@ -10,6 +10,10 @@ pub fn test() where (): Test<{ 1 + (<() as Elide(&())>::call) }>, //~^ ERROR cannot capture late-bound lifetime in constant + //~| ERROR associated type bindings are not allowed here + //~| ERROR the trait bound `(): Elide<(&(),)>` is not satisfied + //~| ERROR the trait bound `(): Elide<(&(),)>` is not satisfied + //~| ERROR cannot add { } diff --git a/tests/ui/typeck/escaping_bound_vars.stderr b/tests/ui/typeck/escaping_bound_vars.stderr index 3ea409435779..8c7dcdb7f161 100644 --- a/tests/ui/typeck/escaping_bound_vars.stderr +++ b/tests/ui/typeck/escaping_bound_vars.stderr @@ -6,5 +6,55 @@ LL | (): Test<{ 1 + (<() as Elide(&())>::call) }>, | | | lifetime defined here -error: aborting due to 1 previous error +error[E0229]: associated type bindings are not allowed here + --> $DIR/escaping_bound_vars.rs:11:28 + | +LL | (): Test<{ 1 + (<() as Elide(&())>::call) }>, + | ^^^^^^^^^^ associated type not allowed here +error[E0277]: the trait bound `(): Elide<(&(),)>` is not satisfied + --> $DIR/escaping_bound_vars.rs:11:22 + | +LL | (): Test<{ 1 + (<() as Elide(&())>::call) }>, + | ^^ the trait `Elide<(&(),)>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/escaping_bound_vars.rs:5:1 + | +LL | trait Elide { + | ^^^^^^^^^^^^^^ + +error[E0277]: cannot add `fn() {<() as Elide<(&(),)>>::call}` to `{integer}` + --> $DIR/escaping_bound_vars.rs:11:18 + | +LL | (): Test<{ 1 + (<() as Elide(&())>::call) }>, + | ^ no implementation for `{integer} + fn() {<() as Elide<(&(),)>>::call}` + | + = help: the trait `Add>::call}>` is not implemented for `{integer}` + = help: the following other types implement trait `Add`: + + > + + > + + > + + > + and 48 others + +error[E0277]: the trait bound `(): Elide<(&(),)>` is not satisfied + --> $DIR/escaping_bound_vars.rs:11:18 + | +LL | (): Test<{ 1 + (<() as Elide(&())>::call) }>, + | ^ the trait `Elide<(&(),)>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/escaping_bound_vars.rs:5:1 + | +LL | trait Elide { + | ^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0229, E0277. +For more information about an error, try `rustc --explain E0229`. diff --git a/tests/ui/typeck/issue-104513-ice.rs b/tests/ui/typeck/issue-104513-ice.rs index 4968d3f51fe8..aaeee9cef48a 100644 --- a/tests/ui/typeck/issue-104513-ice.rs +++ b/tests/ui/typeck/issue-104513-ice.rs @@ -1,6 +1,6 @@ struct S; fn f() { let _: S = S; //~ ERROR cannot find trait `Oops` in this scope - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + //~^ ERROR `impl Trait` is not allowed in the type of variable bindings } fn main() {} diff --git a/tests/ui/typeck/issue-104513-ice.stderr b/tests/ui/typeck/issue-104513-ice.stderr index 56c6b3361546..37d38a76a403 100644 --- a/tests/ui/typeck/issue-104513-ice.stderr +++ b/tests/ui/typeck/issue-104513-ice.stderr @@ -4,11 +4,13 @@ error[E0405]: cannot find trait `Oops` in this scope LL | let _: S = S; | ^^^^ not found in this scope -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in variable bindings +error[E0562]: `impl Trait` is not allowed in the type of variable bindings --> $DIR/issue-104513-ice.rs:3:14 | LL | let _: S = S; | ^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/issue-110052.rs b/tests/ui/typeck/issue-110052.rs index f124b58b5b60..acbfac30acb3 100644 --- a/tests/ui/typeck/issue-110052.rs +++ b/tests/ui/typeck/issue-110052.rs @@ -1,7 +1,7 @@ // Makes sure we deal with escaping lifetimes *above* INNERMOST when // suggesting trait for ambiguous associated type. -impl Validator for () +impl Validator for () where for<'iter> dyn Validator<<&'iter I>::Item>:, //~^ ERROR ambiguous associated type diff --git a/tests/ui/typeck/issue-79040.rs b/tests/ui/typeck/issue-79040.rs index 941612542207..03e008207566 100644 --- a/tests/ui/typeck/issue-79040.rs +++ b/tests/ui/typeck/issue-79040.rs @@ -1,5 +1,6 @@ fn main() { const FOO = "hello" + 1; //~ ERROR cannot add `{integer}` to `&str` //~^ missing type for `const` item + //~| ERROR cannot add `{integer}` to `&str` println!("{}", FOO); } diff --git a/tests/ui/typeck/issue-79040.stderr b/tests/ui/typeck/issue-79040.stderr index c820d1e08c4a..ce6a4b362170 100644 --- a/tests/ui/typeck/issue-79040.stderr +++ b/tests/ui/typeck/issue-79040.stderr @@ -12,6 +12,16 @@ error: missing type for `const` item LL | const FOO = "hello" + 1; | ^ help: provide a type for the item: `: ` -error: aborting due to 2 previous errors +error[E0369]: cannot add `{integer}` to `&str` + --> $DIR/issue-79040.rs:2:25 + | +LL | const FOO = "hello" + 1; + | ------- ^ - {integer} + | | + | &str + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/typeck/typeck-builtin-bound-type-parameters.rs b/tests/ui/typeck/typeck-builtin-bound-type-parameters.rs index e7e62c077394..5e5e88c8d0d6 100644 --- a/tests/ui/typeck/typeck-builtin-bound-type-parameters.rs +++ b/tests/ui/typeck/typeck-builtin-bound-type-parameters.rs @@ -4,11 +4,12 @@ fn foo1, U>(x: T) {} trait Trait: Copy {} //~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied //~| ERROR trait takes 0 generic arguments but 1 generic argument was supplied +//~| ERROR trait takes 0 generic arguments but 1 generic argument was supplied -struct MyStruct1>; +struct MyStruct1>(T); //~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied -struct MyStruct2<'a, T: Copy<'a>>; +struct MyStruct2<'a, T: Copy<'a>>(&'a T); //~^ ERROR trait takes 0 lifetime arguments but 1 lifetime argument was supplied fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} diff --git a/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr b/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr index 67ca2b061f9b..1dc1d46aa71a 100644 --- a/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr +++ b/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr @@ -25,23 +25,23 @@ LL | trait Trait: Copy {} = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/typeck-builtin-bound-type-parameters.rs:8:21 + --> $DIR/typeck-builtin-bound-type-parameters.rs:9:21 | -LL | struct MyStruct1>; +LL | struct MyStruct1>(T); | ^^^^--- help: remove these generics | | | expected 0 generic arguments error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/typeck-builtin-bound-type-parameters.rs:11:25 + --> $DIR/typeck-builtin-bound-type-parameters.rs:12:25 | -LL | struct MyStruct2<'a, T: Copy<'a>>; +LL | struct MyStruct2<'a, T: Copy<'a>>(&'a T); | ^^^^---- help: remove these generics | | | expected 0 lifetime arguments error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/typeck-builtin-bound-type-parameters.rs:14:15 + --> $DIR/typeck-builtin-bound-type-parameters.rs:15:15 | LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} | ^^^^ -- help: remove this lifetime argument @@ -49,13 +49,23 @@ LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} | expected 0 lifetime arguments error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/typeck-builtin-bound-type-parameters.rs:14:15 + --> $DIR/typeck-builtin-bound-type-parameters.rs:15:15 | LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} | ^^^^ - help: remove this generic argument | | | expected 0 generic arguments -error: aborting due to 7 previous errors +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/typeck-builtin-bound-type-parameters.rs:4:14 + | +LL | trait Trait: Copy {} + | ^^^^---------- help: remove these generics + | | + | expected 0 generic arguments + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs index 4eba14f5a93f..f6d1fb6a23d4 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.rs +++ b/tests/ui/typeck/typeck_type_placeholder_item.rs @@ -198,6 +198,7 @@ trait Qux { //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types } impl Qux for Struct { + //~^ ERROR: not all trait items implemented, missing: `F` type A = _; //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types type B = _; diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index a4325b01f02c..bfcc76c1dae7 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -29,7 +29,7 @@ LL | struct BadStruct2<_, T>(_, T); | ^ expected identifier, found reserved identifier error: associated constant in `impl` without body - --> $DIR/typeck_type_placeholder_item.rs:205:5 + --> $DIR/typeck_type_placeholder_item.rs:206:5 | LL | const C: _; | ^^^^^^^^^^- @@ -411,7 +411,7 @@ LL | type Y = impl Trait<_>; | ^ not allowed in type signatures error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types - --> $DIR/typeck_type_placeholder_item.rs:216:31 + --> $DIR/typeck_type_placeholder_item.rs:217:31 | LL | fn value() -> Option<&'static _> { | ----------------^- @@ -420,7 +420,7 @@ LL | fn value() -> Option<&'static _> { | help: replace with the correct return type: `Option<&'static u8>` error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants - --> $DIR/typeck_type_placeholder_item.rs:221:10 + --> $DIR/typeck_type_placeholder_item.rs:222:10 | LL | const _: Option<_> = map(value); | ^^^^^^^^^ @@ -429,7 +429,7 @@ LL | const _: Option<_> = map(value); | help: replace with the correct type: `Option` error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types - --> $DIR/typeck_type_placeholder_item.rs:224:31 + --> $DIR/typeck_type_placeholder_item.rs:225:31 | LL | fn evens_squared(n: usize) -> _ { | ^ @@ -438,13 +438,13 @@ LL | fn evens_squared(n: usize) -> _ { | help: replace with an appropriate return type: `impl Iterator` error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants - --> $DIR/typeck_type_placeholder_item.rs:229:10 + --> $DIR/typeck_type_placeholder_item.rs:230:10 | LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); | ^ not allowed in type signatures | -note: however, the inferred type `Map, {closure@typeck_type_placeholder_item.rs:229:29}>, {closure@typeck_type_placeholder_item.rs:229:49}>` cannot be named - --> $DIR/typeck_type_placeholder_item.rs:229:14 +note: however, the inferred type `Map, {closure@typeck_type_placeholder_item.rs:230:29}>, {closure@typeck_type_placeholder_item.rs:230:49}>` cannot be named + --> $DIR/typeck_type_placeholder_item.rs:230:14 | LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -631,25 +631,25 @@ LL | fn clone_from(&mut self, other: &FnTest9) { *self = FnTest9; } | ~~~~~~~~ error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types - --> $DIR/typeck_type_placeholder_item.rs:201:14 + --> $DIR/typeck_type_placeholder_item.rs:202:14 | LL | type A = _; | ^ not allowed in type signatures error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types - --> $DIR/typeck_type_placeholder_item.rs:203:14 + --> $DIR/typeck_type_placeholder_item.rs:204:14 | LL | type B = _; | ^ not allowed in type signatures error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants - --> $DIR/typeck_type_placeholder_item.rs:205:14 + --> $DIR/typeck_type_placeholder_item.rs:206:14 | LL | const C: _; | ^ not allowed in type signatures error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants - --> $DIR/typeck_type_placeholder_item.rs:208:14 + --> $DIR/typeck_type_placeholder_item.rs:209:14 | LL | const D: _ = 42; | ^ @@ -657,7 +657,16 @@ LL | const D: _ = 42; | not allowed in type signatures | help: replace with the correct type: `i32` -error: aborting due to 71 previous errors +error[E0046]: not all trait items implemented, missing: `F` + --> $DIR/typeck_type_placeholder_item.rs:200:1 + | +LL | type F: std::ops::Fn(_); + | ----------------------- `F` from trait +... +LL | impl Qux for Struct { + | ^^^^^^^^^^^^^^^^^^^ missing `F` in implementation -Some errors have detailed explanations: E0121, E0282, E0403. -For more information about an error, try `rustc --explain E0121`. +error: aborting due to 72 previous errors + +Some errors have detailed explanations: E0046, E0121, E0282, E0403. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/typeck/typeck_type_placeholder_item_help.rs b/tests/ui/typeck/typeck_type_placeholder_item_help.rs index 914f8a2b28b3..ff6182588c72 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item_help.rs +++ b/tests/ui/typeck/typeck_type_placeholder_item_help.rs @@ -27,7 +27,7 @@ impl Test6 { } pub fn main() { - let _: Option = test1(); - let _: f64 = test1(); + let _: Option = test1(); //~ ERROR mismatched types + let _: f64 = test1(); //~ ERROR mismatched types let _: Option = test1(); } diff --git a/tests/ui/typeck/typeck_type_placeholder_item_help.stderr b/tests/ui/typeck/typeck_type_placeholder_item_help.stderr index ed6f4088019f..b0d4ed8272be 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item_help.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item_help.stderr @@ -55,6 +55,29 @@ LL | const TEST6: _ = 13; | not allowed in type signatures | help: replace with the correct type: `i32` -error: aborting due to 7 previous errors +error[E0308]: mismatched types + --> $DIR/typeck_type_placeholder_item_help.rs:30:28 + | +LL | let _: Option = test1(); + | ------------- ^^^^^^^ expected `Option`, found `Option` + | | + | expected due to this + | + = note: expected enum `Option` + found enum `Option` -For more information about this error, try `rustc --explain E0121`. +error[E0308]: mismatched types + --> $DIR/typeck_type_placeholder_item_help.rs:31:18 + | +LL | let _: f64 = test1(); + | --- ^^^^^^^ expected `f64`, found `Option` + | | + | expected due to this + | + = note: expected type `f64` + found enum `Option` + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0121, E0308. +For more information about an error, try `rustc --explain E0121`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs index c575f507704e..ea73b8b3c4a2 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs @@ -21,10 +21,12 @@ fn same_type>(a: A, b: B) { } fn test<'a,'b>() { // Parens are equivalent to omitting default in angle. eq::< dyn Foo<(isize,),Output=()>, dyn Foo(isize) >(); + //~^ ERROR trait takes 1 lifetime argument but 0 lifetime arguments were supplied // Here we specify 'static explicitly in angle-bracket version. // Parenthesized winds up getting inferred. eq::< dyn Foo<'static, (isize,),Output=()>, dyn Foo(isize) >(); + //~^ ERROR trait takes 1 lifetime argument but 0 lifetime arguments were supplied } fn test2(x: &dyn Foo<(isize,),Output=()>, y: &dyn Foo(isize)) { diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr index 0465c20dffa2..d73aef851fd7 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr @@ -1,5 +1,5 @@ error[E0107]: trait takes 1 lifetime argument but 0 lifetime arguments were supplied - --> $DIR/unboxed-closure-sugar-region.rs:30:51 + --> $DIR/unboxed-closure-sugar-region.rs:32:51 | LL | fn test2(x: &dyn Foo<(isize,),Output=()>, y: &dyn Foo(isize)) { | ^^^ expected 1 lifetime argument @@ -10,6 +10,30 @@ note: trait defined here, with 1 lifetime parameter: `'a` LL | trait Foo<'a,T> { | ^^^ -- -error: aborting due to 1 previous error +error[E0107]: trait takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/unboxed-closure-sugar-region.rs:23:58 + | +LL | eq::< dyn Foo<(isize,),Output=()>, dyn Foo(isize) >(); + | ^^^ expected 1 lifetime argument + | +note: trait defined here, with 1 lifetime parameter: `'a` + --> $DIR/unboxed-closure-sugar-region.rs:10:7 + | +LL | trait Foo<'a,T> { + | ^^^ -- + +error[E0107]: trait takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/unboxed-closure-sugar-region.rs:28:58 + | +LL | eq::< dyn Foo<'static, (isize,),Output=()>, dyn Foo(isize) >(); + | ^^^ expected 1 lifetime argument + | +note: trait defined here, with 1 lifetime parameter: `'a` + --> $DIR/unboxed-closure-sugar-region.rs:10:7 + | +LL | trait Foo<'a,T> { + | ^^^ -- + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs index 2c7e12f32575..43db7870ada5 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs @@ -2,25 +2,25 @@ trait Zero { fn dummy(&self); } -fn foo1(_: dyn Zero()) { +fn foo1(_: &dyn Zero()) { //~^ ERROR trait takes 0 generic arguments but 1 generic argument //~| ERROR associated type `Output` not found for `Zero` } -fn foo2(_: dyn Zero) { +fn foo2(_: &dyn Zero) { //~^ ERROR trait takes 0 generic arguments but 1 generic argument } -fn foo3(_: dyn Zero < usize >) { +fn foo3(_: &dyn Zero < usize >) { //~^ ERROR trait takes 0 generic arguments but 1 generic argument } -fn foo4(_: dyn Zero(usize)) { +fn foo4(_: &dyn Zero(usize)) { //~^ ERROR trait takes 0 generic arguments but 1 generic argument //~| ERROR associated type `Output` not found for `Zero` } -fn foo5(_: dyn Zero ( usize )) { +fn foo5(_: &dyn Zero ( usize )) { //~^ ERROR trait takes 0 generic arguments but 1 generic argument //~| ERROR associated type `Output` not found for `Zero` } diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr index 50b90553aa71..5a2de132d70e 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr @@ -1,10 +1,10 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:5:16 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:5:17 | -LL | fn foo1(_: dyn Zero()) { - | ^^^^-- help: remove these parenthetical generics - | | - | expected 0 generic arguments +LL | fn foo1(_: &dyn Zero()) { + | ^^^^-- help: remove these parenthetical generics + | | + | expected 0 generic arguments | note: trait defined here, with 0 generic parameters --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:3:7 @@ -13,18 +13,18 @@ LL | trait Zero { fn dummy(&self); } | ^^^^ error[E0220]: associated type `Output` not found for `Zero` - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:5:16 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:5:17 | -LL | fn foo1(_: dyn Zero()) { - | ^^^^^^ associated type `Output` not found +LL | fn foo1(_: &dyn Zero()) { + | ^^^^^^ associated type `Output` not found error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:10:16 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:10:17 | -LL | fn foo2(_: dyn Zero) { - | ^^^^------- help: remove these generics - | | - | expected 0 generic arguments +LL | fn foo2(_: &dyn Zero) { + | ^^^^------- help: remove these generics + | | + | expected 0 generic arguments | note: trait defined here, with 0 generic parameters --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:3:7 @@ -33,12 +33,12 @@ LL | trait Zero { fn dummy(&self); } | ^^^^ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:14:16 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:14:17 | -LL | fn foo3(_: dyn Zero < usize >) { - | ^^^^-------------- help: remove these generics - | | - | expected 0 generic arguments +LL | fn foo3(_: &dyn Zero < usize >) { + | ^^^^-------------- help: remove these generics + | | + | expected 0 generic arguments | note: trait defined here, with 0 generic parameters --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:3:7 @@ -47,12 +47,12 @@ LL | trait Zero { fn dummy(&self); } | ^^^^ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:18:16 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:18:17 | -LL | fn foo4(_: dyn Zero(usize)) { - | ^^^^------- help: remove these parenthetical generics - | | - | expected 0 generic arguments +LL | fn foo4(_: &dyn Zero(usize)) { + | ^^^^------- help: remove these parenthetical generics + | | + | expected 0 generic arguments | note: trait defined here, with 0 generic parameters --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:3:7 @@ -61,18 +61,18 @@ LL | trait Zero { fn dummy(&self); } | ^^^^ error[E0220]: associated type `Output` not found for `Zero` - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:18:16 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:18:17 | -LL | fn foo4(_: dyn Zero(usize)) { - | ^^^^^^^^^^^ associated type `Output` not found +LL | fn foo4(_: &dyn Zero(usize)) { + | ^^^^^^^^^^^ associated type `Output` not found error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:23:16 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:23:17 | -LL | fn foo5(_: dyn Zero ( usize )) { - | ^^^^-------------- help: remove these parenthetical generics - | | - | expected 0 generic arguments +LL | fn foo5(_: &dyn Zero ( usize )) { + | ^^^^-------------- help: remove these parenthetical generics + | | + | expected 0 generic arguments | note: trait defined here, with 0 generic parameters --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:3:7 @@ -81,10 +81,10 @@ LL | trait Zero { fn dummy(&self); } | ^^^^ error[E0220]: associated type `Output` not found for `Zero` - --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:23:16 + --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:23:17 | -LL | fn foo5(_: dyn Zero ( usize )) { - | ^^^^^^^^^^^^^^^^^^ associated type `Output` not found +LL | fn foo5(_: &dyn Zero ( usize )) { + | ^^^^^^^^^^^^^^^^^^ associated type `Output` not found error: aborting due to 8 previous errors diff --git a/tests/ui/unused-crate-deps/test.mk b/tests/ui/unused-crate-deps/test.mk deleted file mode 100644 index 0b98b4e44fb2..000000000000 --- a/tests/ui/unused-crate-deps/test.mk +++ /dev/null @@ -1,7 +0,0 @@ -# Everyone uses make for building Rust - -foo: bar.rlib - $(RUSTC) --crate-type bin --extern bar=bar.rlib - -%.rlib: %.rs - $(RUSTC) --crate-type lib $<