diff options
920 files changed, 14109 insertions, 5963 deletions
diff --git a/Cargo.lock b/Cargo.lock index da99ac9b8af..9d1481ec768 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -638,7 +638,7 @@ dependencies = [ "filetime", "futures", "if_chain", - "itertools 0.12.1", + "itertools", "parking_lot", "quote", "regex", @@ -670,7 +670,7 @@ dependencies = [ "aho-corasick", "clap", "indoc", - "itertools 0.12.1", + "itertools", "opener 0.6.1", "shell-escape", "walkdir", @@ -685,7 +685,7 @@ dependencies = [ "clippy_config", "clippy_utils", "declare_clippy_lint", - "itertools 0.12.1", + "itertools", "quine-mc_cluskey", "regex", "regex-syntax 0.8.4", @@ -707,8 +707,9 @@ version = "0.1.81" dependencies = [ "arrayvec", "clippy_config", - "itertools 0.12.1", + "itertools", "rustc-semver", + "rustc_apfloat", ] [[package]] @@ -1025,7 +1026,7 @@ dependencies = [ name = "declare_clippy_lint" version = "0.1.81" dependencies = [ - "itertools 0.12.1", + "itertools", "quote", "syn 2.0.66", ] @@ -1132,16 +1133,16 @@ version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" dependencies = [ - "dirs-sys 0.4.1", + "dirs-sys", ] [[package]] name = "dirs" -version = "4.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ - "dirs-sys 0.3.7", + "dirs-sys", ] [[package]] @@ -1156,17 +1157,6 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dirs-sys" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" @@ -2077,15 +2067,6 @@ checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" [[package]] name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" @@ -2226,7 +2207,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -3664,7 +3645,7 @@ dependencies = [ name = "rustc_ast_passes" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_ast", "rustc_ast_pretty", "rustc_attr", @@ -3684,7 +3665,7 @@ dependencies = [ name = "rustc_ast_pretty" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_ast", "rustc_lexer", "rustc_span", @@ -3725,7 +3706,7 @@ name = "rustc_borrowck" version = "0.0.0" dependencies = [ "either", - "itertools 0.12.1", + "itertools", "polonius-engine", "rustc_data_structures", "rustc_errors", @@ -3778,7 +3759,7 @@ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ "bitflags 2.5.0", - "itertools 0.12.1", + "itertools", "libc", "measureme", "object 0.32.2", @@ -3817,7 +3798,7 @@ dependencies = [ "bitflags 2.5.0", "cc", "either", - "itertools 0.12.1", + "itertools", "jobserver", "libc", "object 0.32.2", @@ -4097,7 +4078,7 @@ dependencies = [ name = "rustc_hir_analysis" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_arena", "rustc_ast", "rustc_attr", @@ -4136,7 +4117,7 @@ dependencies = [ name = "rustc_hir_typeck" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_ast", "rustc_ast_ir", "rustc_attr", @@ -4420,7 +4401,7 @@ dependencies = [ name = "rustc_mir_build" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_apfloat", "rustc_arena", "rustc_ast", @@ -4467,7 +4448,7 @@ name = "rustc_mir_transform" version = "0.0.0" dependencies = [ "either", - "itertools 0.12.1", + "itertools", "rustc_arena", "rustc_ast", "rustc_attr", @@ -4761,6 +4742,7 @@ dependencies = [ name = "rustc_span" version = "0.0.0" dependencies = [ + "derivative", "indexmap", "itoa", "md-5", @@ -4822,7 +4804,7 @@ version = "0.0.0" dependencies = [ "bitflags 2.5.0", "derivative", - "itertools 0.12.1", + "itertools", "rustc_ast", "rustc_ast_ir", "rustc_attr", @@ -4865,7 +4847,7 @@ dependencies = [ name = "rustc_transmute" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_ast_ir", "rustc_data_structures", "rustc_hir", @@ -4881,7 +4863,7 @@ dependencies = [ name = "rustc_ty_utils" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_ast_ir", "rustc_data_structures", "rustc_errors", @@ -4905,6 +4887,7 @@ version = "0.0.0" dependencies = [ "bitflags 2.5.0", "derivative", + "indexmap", "rustc_ast_ir", "rustc_data_structures", "rustc_index", @@ -4944,7 +4927,7 @@ dependencies = [ "base64", "expect-test", "indexmap", - "itertools 0.12.1", + "itertools", "minifier", "regex", "rustdoc-json-types", @@ -5025,20 +5008,19 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.7.0" +version = "1.7.1" dependencies = [ "annotate-snippets 0.9.2", "anyhow", "bytecount", - "cargo_metadata 0.15.4", + "cargo_metadata 0.18.1", "clap", "clap-cargo", "diff", "dirs", "getopts", "ignore", - "itertools 0.11.0", - "lazy_static", + "itertools", "regex", "rustfmt-config_proc_macro", "serde", @@ -5697,6 +5679,7 @@ name = "tidy" version = "0.1.0" dependencies = [ "cargo_metadata 0.15.4", + "fluent-syntax", "ignore", "miropt-test-tools", "regex", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 71932f02017..30c54ef2d3c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3184,38 +3184,6 @@ pub struct StaticItem { pub expr: Option<P<Expr>>, } -/// A static item in `extern` block. -// This struct is identical to StaticItem for now but it's going to have a safety attribute. -#[derive(Clone, Encodable, Decodable, Debug)] -pub struct StaticForeignItem { - pub ty: P<Ty>, - pub safety: Safety, - pub mutability: Mutability, - pub expr: Option<P<Expr>>, -} - -impl From<StaticItem> for StaticForeignItem { - fn from(static_item: StaticItem) -> StaticForeignItem { - StaticForeignItem { - ty: static_item.ty, - safety: static_item.safety, - mutability: static_item.mutability, - expr: static_item.expr, - } - } -} - -impl From<StaticForeignItem> for StaticItem { - fn from(static_item: StaticForeignItem) -> StaticItem { - StaticItem { - ty: static_item.ty, - safety: static_item.safety, - mutability: static_item.mutability, - expr: static_item.expr, - } - } -} - #[derive(Clone, Encodable, Decodable, Debug)] pub struct ConstItem { pub defaultness: Defaultness, @@ -3430,7 +3398,7 @@ impl TryFrom<ItemKind> for AssocItemKind { #[derive(Clone, Encodable, Decodable, Debug)] pub enum ForeignItemKind { /// A foreign static item (`static FOO: u8`). - Static(Box<StaticForeignItem>), + Static(Box<StaticItem>), /// An foreign function. Fn(Box<Fn>), /// An foreign type. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 35aa53e978c..c9d2f5c779b 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1310,12 +1310,7 @@ pub fn noop_flat_map_item<K: NoopVisitItemKind>( impl NoopVisitItemKind for ForeignItemKind { fn noop_visit(&mut self, visitor: &mut impl MutVisitor) { match self { - ForeignItemKind::Static(box StaticForeignItem { - ty, - mutability: _, - expr, - safety: _, - }) => { + ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => { visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 109c401bb6a..cc66cc87652 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -558,9 +558,10 @@ impl Token { /// Returns `true` if the token can appear at the start of a const param. pub fn can_begin_const_arg(&self) -> bool { match self.kind { - OpenDelim(Delimiter::Brace) => true, + OpenDelim(Delimiter::Brace) | Literal(..) | BinOp(Minus) => true, + Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)), - _ => self.can_begin_literal_maybe_minus(), + _ => false, } } @@ -620,6 +621,21 @@ impl Token { } } + pub fn can_begin_string_literal(&self) -> bool { + match self.uninterpolate().kind { + Literal(..) => true, + Interpolated(ref nt) => match &**nt { + NtLiteral(_) => true, + NtExpr(e) => match &e.kind { + ast::ExprKind::Lit(_) => true, + _ => false, + }, + _ => false, + }, + _ => false, + } + } + /// A convenience function for matching on identifiers during parsing. /// Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token /// into the regular identifier or lifetime token it refers to, @@ -884,7 +900,11 @@ pub enum NonterminalKind { PatWithOr, Expr, /// Matches an expression using the rules from edition 2021 and earlier. - Expr2021, + Expr2021 { + /// Keep track of whether the user used `:expr` or `:expr_2021` and we inferred it from the + /// edition of the span. This is used for diagnostics AND feature gating. + inferred: bool, + }, Ty, Ident, Lifetime, @@ -913,8 +933,13 @@ impl NonterminalKind { Edition::Edition2021 | Edition::Edition2024 => NonterminalKind::PatWithOr, }, sym::pat_param => NonterminalKind::PatParam { inferred: false }, - sym::expr => NonterminalKind::Expr, - sym::expr_2021 if edition().at_least_rust_2021() => NonterminalKind::Expr2021, + sym::expr => match edition() { + Edition::Edition2015 | Edition::Edition2018 | Edition::Edition2021 => { + NonterminalKind::Expr2021 { inferred: true } + } + Edition::Edition2024 => NonterminalKind::Expr, + }, + sym::expr_2021 => NonterminalKind::Expr2021 { inferred: false }, sym::ty => NonterminalKind::Ty, sym::ident => NonterminalKind::Ident, sym::lifetime => NonterminalKind::Lifetime, @@ -933,8 +958,8 @@ impl NonterminalKind { NonterminalKind::Stmt => sym::stmt, NonterminalKind::PatParam { inferred: false } => sym::pat_param, NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat, - NonterminalKind::Expr => sym::expr, - NonterminalKind::Expr2021 => sym::expr_2021, + NonterminalKind::Expr | NonterminalKind::Expr2021 { inferred: true } => sym::expr, + NonterminalKind::Expr2021 { inferred: false } => sym::expr_2021, NonterminalKind::Ty => sym::ty, NonterminalKind::Ident => sym::ident, NonterminalKind::Lifetime => sym::lifetime, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ed34a44db67..ce38a67ea69 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -672,12 +672,7 @@ impl WalkItemKind for ForeignItemKind { ) -> V::Result { let &Item { id, span, ident, ref vis, .. } = item; match self { - ForeignItemKind::Static(box StaticForeignItem { - ty, - mutability: _, - expr, - safety: _, - }) => { + ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 7d81e45d314..52164d6ef16 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -78,7 +78,7 @@ ast_lowering_inline_asm_unsupported_target = ast_lowering_invalid_abi = invalid ABI: found `{$abi}` .label = invalid ABI - .note = invoke `{$command}` for a full list of supported calling conventions. + .note = invoke `{$command}` for a full list of supported calling conventions ast_lowering_invalid_abi_clobber_abi = invalid ABI for `clobber_abi` diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c6c0d9a2e60..4c7e8c24d32 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -664,12 +664,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ForeignItemKind::Fn(fn_dec, fn_args, generics, safety) } - ForeignItemKind::Static(box StaticForeignItem { - ty, - mutability, - expr: _, - safety, - }) => { + ForeignItemKind::Static(box StaticItem { ty, mutability, expr: _, safety }) => { let ty = self .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); let safety = self.lower_safety(*safety, hir::Safety::Unsafe); diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 2626631d800..7da726ef408 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -28,7 +28,10 @@ ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetim .label = {ast_passes_auto_super_lifetime} .suggestion = remove the super traits or lifetime bounds -ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic +ast_passes_bad_c_variadic = only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + +ast_passes_bare_fn_invalid_safety = function pointers cannot be declared with `safe` safety qualifier + .suggestion = remove safe from this item ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block .cannot_have = cannot have a body @@ -167,6 +170,9 @@ ast_passes_invalid_unnamed_field_ty = unnamed fields can only have struct or union types .label = not a struct or union +ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot be declared with `safe` safety qualifier + .suggestion = remove safe from this item + ast_passes_item_underscore = `{$kind}` items in this context need a name .label = `_` is not a valid name for this `{$kind}` item diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index b274a9b9114..79717c969d7 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -456,15 +456,29 @@ impl<'a> AstValidator<'a> { } } - fn check_foreign_item_safety(&self, item_span: Span, safety: Safety) { - if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) - && (self.extern_mod_safety == Some(Safety::Default) - || !self.features.unsafe_extern_blocks) - { - self.dcx().emit_err(errors::InvalidSafetyOnExtern { - item_span, - block: self.current_extern_span(), - }); + fn check_item_safety(&self, span: Span, safety: Safety) { + match self.extern_mod_safety { + Some(extern_safety) => { + if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) + && (extern_safety == Safety::Default || !self.features.unsafe_extern_blocks) + { + self.dcx().emit_err(errors::InvalidSafetyOnExtern { + item_span: span, + block: self.current_extern_span(), + }); + } + } + None => { + if matches!(safety, Safety::Safe(_)) { + self.dcx().emit_err(errors::InvalidSafetyOnItem { span }); + } + } + } + } + + fn check_bare_fn_safety(&self, span: Span, safety: Safety) { + if matches!(safety, Safety::Safe(_)) { + self.dcx().emit_err(errors::InvalidSafetyOnBareFn { span }); } } @@ -623,6 +637,7 @@ impl<'a> AstValidator<'a> { (Some(FnCtxt::Foreign), _) => return, (Some(FnCtxt::Free), Some(header)) => match header.ext { Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _) + | Extern::Explicit(StrLit { symbol_unescaped: sym::C_dash_unwind, .. }, _) | Extern::Implicit(_) if matches!(header.safety, Safety::Unsafe(_)) => { @@ -746,6 +761,7 @@ impl<'a> AstValidator<'a> { fn visit_ty_common(&mut self, ty: &'a Ty) { match &ty.kind { TyKind::BareFn(bfty) => { + self.check_bare_fn_safety(bfty.decl_span, bfty.safety); self.check_fn_decl(&bfty.decl, SelfSemantic::No); Self::check_decl_no_pat(&bfty.decl, |span, _, _| { self.dcx().emit_err(errors::PatternFnPointer { span }); @@ -1174,11 +1190,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } } - ItemKind::Static(box StaticItem { expr: None, .. }) => { - self.dcx().emit_err(errors::StaticWithoutBody { - span: item.span, - replace_span: self.ending_semi_or_hi(item.span), - }); + ItemKind::Static(box StaticItem { expr, safety, .. }) => { + self.check_item_safety(item.span, *safety); + + if expr.is_none() { + self.dcx().emit_err(errors::StaticWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); + } } ItemKind::TyAlias( ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. }, @@ -1212,7 +1232,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { match &fi.kind { ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => { - self.check_foreign_item_safety(fi.span, sig.header.safety); self.check_defaultness(fi.span, *defaultness); self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); self.check_foreign_fn_headerless(sig.header); @@ -1232,8 +1251,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_foreign_ty_genericless(generics, where_clauses); self.check_foreign_item_ascii_only(fi.ident); } - ForeignItemKind::Static(box StaticForeignItem { expr, safety, .. }) => { - self.check_foreign_item_safety(fi.span, *safety); + ForeignItemKind::Static(box StaticItem { expr, safety, .. }) => { + self.check_item_safety(fi.span, *safety); self.check_foreign_kind_bodyless(fi.ident, "static", expr.as_ref().map(|b| b.span)); self.check_foreign_item_ascii_only(fi.ident); } @@ -1453,6 +1472,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }; self.check_fn_decl(fk.decl(), self_semantic); + if let Some(&FnHeader { safety, .. }) = fk.header() { + self.check_item_safety(span, safety); + } + self.check_c_variadic_type(fk); // Functions cannot both be `const async` or `const gen` diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 601910ded20..96c476b271c 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -226,6 +226,20 @@ pub struct InvalidSafetyOnExtern { } #[derive(Diagnostic)] +#[diag(ast_passes_item_invalid_safety)] +pub struct InvalidSafetyOnItem { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_bare_fn_invalid_safety)] +pub struct InvalidSafetyOnBareFn { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_bound_in_context)] pub struct BoundInContext<'a> { #[primary_span] diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 764d942836c..e1c1a027a30 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -562,6 +562,10 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental"); gate_all!(global_registration, "global registration is experimental"); gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental"); + gate_all!( + unsafe_extern_blocks, + "`unsafe extern {}` blocks and `safe` keyword are experimental" + ); if !visitor.features.never_patterns { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 49ac5ece337..d8382057d3f 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -37,12 +37,7 @@ impl<'a> State<'a> { ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); } - ast::ForeignItemKind::Static(box ast::StaticForeignItem { - ty, - mutability, - expr, - safety, - }) => { + ast::ForeignItemKind::Static(box ast::StaticItem { ty, mutability, expr, safety }) => { self.print_safety(*safety); self.print_item_const( ident, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 40b58500598..bf1c1b1433e 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1110,7 +1110,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { tcx: TyCtxt<'tcx>, } impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for OpaqueFolder<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 8f96070d149..c0310a2f4b0 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -1,6 +1,7 @@ +//! The expansion from a test function to the appropriate test struct for libtest +//! Ideally, this code would be in libtest but for efficiency and error messages it lives here. + use crate::errors; -/// The expansion from a test function to the appropriate test struct for libtest -/// Ideally, this code would be in libtest but for efficiency and error messages it lives here. use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; use rustc_ast::ptr::P; use rustc_ast::{self as ast, attr, GenericParamKind}; diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 2edb34e7c20..06ca52b3903 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -271,9 +271,9 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn TargetIs flags_builder.set("enable_verifier", enable_verifier).unwrap(); flags_builder.set("regalloc_checker", enable_verifier).unwrap(); - let preserve_frame_pointer = sess.target.options.frame_pointer - != rustc_target::spec::FramePointer::MayOmit - || matches!(sess.opts.cg.force_frame_pointers, Some(true)); + let mut frame_ptr = sess.target.options.frame_pointer.clone(); + frame_ptr.ratchet(sess.opts.cg.force_frame_pointers); + let preserve_frame_pointer = frame_ptr != rustc_target::spec::FramePointer::MayOmit; flags_builder .set("preserve_frame_pointers", if preserve_frame_pointer { "true" } else { "false" }) .unwrap(); diff --git a/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs b/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs index d321ffc8ff5..09307836fd4 100644 --- a/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs +++ b/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs @@ -1,4 +1,5 @@ //! The common code for `tests/lang_tests_*.rs` + use std::{ env::{self, current_dir}, path::{Path, PathBuf}, diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 60e63b956db..597ebd97365 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::*; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, span_bug, ty::Instance}; -use rustc_span::{Pos, Span}; +use rustc_span::{sym, Pos, Span, Symbol}; use rustc_target::abi::*; use rustc_target::asm::*; use tracing::debug; @@ -64,7 +64,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let mut layout = None; let ty = if let Some(ref place) = place { layout = Some(&place.layout); - llvm_fixup_output_type(self.cx, reg.reg_class(), &place.layout) + llvm_fixup_output_type(self.cx, reg.reg_class(), &place.layout, instance) } else if matches!( reg.reg_class(), InlineAsmRegClass::X86( @@ -112,7 +112,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { // so we just use the type of the input. &in_value.layout }; - let ty = llvm_fixup_output_type(self.cx, reg.reg_class(), layout); + let ty = llvm_fixup_output_type(self.cx, reg.reg_class(), layout, instance); output_types.push(ty); op_idx.insert(idx, constraints.len()); let prefix = if late { "=" } else { "=&" }; @@ -127,8 +127,13 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { for (idx, op) in operands.iter().enumerate() { match *op { InlineAsmOperandRef::In { reg, value } => { - let llval = - llvm_fixup_input(self, value.immediate(), reg.reg_class(), &value.layout); + let llval = llvm_fixup_input( + self, + value.immediate(), + reg.reg_class(), + &value.layout, + instance, + ); inputs.push(llval); op_idx.insert(idx, constraints.len()); constraints.push(reg_to_llvm(reg, Some(&value.layout))); @@ -139,6 +144,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { in_value.immediate(), reg.reg_class(), &in_value.layout, + instance, ); inputs.push(value); @@ -341,7 +347,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } else { self.extract_value(result, op_idx[&idx] as u64) }; - let value = llvm_fixup_output(self, value, reg.reg_class(), &place.layout); + let value = + llvm_fixup_output(self, value, reg.reg_class(), &place.layout, instance); OperandValue::Immediate(value).store(self, place); } } @@ -913,12 +920,22 @@ fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Ty } } +fn any_target_feature_enabled( + cx: &CodegenCx<'_, '_>, + instance: Instance<'_>, + features: &[Symbol], +) -> bool { + let enabled = cx.tcx.asm_target_features(instance.def_id()); + features.iter().any(|feat| enabled.contains(feat)) +} + /// Fix up an input value to work around LLVM bugs. fn llvm_fixup_input<'ll, 'tcx>( bx: &mut Builder<'_, 'll, 'tcx>, mut value: &'ll Value, reg: InlineAsmRegClass, layout: &TyAndLayout<'tcx>, + instance: Instance<'_>, ) -> &'ll Value { let dl = &bx.tcx.data_layout; match (reg, layout.abi) { @@ -1020,6 +1037,19 @@ fn llvm_fixup_input<'ll, 'tcx>( value } } + ( + InlineAsmRegClass::Arm( + ArmInlineAsmRegClass::dreg + | ArmInlineAsmRegClass::dreg_low8 + | ArmInlineAsmRegClass::dreg_low16 + | ArmInlineAsmRegClass::qreg + | ArmInlineAsmRegClass::qreg_low4 + | ArmInlineAsmRegClass::qreg_low8, + ), + Abi::Vector { element, count: count @ (4 | 8) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) + } (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. @@ -1029,6 +1059,16 @@ fn llvm_fixup_input<'ll, 'tcx>( _ => value, } } + (InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + if s.primitive() == Primitive::Float(Float::F16) + && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) => + { + // Smaller floats are always "NaN-boxed" inside larger floats on RISC-V. + let value = bx.bitcast(value, bx.type_i16()); + let value = bx.zext(value, bx.type_i32()); + let value = bx.or(value, bx.const_u32(0xFFFF_0000)); + bx.bitcast(value, bx.type_f32()) + } _ => value, } } @@ -1039,6 +1079,7 @@ fn llvm_fixup_output<'ll, 'tcx>( mut value: &'ll Value, reg: InlineAsmRegClass, layout: &TyAndLayout<'tcx>, + instance: Instance<'_>, ) -> &'ll Value { match (reg, layout.abi) { (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { @@ -1130,6 +1171,19 @@ fn llvm_fixup_output<'ll, 'tcx>( value } } + ( + InlineAsmRegClass::Arm( + ArmInlineAsmRegClass::dreg + | ArmInlineAsmRegClass::dreg_low8 + | ArmInlineAsmRegClass::dreg_low16 + | ArmInlineAsmRegClass::qreg + | ArmInlineAsmRegClass::qreg_low4 + | ArmInlineAsmRegClass::qreg_low8, + ), + Abi::Vector { element, count: count @ (4 | 8) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) + } (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. @@ -1140,6 +1194,14 @@ fn llvm_fixup_output<'ll, 'tcx>( _ => value, } } + (InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + if s.primitive() == Primitive::Float(Float::F16) + && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) => + { + let value = bx.bitcast(value, bx.type_i32()); + let value = bx.trunc(value, bx.type_i16()); + bx.bitcast(value, bx.type_f16()) + } _ => value, } } @@ -1149,6 +1211,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass, layout: &TyAndLayout<'tcx>, + instance: Instance<'_>, ) -> &'ll Type { match (reg, layout.abi) { (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { @@ -1233,6 +1296,19 @@ fn llvm_fixup_output_type<'ll, 'tcx>( layout.llvm_type(cx) } } + ( + InlineAsmRegClass::Arm( + ArmInlineAsmRegClass::dreg + | ArmInlineAsmRegClass::dreg_low8 + | ArmInlineAsmRegClass::dreg_low16 + | ArmInlineAsmRegClass::qreg + | ArmInlineAsmRegClass::qreg_low4 + | ArmInlineAsmRegClass::qreg_low8, + ), + Abi::Vector { element, count: count @ (4 | 8) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + cx.type_vector(cx.type_i16(), count) + } (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. @@ -1242,6 +1318,12 @@ fn llvm_fixup_output_type<'ll, 'tcx>( _ => layout.llvm_type(cx), } } + (InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + if s.primitive() == Primitive::Float(Float::F16) + && !any_target_feature_enabled(cx, instance, &[sym::zfhmin, sym::zfh]) => + { + cx.type_f32() + } _ => layout.llvm_type(cx), } } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 870e5ab3296..48693895da1 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -108,9 +108,10 @@ pub fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attr let opts = &cx.sess().opts; // "mcount" function relies on stack pointer. // See <https://sourceware.org/binutils/docs/gprof/Implementation.html>. - if opts.unstable_opts.instrument_mcount || matches!(opts.cg.force_frame_pointers, Some(true)) { - fp = FramePointer::Always; + if opts.unstable_opts.instrument_mcount { + fp.ratchet(FramePointer::Always); } + fp.ratchet(opts.cg.force_frame_pointers); let attr_value = match fp { FramePointer::Always => "all", FramePointer::NonLeaf => "non-leaf", diff --git a/compiler/rustc_codegen_ssa/src/mir/locals.rs b/compiler/rustc_codegen_ssa/src/mir/locals.rs index c7f63eab829..a6c873e195e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/locals.rs +++ b/compiler/rustc_codegen_ssa/src/mir/locals.rs @@ -1,6 +1,7 @@ //! Locals are in a private module as updating `LocalRef::Operand` has to //! be careful wrt to subtyping. To deal with this we only allow updates by using //! `FunctionCx::overwrite_local` which handles it automatically. + use crate::mir::{FunctionCx, LocalRef}; use crate::traits::BuilderMethods; use rustc_index::IndexVec; diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 05861e33767..f9e928a84a7 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -639,7 +639,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (OperandValue::Immediate(llval), operand.layout) } mir::UnOp::PtrMetadata => { - debug_assert!(operand.layout.ty.is_unsafe_ptr()); + debug_assert!( + operand.layout.ty.is_unsafe_ptr() || operand.layout.ty.is_ref(), + ); let (_, meta) = operand.val.pointer_parts(); assert_eq!(operand.layout.fields.count() > 1, meta.is_some()); if let Some(meta) = meta { diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 1a7e5bd7092..1476fe285ef 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -341,8 +341,7 @@ const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in const_eval_unallowed_heap_allocations = allocations are not allowed in {const_eval_const_context}s .label = allocation not allowed in {const_eval_const_context}s - .teach_note = - The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. + .teach_note = The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. const_eval_unallowed_inline_asm = inline assembly is not allowed in {const_eval_const_context}s diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 9a26ac04b85..9d0c4908225 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -630,6 +630,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } + /// Gives raw, immutable access to the `Allocation` address, without bounds or alignment checks. + /// The caller is responsible for calling the access hooks! + pub fn get_alloc_bytes_unchecked_raw(&self, id: AllocId) -> InterpResult<'tcx, *const u8> { + let alloc = self.get_alloc_raw(id)?; + Ok(alloc.get_bytes_unchecked_raw()) + } + /// Bounds-checked *but not align-checked* allocation access. pub fn get_ptr_alloc<'a>( &'a self, @@ -713,6 +720,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok((alloc, &mut self.machine)) } + /// Gives raw, mutable access to the `Allocation` address, without bounds or alignment checks. + /// The caller is responsible for calling the access hooks! + pub fn get_alloc_bytes_unchecked_raw_mut( + &mut self, + id: AllocId, + ) -> InterpResult<'tcx, *mut u8> { + let alloc = self.get_alloc_raw_mut(id)?.0; + Ok(alloc.get_bytes_unchecked_raw_mut()) + } + /// Bounds-checked *but not align-checked* allocation access. pub fn get_ptr_alloc_mut<'a>( &'a mut self, diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 73bdf96627a..2723507397e 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -460,7 +460,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let res = ScalarInt::truncate_from_uint(res, layout.size).0; Ok(ImmTy::from_scalar(res.into(), layout)) } - ty::RawPtr(..) => { + ty::RawPtr(..) | ty::Ref(..) => { assert_eq!(un_op, PtrMetadata); let (_, meta) = val.to_scalar_and_meta(); Ok(match meta { diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 08d3165867c..baaee67e787 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -441,7 +441,7 @@ where /// Take an operand, representing a pointer, and dereference it to a place. /// Corresponds to the `*` operator in Rust. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] pub fn deref_pointer( &self, src: &impl Readable<'tcx, M::Provenance>, @@ -533,7 +533,7 @@ where /// Computes a place. You should only use this if you intend to write into this /// place; for reading, a more efficient alternative is `eval_place_to_op`. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] pub fn eval_place( &self, mir_place: mir::Place<'tcx>, @@ -570,7 +570,7 @@ where /// Write an immediate to a place #[inline(always)] - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] pub fn write_immediate( &mut self, src: Immediate<M::Provenance>, @@ -808,7 +808,7 @@ where /// Copies the data from an operand to a place. /// `allow_transmute` indicates whether the layouts may disagree. #[inline(always)] - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] fn copy_op_inner( &mut self, src: &impl Readable<'tcx, M::Provenance>, @@ -837,7 +837,7 @@ where /// `allow_transmute` indicates whether the layouts may disagree. /// Also, if you use this you are responsible for validating that things get copied at the /// right type. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] fn copy_op_no_validate( &mut self, src: &impl Readable<'tcx, M::Provenance>, @@ -914,7 +914,7 @@ where /// If the place currently refers to a local that doesn't yet have a matching allocation, /// create such an allocation. /// This is essentially `force_to_memplace`. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] pub fn force_allocation( &mut self, place: &PlaceTy<'tcx, M::Provenance>, diff --git a/compiler/rustc_data_structures/src/base_n.rs b/compiler/rustc_data_structures/src/base_n.rs index aed89fadc4c..80810df14d0 100644 --- a/compiler/rustc_data_structures/src/base_n.rs +++ b/compiler/rustc_data_structures/src/base_n.rs @@ -1,5 +1,6 @@ -/// Converts unsigned integers into a string representation with some base. -/// Bases up to and including 36 can be used for case-insensitive things. +//! Converts unsigned integers into a string representation with some base. +//! Bases up to and including 36 can be used for case-insensitive things. + use std::ascii; use std::fmt; diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 245deda50d5..7405705dd33 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1905,7 +1905,7 @@ impl HumanEmitter { // // LL | this line was highlighted // LL | this line is just for context - // ... + // ... // LL | this line is just for context // LL | this line was highlighted _ => { @@ -1926,7 +1926,7 @@ impl HumanEmitter { ) } - buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber); + buffer.puts(row_num, 0, "...", Style::LineNumber); row_num += 1; if let Some((p, l)) = last_line { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 83d5bbff0b0..91112a57277 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1437,11 +1437,29 @@ impl DiagCtxtInner { // Return value is only `Some` if the level is `Error` or `DelayedBug`. fn emit_diagnostic(&mut self, mut diagnostic: DiagInner) -> Option<ErrorGuaranteed> { + match diagnostic.level { + Expect(expect_id) | ForceWarning(Some(expect_id)) => { + // The `LintExpectationId` can be stable or unstable depending on when it was + // created. Diagnostics created before the definition of `HirId`s are unstable and + // can not yet be stored. Instead, they are buffered until the `LintExpectationId` + // is replaced by a stable one by the `LintLevelsBuilder`. + if let LintExpectationId::Unstable { .. } = expect_id { + // We don't call TRACK_DIAGNOSTIC because we wait for the + // unstable ID to be updated, whereupon the diagnostic will be + // passed into this method again. + self.unstable_expect_diagnostics.push(diagnostic); + return None; + } + // Continue through to the `Expect`/`ForceWarning` case below. + } + _ => {} + } + if diagnostic.has_future_breakage() { - // Future breakages aren't emitted if they're `Level::Allow`, - // but they still need to be constructed and stashed below, - // so they'll trigger the must_produce_diag check. - assert!(matches!(diagnostic.level, Error | Warning | Allow)); + // Future breakages aren't emitted if they're `Level::Allow` or + // `Level::Expect`, but they still need to be constructed and + // stashed below, so they'll trigger the must_produce_diag check. + assert!(matches!(diagnostic.level, Error | Warning | Allow | Expect(_))); self.future_breakage_diagnostics.push(diagnostic.clone()); } @@ -1512,16 +1530,8 @@ impl DiagCtxtInner { return None; } Expect(expect_id) | ForceWarning(Some(expect_id)) => { - // Diagnostics created before the definition of `HirId`s are - // unstable and can not yet be stored. Instead, they are - // buffered until the `LintExpectationId` is replaced by a - // stable one by the `LintLevelsBuilder`. if let LintExpectationId::Unstable { .. } = expect_id { - // We don't call TRACK_DIAGNOSTIC because we wait for the - // unstable ID to be updated, whereupon the diagnostic will - // be passed into this method again. - self.unstable_expect_diagnostics.push(diagnostic); - return None; + unreachable!(); // this case was handled at the top of this function } self.fulfilled_expectations.insert(expect_id.normalize()); if let Expect(_) = diagnostic.level { diff --git a/compiler/rustc_errors/src/markdown/mod.rs b/compiler/rustc_errors/src/markdown/mod.rs index 53b766dfcce..64576cdc8ca 100644 --- a/compiler/rustc_errors/src/markdown/mod.rs +++ b/compiler/rustc_errors/src/markdown/mod.rs @@ -1,6 +1,7 @@ //! A simple markdown parser that can write formatted text to the terminal //! //! Entrypoint is `MdStream::parse_str(...)` + use std::io; use termcolor::{Buffer, BufferWriter, ColorChoice}; diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index d9a945a3215..56ef609612a 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -104,6 +104,7 @@ //! Kleene operators under which a meta-variable is repeating is the concatenation of the stacks //! stored when entering a macro definition starting from the state in which the meta-variable is //! bound. + use crate::errors; use crate::mbe::{KleeneToken, TokenTree}; diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 49b1f5ce0e3..0050ff10539 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -1292,7 +1292,9 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { // maintain IsInFollow::Yes } - NonterminalKind::Stmt | NonterminalKind::Expr | NonterminalKind::Expr2021 => { + NonterminalKind::Stmt + | NonterminalKind::Expr + | NonterminalKind::Expr2021 { inferred: _ } => { const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"]; match tok { TokenTree::Token(token) => match token.kind { diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 74f78c0ef78..fdf187438d3 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -113,7 +113,8 @@ pub(super) fn parse( ); token::NonterminalKind::Ident }); - if kind == token::NonterminalKind::Expr2021 + if kind + == (token::NonterminalKind::Expr2021 { inferred: false }) && !features.expr_fragment_specifier_2024 { rustc_session::parse::feature_err( diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index ef141c7c25e..9beaa6b8d95 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -80,6 +80,8 @@ declare_features! ( (accepted, braced_empty_structs, "1.8.0", Some(29720)), /// Allows `c"foo"` literals. (accepted, c_str_literals, "1.77.0", Some(105723)), + /// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries and treat `extern "C" fn` as nounwind. + (accepted, c_unwind, "CURRENT_RUSTC_VERSION", Some(74990)), /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. (accepted, cfg_attr_multi, "1.33.0", Some(54881)), /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index c165620f657..9e2756f07ed 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1089,6 +1089,14 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "the `#[custom_mir]` attribute is just used for the Rust test suite", ), rustc_attr!( + TEST, rustc_dump_item_bounds, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::No + ), + rustc_attr!( + TEST, rustc_dump_predicates, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::No + ), + rustc_attr!( TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No ), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 5cfbcdcbbbe..fbd67657e3b 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -363,8 +363,6 @@ declare_features! ( (unstable, async_for_loop, "1.77.0", Some(118898)), /// Allows builtin # foo() syntax (unstable, builtin_syntax, "1.71.0", Some(110680)), - /// Treat `extern "C"` function as nounwind. - (unstable, c_unwind, "1.52.0", Some(74990)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour. @@ -451,7 +449,7 @@ declare_features! ( /// Allows `dyn* Trait` objects. (incomplete, dyn_star, "1.65.0", Some(102425)), /// Uses generic effect parameters for ~const bounds - (unstable, effects, "1.72.0", Some(102090)), + (incomplete, effects, "1.72.0", Some(102090)), /// Allows exhaustive pattern matching on types that contain uninhabited types. (unstable, exhaustive_patterns, "1.13.0", Some(51085)), /// Allows explicit tail calls via `become` expression. diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 5a9b15204d5..d376c24cb58 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -1,9 +1,7 @@ -// tidy-alphabetical-start use std::ffi::CString; use std::fs; use std::io; use std::path::{absolute, Path, PathBuf}; -// tidy-alphabetical-end // Unfortunately, on windows, it looks like msvcrt.dll is silently translating // verbatim paths under the hood to non-verbatim paths! This manifests itself as diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 35833e258d5..5c86135ec8d 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -377,22 +377,17 @@ impl Definitions { } #[inline(always)] - pub fn local_def_path_hash_to_def_id( - &self, - hash: DefPathHash, - err_msg: &dyn std::fmt::Debug, - ) -> LocalDefId { + /// Returns `None` if the `DefPathHash` does not correspond to a `LocalDefId` + /// in the current compilation session. This can legitimately happen if the + /// `DefPathHash` is from a `DefId` in an upstream crate or, during incr. comp., + /// if the `DefPathHash` is from a previous compilation session and + /// the def-path does not exist anymore. + pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> Option<LocalDefId> { debug_assert!(hash.stable_crate_id() == self.table.stable_crate_id); - #[cold] - #[inline(never)] - fn err(err_msg: &dyn std::fmt::Debug) -> ! { - panic!("{err_msg:?}") - } self.table .def_path_hash_to_index .get(&hash.local_hash()) .map(|local_def_index| LocalDefId { local_def_index }) - .unwrap_or_else(|| err(err_msg)) } pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap { diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 8c740d87e95..7ed32fb9d9f 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -194,7 +194,7 @@ hir_analysis_inherent_ty_outside = cannot define inherent `impl` for a type outs .span_help = alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items hir_analysis_inherent_ty_outside_new = cannot define inherent `impl` for a type outside of the crate where the type is defined - .label = impl for type defined outside of crate. + .label = impl for type defined outside of crate .note = define and implement a trait or new type instead hir_analysis_inherent_ty_outside_primitive = cannot define inherent `impl` for primitive types outside of `core` @@ -510,7 +510,7 @@ hir_analysis_ty_param_some = type parameter `{$param}` must be used as the type .note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local .only_note = only traits defined in the current crate can be implemented for a type parameter -hir_analysis_type_of = {$type_of} +hir_analysis_type_of = {$ty} hir_analysis_typeof_reserved_keyword_used = `typeof` is a reserved keyword but unimplemented @@ -544,7 +544,7 @@ hir_analysis_unrecognized_intrinsic_function = hir_analysis_unused_associated_type_bounds = unnecessary associated type bound for not object safe associated type - .note = this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`. + .note = this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized` .suggestion = remove this bound hir_analysis_unused_generic_parameter = @@ -566,7 +566,7 @@ hir_analysis_value_of_associated_struct_already_specified = hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions} .label = C-variadic function must have a compatible calling convention -hir_analysis_variances_of = {$variances_of} +hir_analysis_variances_of = {$variances} hir_analysis_where_clause_on_main = `main` function is not allowed to have a `where` clause .label = `main` cannot have a `where` clause 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 82b57cdd106..550f38af8b5 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -397,7 +397,7 @@ struct RemapLateBound<'a, 'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -790,13 +790,13 @@ impl<'tcx, E> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx, E where E: 'tcx, { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.ocx.infcx.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { if let ty::Alias(ty::Projection, proj) = ty.kind() - && self.interner().is_impl_trait_in_trait(proj.def_id) + && self.cx().is_impl_trait_in_trait(proj.def_id) { if let Some((ty, _)) = self.types.get(&proj.def_id) { return *ty; @@ -810,9 +810,9 @@ where self.types.insert(proj.def_id, (infer_ty, proj.args)); // Recurse into bounds for (pred, pred_span) in self - .interner() + .cx() .explicit_item_bounds(proj.def_id) - .iter_instantiated_copied(self.interner(), proj.args) + .iter_instantiated_copied(self.cx(), proj.args) { let pred = pred.fold_with(self); let pred = self.ocx.normalize( @@ -822,7 +822,7 @@ where ); self.ocx.register_obligation(traits::Obligation::new( - self.interner(), + self.cx(), ObligationCause::new( self.span, self.body_id, @@ -853,7 +853,7 @@ struct RemapHiddenTyRegions<'tcx> { impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> { type Error = ErrorGuaranteed; - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -2072,7 +2072,7 @@ struct ReplaceTy<'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceTy<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 10b097a1060..6cdbd692f73 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -322,7 +322,7 @@ struct Anonymize<'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Anonymize<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 8ec6dd12a78..19371448025 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -1,6 +1,7 @@ // FIXME(@lcnr): Move this module out of `rustc_hir_analysis`. // // We don't do any drop checking during hir typeck. + use rustc_data_structures::fx::FxHashSet; use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 13180fa2673..683709f43f2 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -429,17 +429,17 @@ pub fn check_intrinsic_type( sym::ptr_guaranteed_cmp => ( 1, - 1, + 0, vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], tcx.types.u8, ), sym::const_allocate => { - (0, 1, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8)) + (0, 0, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8)) } sym::const_deallocate => ( 0, - 1, + 0, vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize], tcx.types.unit, ), @@ -478,16 +478,16 @@ pub fn check_intrinsic_type( | sym::frem_algebraic => (1, 0, vec![param(0), param(0)], param(0)), sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)), - sym::assume => (0, 1, vec![tcx.types.bool], tcx.types.unit), - sym::likely => (0, 1, vec![tcx.types.bool], tcx.types.bool), - sym::unlikely => (0, 1, vec![tcx.types.bool], tcx.types.bool), + sym::assume => (0, 0, vec![tcx.types.bool], tcx.types.unit), + sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool), + sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool), sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), sym::write_via_move => { (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) } - sym::typed_swap => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit), + sym::typed_swap => (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit), sym::discriminant_value => { let assoc_items = tcx.associated_item_def_ids( @@ -566,9 +566,9 @@ pub fn check_intrinsic_type( sym::black_box => (1, 0, vec![param(0)], param(0)), - sym::is_val_statically_known => (1, 1, vec![param(0)], tcx.types.bool), + sym::is_val_statically_known => (1, 0, vec![param(0)], tcx.types.bool), - sym::const_eval_select => (4, 1, vec![param(0), param(1), param(2)], param(3)), + sym::const_eval_select => (4, 0, vec![param(0), param(1), param(2)], param(3)), sym::vtable_size | sym::vtable_align => { (0, 0, vec![Ty::new_imm_ptr(tcx, tcx.types.unit)], tcx.types.usize) @@ -576,10 +576,10 @@ pub fn check_intrinsic_type( // This type check is not particularly useful, but the `where` bounds // on the definition in `core` do the heavy lifting for checking it. - sym::aggregate_raw_ptr => (3, 1, vec![param(1), param(2)], param(0)), - sym::ptr_metadata => (2, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)), + sym::aggregate_raw_ptr => (3, 0, vec![param(1), param(2)], param(0)), + sym::ptr_metadata => (2, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)), - sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool), + sym::ub_checks => (0, 0, Vec::new(), tcx.types.bool), sym::simd_eq | sym::simd_ne diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b206d8046ee..a188c1b12ae 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -119,16 +119,7 @@ where let errors = wfcx.select_all_or_error(); if !errors.is_empty() { - let err = infcx.err_ctxt().report_fulfillment_errors(errors); - if tcx.dcx().has_errors().is_some() { - return Err(err); - } else { - // HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs - // causes an delayed bug during normalization, without reporting an error, so we need - // to act as if no error happened, in order to let our callers continue and report an - // error later in check_impl_items_against_trait. - return Ok(()); - } + return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } debug!(?assumed_wf_types); diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 9421269e51e..5cb91603fd0 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -539,7 +539,7 @@ struct TyVarReplacer<'cx, 'tcx> { } impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for TyVarReplacer<'cx, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index c6e8759327f..e5bd147352d 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -45,8 +45,8 @@ use std::ops::Bound; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::errors; use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; -pub use type_of::test_opaque_hidden_types; +pub(crate) mod dump; mod generics_of; mod item_bounds; mod predicates_of; diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs new file mode 100644 index 00000000000..85e1c600d6d --- /dev/null +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -0,0 +1,43 @@ +use rustc_hir::def::DefKind; +use rustc_hir::def_id::CRATE_DEF_ID; +use rustc_middle::ty::TyCtxt; +use rustc_span::sym; + +pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) { + if !tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) { + return; + } + + for id in tcx.hir().items() { + let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue }; + + let ty = tcx.type_of(id.owner_id).instantiate_identity(); + + tcx.dcx().emit_err(crate::errors::TypeOf { span: tcx.def_span(id.owner_id), ty }); + } +} + +pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) { + for id in tcx.hir_crate_items(()).owners() { + if tcx.has_attr(id, sym::rustc_dump_predicates) { + let preds = tcx.predicates_of(id).instantiate_identity(tcx).predicates; + let span = tcx.def_span(id); + + let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_predicates.as_str()); + for pred in preds { + diag.note(format!("{pred:?}")); + } + diag.emit(); + } + if tcx.has_attr(id, sym::rustc_dump_item_bounds) { + let bounds = tcx.item_bounds(id).instantiate_identity(); + let span = tcx.def_span(id); + + let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_item_bounds.as_str()); + for bound in bounds { + diag.note(format!("{bound:?}")); + } + diag.emit(); + } + } +} diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 94d6e13d751..9f198933dee 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -203,7 +203,7 @@ struct AssocTyToOpaque<'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTyToOpaque<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 2684467a438..1e2b0c43233 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -15,7 +15,6 @@ use crate::errors::TypeofReservedKeywordUsed; use super::bad_placeholder; use super::ItemCtxt; -pub use opaque::test_opaque_hidden_types; mod opaque; 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 2b2f07001d2..d1048b742a0 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -1,28 +1,14 @@ use rustc_errors::StashKey; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP}; +use rustc_span::DUMMY_SP; -use crate::errors::{TaitForwardCompat, TaitForwardCompat2, TypeOf, UnconstrainedOpaqueType}; - -pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { - let mut res = Ok(()); - if tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) { - for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { - let type_of = tcx.type_of(id.owner_id).instantiate_identity(); - - res = Err(tcx.dcx().emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of })); - } - } - } - res -} +use crate::errors::{TaitForwardCompat, TaitForwardCompat2, UnconstrainedOpaqueType}; /// Checks "defining uses" of opaque `impl Trait` in associated types. /// These can only be defined by associated items of the same trait. diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index cff8d5a5ea5..44025c3cd61 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -682,7 +682,7 @@ pub(crate) enum CannotCaptureLateBound { pub(crate) struct VariancesOf { #[primary_span] pub span: Span, - pub variances_of: String, + pub variances: String, } #[derive(Diagnostic)] @@ -690,7 +690,7 @@ pub(crate) struct VariancesOf { pub(crate) struct TypeOf<'tcx> { #[primary_span] pub span: Span, - pub type_of: Ty<'tcx>, + pub ty: Ty<'tcx>, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 1927359421d..0428abcdf24 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -151,10 +151,6 @@ pub fn provide(providers: &mut Providers) { pub fn check_crate(tcx: TyCtxt<'_>) { let _prof_timer = tcx.sess.timer("type_check_crate"); - if tcx.features().rustc_attrs { - let _ = tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx)); - } - tcx.sess.time("coherence_checking", || { tcx.hir().par_for_each_module(|module| { let _ = tcx.ensure().check_mod_type_wf(module); @@ -169,11 +165,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) { }); if tcx.features().rustc_attrs { - let _ = tcx.sess.time("variance_testing", || variance::test::test_variance(tcx)); - } - - if tcx.features().rustc_attrs { - let _ = collect::test_opaque_hidden_types(tcx); + tcx.sess.time("outlives_dumping", || outlives::dump::inferred_outlives(tcx)); + tcx.sess.time("variance_dumping", || variance::dump::variances(tcx)); + collect::dump::opaque_hidden_types(tcx); + collect::dump::predicates_and_item_bounds(tcx); } // Make sure we evaluate all static and (non-associated) const items, even if unused. diff --git a/compiler/rustc_hir_analysis/src/outlives/dump.rs b/compiler/rustc_hir_analysis/src/outlives/dump.rs new file mode 100644 index 00000000000..ab50d9e86ef --- /dev/null +++ b/compiler/rustc_hir_analysis/src/outlives/dump.rs @@ -0,0 +1,29 @@ +use rustc_middle::bug; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::sym; + +pub(crate) fn inferred_outlives(tcx: TyCtxt<'_>) { + for id in tcx.hir().items() { + if !tcx.has_attr(id.owner_id, sym::rustc_outlives) { + continue; + } + + let preds = tcx.inferred_outlives_of(id.owner_id); + let mut preds: Vec<_> = preds + .iter() + .map(|(pred, _)| match pred.kind().skip_binder() { + ty::ClauseKind::RegionOutlives(p) => p.to_string(), + ty::ClauseKind::TypeOutlives(p) => p.to_string(), + err => bug!("unexpected clause {:?}", err), + }) + .collect(); + preds.sort(); + + let span = tcx.def_span(id.owner_id); + let mut err = tcx.dcx().struct_span_err(span, sym::rustc_outlives.as_str()); + for pred in preds { + err.note(pred); + } + err.emit(); + } +} diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index 97fd7731b1e..1f74ebf99f1 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -5,10 +5,9 @@ use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt, Upcast}; use rustc_span::Span; +pub(crate) mod dump; mod explicit; mod implicit_infer; -/// Code to write unit test for outlives. -pub mod test; mod utils; pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs deleted file mode 100644 index e9b6c679bd5..00000000000 --- a/compiler/rustc_hir_analysis/src/outlives/test.rs +++ /dev/null @@ -1,31 +0,0 @@ -use rustc_middle::bug; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::{symbol::sym, ErrorGuaranteed}; - -pub fn test_inferred_outlives(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { - let mut res = Ok(()); - for id in tcx.hir().items() { - // For unit testing: check for a special "rustc_outlives" - // attribute and report an error with various results if found. - if tcx.has_attr(id.owner_id, sym::rustc_outlives) { - let predicates = tcx.inferred_outlives_of(id.owner_id); - let mut pred: Vec<String> = predicates - .iter() - .map(|(out_pred, _)| match out_pred.kind().skip_binder() { - ty::ClauseKind::RegionOutlives(p) => p.to_string(), - ty::ClauseKind::TypeOutlives(p) => p.to_string(), - err => bug!("unexpected clause {:?}", err), - }) - .collect(); - pred.sort(); - - let span = tcx.def_span(id.owner_id); - let mut err = tcx.dcx().struct_span_err(span, "rustc_outlives"); - for p in pred { - err.note(p); - } - res = Err(err.emit()); - } - } - res -} diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs new file mode 100644 index 00000000000..1a17dabb677 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/variance/dump.rs @@ -0,0 +1,32 @@ +use rustc_hir::def::DefKind; +use rustc_hir::def_id::CRATE_DEF_ID; +use rustc_middle::ty::TyCtxt; +use rustc_span::symbol::sym; + +pub(crate) fn variances(tcx: TyCtxt<'_>) { + if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { + for id in tcx.hir().items() { + let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue }; + + let variances = tcx.variances_of(id.owner_id); + + tcx.dcx().emit_err(crate::errors::VariancesOf { + span: tcx.def_span(id.owner_id), + variances: format!("{variances:?}"), + }); + } + } + + for id in tcx.hir().items() { + if !tcx.has_attr(id.owner_id, sym::rustc_variance) { + continue; + } + + let variances = tcx.variances_of(id.owner_id); + + tcx.dcx().emit_err(crate::errors::VariancesOf { + span: tcx.def_span(id.owner_id), + variances: format!("{variances:?}"), + }); + } +} diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 1977451f39e..29f96e27b64 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -22,8 +22,7 @@ mod constraints; /// Code to solve constraints and write out the results. mod solve; -/// Code to write unit tests of variance. -pub mod test; +pub(crate) mod dump; /// Code for transforming variances. mod xform; diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs deleted file mode 100644 index c211e1af046..00000000000 --- a/compiler/rustc_hir_analysis/src/variance/test.rs +++ /dev/null @@ -1,37 +0,0 @@ -use rustc_hir::def::DefKind; -use rustc_hir::def_id::CRATE_DEF_ID; -use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::sym; -use rustc_span::ErrorGuaranteed; - -use crate::errors; - -pub fn test_variance(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { - let mut res = Ok(()); - if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { - for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { - let variances_of = tcx.variances_of(id.owner_id); - - res = Err(tcx.dcx().emit_err(errors::VariancesOf { - span: tcx.def_span(id.owner_id), - variances_of: format!("{variances_of:?}"), - })); - } - } - } - - // For unit testing: check for a special "rustc_variance" - // attribute and report an error with various results if found. - for id in tcx.hir().items() { - if tcx.has_attr(id.owner_id, sym::rustc_variance) { - let variances_of = tcx.variances_of(id.owner_id); - - res = Err(tcx.dcx().emit_err(errors::VariancesOf { - span: tcx.def_span(id.owner_id), - variances_of: format!("{variances_of:?}"), - })); - } - } - res -} diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs index 2bb7caea3c4..5db71591e66 100644 --- a/compiler/rustc_hir_typeck/src/autoderef.rs +++ b/compiler/rustc_hir_typeck/src/autoderef.rs @@ -1,4 +1,5 @@ -//! Some helper functions for `AutoDeref` +//! Some helper functions for `AutoDeref`. + use super::method::MethodCallee; use super::{FnCtxt, PlaceOp}; diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 24f039b8e90..98add86252c 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -1,4 +1,5 @@ //! Errors emitted by `rustc_hir_typeck`. + use std::borrow::Cow; use crate::fluent_generated as fluent; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index 23f4d3c36a3..fab7eb7495c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -1,4 +1,5 @@ //! A utility module to inspect currently ambiguous obligations in the current context. + use crate::FnCtxt; use rustc_infer::traits::{self, ObligationCause}; use rustc_middle::traits::solve::Goal; diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index b67d29fce92..aea0114167e 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -793,7 +793,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { } fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed { - if let Some(guar) = self.fcx.dcx().has_errors() { + if let Some(guar) = self.fcx.tainted_by_errors() { guar } else { self.fcx @@ -847,7 +847,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { } impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.fcx.tcx } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index bc2592b43f3..1659f3d0493 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -304,7 +304,7 @@ struct Canonicalizer<'cx, 'tcx> { } impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -773,7 +773,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { ) -> ty::Region<'tcx> { let var = self.canonical_var(info, r.into()); let br = ty::BoundRegion { var, kind: ty::BrAnon }; - ty::Region::new_bound(self.interner(), self.binder_index, br) + ty::Region::new_bound(self.cx(), self.binder_index, br) } /// Given a type variable `ty_var` of the given kind, first check diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index cb0e13652e8..d7349abc44c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -158,7 +158,7 @@ struct ClosureEraser<'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 29da12e7d15..85624c9ca73 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -1,5 +1,6 @@ //! Error Reporting for Anonymous Region Lifetime Errors //! where one region is named and the other is anonymous. + use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::{ errors::ExplicitLifetimeRequired, diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 4bb59bd9037..de4267f7cea 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -30,6 +30,7 @@ //! solving a set of constraints. In contrast, the type inferencer assigns a value to each type //! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type //! inferencer knows "so far". + use super::InferCtxt; use rustc_data_structures::fx::FxHashMap; use rustc_middle::bug; @@ -100,7 +101,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { } impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -117,7 +118,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { | ty::RePlaceholder(..) | ty::ReStatic | ty::ReError(_) - | ty::ReErased => self.interner().lifetimes.re_erased, + | ty::ReErased => self.cx().lifetimes.re_erased, } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 4d6ddd7ba66..a3cf588da1c 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1719,7 +1719,7 @@ struct InferenceLiteralEraser<'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceLiteralEraser<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -1859,7 +1859,7 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceParamAndInferWithPlaceholder<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index a4f9316b502..48d006e7fbc 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -1,4 +1,5 @@ //! Various code related to computing outlives relations. + use self::env::OutlivesEnvironment; use super::region_constraints::RegionConstraintData; use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 830d79f52b9..ed75fd183f2 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -24,7 +24,7 @@ impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> { } impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticVarResolver<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -66,7 +66,7 @@ impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> { } impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticRegionResolver<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -85,7 +85,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticRegionResolver<'a, 'tcx .inner .borrow_mut() .unwrap_region_constraints() - .opportunistic_resolve_var(TypeFolder::interner(self), vid), + .opportunistic_resolve_var(TypeFolder::cx(self), vid), _ => r, } } @@ -121,7 +121,7 @@ struct FullTypeResolver<'a, 'tcx> { impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> { type Error = FixupError; - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index a086c82c92e..f15bd0babee 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -183,7 +183,7 @@ pub struct InferenceFudger<'a, 'tcx> { } impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 2909f8adfb0..6ffc518097e 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -20,9 +20,9 @@ use rustc_span::source_map::{RealFileLoader, SourceMapInputs}; use rustc_span::symbol::sym; use rustc_span::{FileName, SourceFileHashAlgorithm}; use rustc_target::spec::{ - CodeModel, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, WasmCAbi, + CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, + RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, WasmCAbi, }; -use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel}; use std::collections::{BTreeMap, BTreeSet}; use std::num::NonZero; use std::path::{Path, PathBuf}; @@ -605,7 +605,7 @@ fn test_codegen_options_tracking_hash() { tracked!(debug_assertions, Some(true)); tracked!(debuginfo, DebugInfo::Limited); tracked!(embed_bitcode, false); - tracked!(force_frame_pointers, Some(false)); + tracked!(force_frame_pointers, FramePointer::Always); tracked!(force_unwind_tables, Some(true)); tracked!(inline_threshold, Some(0xf007ba11)); tracked!(instrument_coverage, InstrumentCoverage::Yes); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 007709e32d8..fdedf2c2e6d 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -75,7 +75,7 @@ lint_builtin_deprecated_attr_default_suggestion = remove this attribute lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link} .msg_suggestion = {$msg} .default_suggestion = remove this attribute -lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used. +lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used lint_builtin_deref_nullptr = dereferencing a null pointer .label = this code causes undefined behavior when executed @@ -213,7 +213,7 @@ lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better pe lint_default_source = `forbid` lint level is the default for {$id} lint_deprecated_lint_name = - lint name `{$name}` is deprecated and may not have an effect in the future. + lint name `{$name}` is deprecated and may not have an effect in the future .suggestion = change it to .help = change it to {$replace} @@ -244,11 +244,11 @@ lint_duplicate_matcher_binding = duplicate matcher binding lint_enum_intrinsics_mem_discriminant = the return value of `mem::discriminant` is unspecified when called with a non-enum type - .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum. + .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum lint_enum_intrinsics_mem_variant = the return value of `mem::variant_count` is unspecified when called with a non-enum type - .note = the type parameter of `variant_count` should be an enum, but it was instantiated with the type `{$ty_param}`, which is not an enum. + .note = the type parameter of `variant_count` should be an enum, but it was instantiated with the type `{$ty_param}`, which is not an enum lint_expectation = this lint expectation is unfulfilled .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message @@ -550,7 +550,7 @@ lint_non_local_definitions_impl = non-local `impl` definition, `impl` blocks sho .with_trait = an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` .bounds = `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type .doctest = make this doc-test a standalone test with its own `fn main() {"{"} ... {"}"}` - .exception = items in an anonymous const item (`const _: () = {"{"} ... {"}"}`) are treated as in the same scope as the anonymous const's declaration + .exception = items in an anonymous const item (`const _: () = {"{"} ... {"}"}`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint .const_anon = use a const-anon item to suppress this lint .macro_to_change = the {$macro_kind} `{$macro_to_change}` defines the non-local `impl`, and may need to be changed diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 24dd337e699..300dac442d5 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -390,7 +390,7 @@ struct ReplaceLocalTypesWithInfer<'a, 'tcx, F: FnMut(DefId) -> bool> { impl<'a, 'tcx, F: FnMut(DefId) -> bool> TypeFolder<TyCtxt<'tcx>> for ReplaceLocalTypesWithInfer<'a, 'tcx, F> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 70330c44577..b3838f915f6 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -1,4 +1,3 @@ -// tidy-alphabetical-start pub use self::Level::*; use rustc_ast::node_id::NodeId; use rustc_ast::{AttrId, Attribute}; @@ -15,7 +14,6 @@ use rustc_span::edition::Edition; use rustc_span::symbol::MacroRulesNormalizedIdent; use rustc_span::{sym, symbol::Ident, Span, Symbol}; use rustc_target::spec::abi::Abi; -// tidy-alphabetical-end use serde::{Deserialize, Serialize}; diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 932603cd6b2..415399ed06c 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -248,13 +248,13 @@ metadata_rustc_lib_required = .help = try adding `extern crate rustc_driver;` at the top level of this crate metadata_stable_crate_id_collision = - found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values. + found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values metadata_std_required = `std` is required by `{$current_crate}` because it does not declare `#![no_std]` metadata_symbol_conflicts_current = - the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two. + the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments, so this will result in symbol conflicts between the two metadata_target_no_std_support = the `{$locator_triple}` target may not support the standard library diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 3c5bf6eb824..84b47a6ed44 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -194,10 +194,7 @@ impl DepNodeExt for DepNode { /// has been removed. fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> { if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash { - Some(tcx.def_path_hash_to_def_id( - DefPathHash(self.hash.into()), - &("Failed to extract DefId", self.kind, self.hash), - )) + tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into())) } else { None } @@ -390,12 +387,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId { if tcx.fingerprint_style(dep_node.kind) == FingerprintStyle::HirId { let (local_hash, local_id) = Fingerprint::from(dep_node.hash).split(); let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash); - let def_id = tcx - .def_path_hash_to_def_id( - def_path_hash, - &("Failed to extract HirId", dep_node.kind, dep_node.hash), - ) - .expect_local(); + let def_id = tcx.def_path_hash_to_def_id(def_path_hash)?.expect_local(); let local_id = local_id .as_u64() .try_into() diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 46520d69e18..4b47b019fd4 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -1,6 +1,7 @@ //! A pass that checks to make sure private fields and methods aren't used //! outside their scopes. This pass will also generate a set of exported items //! which are available for use externally when compiled as a library. + use crate::ty::{TyCtxt, Visibility}; use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 2fc466c0e7e..cac3bf948a0 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -40,9 +40,16 @@ pub trait AllocBytes: Clone + fmt::Debug + Deref<Target = [u8]> + DerefMut<Targe /// Gives direct access to the raw underlying storage. /// /// Crucially this pointer is compatible with: - /// - other pointers retunred by this method, and + /// - other pointers returned by this method, and /// - references returned from `deref()`, as long as there was no write. fn as_mut_ptr(&mut self) -> *mut u8; + + /// Gives direct access to the raw underlying storage. + /// + /// Crucially this pointer is compatible with: + /// - other pointers returned by this method, and + /// - references returned from `deref()`, as long as there was no write. + fn as_ptr(&self) -> *const u8; } /// Default `bytes` for `Allocation` is a `Box<u8>`. @@ -62,6 +69,11 @@ impl AllocBytes for Box<[u8]> { // Carefully avoiding any intermediate references. ptr::addr_of_mut!(**self).cast() } + + fn as_ptr(&self) -> *const u8 { + // Carefully avoiding any intermediate references. + ptr::addr_of!(**self).cast() + } } /// This type represents an Allocation in the Miri/CTFE core engine. @@ -490,19 +502,27 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> self.provenance.clear(range, cx)?; assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check - // Cruciall, we go via `AllocBytes::as_mut_ptr`, not `AllocBytes::deref_mut`. + // Crucially, we go via `AllocBytes::as_mut_ptr`, not `AllocBytes::deref_mut`. let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize()); let len = range.end().bytes_usize() - range.start.bytes_usize(); Ok(ptr::slice_from_raw_parts_mut(begin_ptr, len)) } /// This gives direct mutable access to the entire buffer, just exposing their internal state - /// without reseting anything. Directly exposes `AllocBytes::as_mut_ptr`. Only works if + /// without resetting anything. Directly exposes `AllocBytes::as_mut_ptr`. Only works if /// `OFFSET_IS_ADDR` is true. pub fn get_bytes_unchecked_raw_mut(&mut self) -> *mut u8 { assert!(Prov::OFFSET_IS_ADDR); self.bytes.as_mut_ptr() } + + /// This gives direct immutable access to the entire buffer, just exposing their internal state + /// without resetting anything. Directly exposes `AllocBytes::as_ptr`. Only works if + /// `OFFSET_IS_ADDR` is true. + pub fn get_bytes_unchecked_raw(&self) -> *const u8 { + assert!(Prov::OFFSET_IS_ADDR); + self.bytes.as_ptr() + } } /// Reading and writing. diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 4d9a931d697..ac3feb71a2b 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -1,4 +1,5 @@ -/// Functionality for statements, operands, places, and things that appear in them. +//! Functionality for statements, operands, places, and things that appear in them. + use super::{interpret::GlobalAlloc, *}; /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 5957a25f0f2..0fc84ea5c62 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1446,10 +1446,12 @@ pub enum UnOp { Not, /// The `-` operator for negation Neg, - /// Get the metadata `M` from a `*const/mut impl Pointee<Metadata = M>`. + /// Gets the metadata `M` from a `*const`/`*mut`/`&`/`&mut` to + /// `impl Pointee<Metadata = M>`. /// /// For example, this will give a `()` from `*const i32`, a `usize` from - /// `*mut [u8]`, or a pointer to a vtable from a `*const dyn Foo`. + /// `&mut [u8]`, or a `ptr::DynMetadata<dyn Foo>` (internally a pointer) + /// from a `*mut dyn Foo`. /// /// Allowed only in [`MirPhase::Runtime`]; earlier it's an intrinsic. PtrMetadata, diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index c8c12e205e1..ed592612358 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -1,4 +1,5 @@ -/// Functionality for terminators and helper types that appear in terminators. +//! Functionality for terminators and helper types that appear in terminators. + use rustc_hir::LangItem; use smallvec::{smallvec, SmallVec}; diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index ccd0c7cb10c..924249bf37d 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -733,10 +733,10 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { // 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. - self.tcx.def_path_hash_to_def_id( - def_path_hash, - &("Failed to convert DefPathHash", def_path_hash), - ) + match self.tcx.def_path_hash_to_def_id(def_path_hash) { + Some(r) => r, + None => panic!("Failed to convert DefPathHash {def_path_hash:?}"), + } } fn decode_attr_id(&mut self) -> rustc_span::AttrId { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 7c8b0ec671a..c97af68c29e 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -1047,6 +1047,12 @@ impl<'tcx> PatRangeBoundary<'tcx> { let b = other.eval_bits(ty, tcx, param_env); match ty.kind() { + ty::Float(ty::FloatTy::F16) => { + use rustc_apfloat::Float; + let a = rustc_apfloat::ieee::Half::from_bits(a); + let b = rustc_apfloat::ieee::Half::from_bits(b); + a.partial_cmp(&b) + } ty::Float(ty::FloatTy::F32) => { use rustc_apfloat::Float; let a = rustc_apfloat::ieee::Single::from_bits(a); @@ -1059,6 +1065,12 @@ impl<'tcx> PatRangeBoundary<'tcx> { let b = rustc_apfloat::ieee::Double::from_bits(b); a.partial_cmp(&b) } + ty::Float(ty::FloatTy::F128) => { + use rustc_apfloat::Float; + let a = rustc_apfloat::ieee::Quad::from_bits(a); + let b = rustc_apfloat::ieee::Quad::from_bits(b); + a.partial_cmp(&b) + } ty::Int(ity) => { let size = rustc_target::abi::Integer::from_int_ty(&tcx, *ity).size(); let a = size.sign_extend(a) as i128; diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 90f80f90767..7bc4c60f102 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -53,7 +53,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> { self, folder: &mut F, ) -> Result<Self, F::Error> { - Ok(FallibleTypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData { + Ok(FallibleTypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData { region_constraints: self.region_constraints.clone().try_fold_with(folder)?, opaque_types: self .opaque_types @@ -68,7 +68,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> { } fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self { - TypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData { + TypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData { region_constraints: self.region_constraints.clone().fold_with(folder), opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(), normalization_nested_goals: self.normalization_nested_goals.clone().fold_with(folder), @@ -94,19 +94,17 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> { self, folder: &mut F, ) -> Result<Self, F::Error> { - Ok(FallibleTypeFolder::interner(folder).mk_predefined_opaques_in_body( - PredefinedOpaquesData { - opaque_types: self - .opaque_types - .iter() - .map(|opaque| opaque.try_fold_with(folder)) - .collect::<Result<_, F::Error>>()?, - }, - )) + Ok(FallibleTypeFolder::cx(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData { + opaque_types: self + .opaque_types + .iter() + .map(|opaque| opaque.try_fold_with(folder)) + .collect::<Result<_, F::Error>>()?, + })) } fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self { - TypeFolder::interner(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData { + TypeFolder::cx(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(), }) } diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index 254e1b54481..3aa01fbef2f 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -1,4 +1,5 @@ //! A subset of a mir body used for const evaluability checking. + use crate::ty::{ self, Const, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, @@ -40,7 +41,7 @@ impl<'tcx> TyCtxt<'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Expander<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 6d64c1d50ae..7848aa21eac 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1677,11 +1677,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation /// session, if it still exists. This is used during incremental compilation to /// turn a deserialized `DefPathHash` into its current `DefId`. - pub fn def_path_hash_to_def_id( - self, - hash: DefPathHash, - err_msg: &dyn std::fmt::Debug, - ) -> DefId { + pub fn def_path_hash_to_def_id(self, hash: DefPathHash) -> Option<DefId> { debug!("def_path_hash_to_def_id({:?})", hash); let stable_crate_id = hash.stable_crate_id(); @@ -1689,13 +1685,9 @@ impl<'tcx> TyCtxt<'tcx> { // If this is a DefPathHash from the local crate, we can look up the // DefId in the tcx's `Definitions`. if stable_crate_id == self.stable_crate_id(LOCAL_CRATE) { - self.untracked - .definitions - .read() - .local_def_path_hash_to_def_id(hash, err_msg) - .to_def_id() + Some(self.untracked.definitions.read().local_def_path_hash_to_def_id(hash)?.to_def_id()) } else { - self.def_path_hash_to_def_id_extern(hash, stable_crate_id) + Some(self.def_path_hash_to_def_id_extern(hash, stable_crate_id)) } } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 8c3ee6955f5..4bf22337991 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -579,7 +579,7 @@ pub struct MakeSuggestableFolder<'tcx> { impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> { type Error = (); - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index cd6e7df31f7..9d5481f3df3 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -37,7 +37,7 @@ struct RegionEraserVisitor<'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 9b5b1430c27..81ea8738e72 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -28,7 +28,7 @@ where G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>, { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -99,7 +99,7 @@ impl<'a, 'tcx> RegionFolder<'a, 'tcx> { } impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -176,7 +176,7 @@ impl<'tcx, D> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'tcx, D> where D: BoundVarReplacerDelegate<'tcx>, { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 83d45ca78d9..5ac3168196a 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -591,7 +591,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArgsRef<'tcx> { match self.len() { 1 => { let param0 = self[0].try_fold_with(folder)?; - if param0 == self[0] { Ok(self) } else { Ok(folder.interner().mk_args(&[param0])) } + if param0 == self[0] { Ok(self) } else { Ok(folder.cx().mk_args(&[param0])) } } 2 => { let param0 = self[0].try_fold_with(folder)?; @@ -599,7 +599,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArgsRef<'tcx> { if param0 == self[0] && param1 == self[1] { Ok(self) } else { - Ok(folder.interner().mk_args(&[param0, param1])) + Ok(folder.cx().mk_args(&[param0, param1])) } } 0 => Ok(self), @@ -635,7 +635,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> { if param0 == self[0] && param1 == self[1] { Ok(self) } else { - Ok(folder.interner().mk_type_list(&[param0, param1])) + Ok(folder.cx().mk_type_list(&[param0, param1])) } } _ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_type_list(v)), diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index efaf9c7231b..1ba8820e0e1 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -873,7 +873,7 @@ fn polymorphize<'tcx>( } impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for PolymorphizationFolder<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 3d397b6b37e..f608b02f42c 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1182,37 +1182,6 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) -> // ABIs have such an option. Otherwise the only other thing here is Rust // itself, and those ABIs are determined by the panic strategy configured // for this compilation. - // - // Unfortunately at this time there's also another caveat. Rust [RFC - // 2945][rfc] has been accepted and is in the process of being implemented - // and stabilized. In this interim state we need to deal with historical - // rustc behavior as well as plan for future rustc behavior. - // - // Historically functions declared with `extern "C"` were marked at the - // codegen layer as `nounwind`. This happened regardless of `panic=unwind` - // or not. This is UB for functions in `panic=unwind` mode that then - // actually panic and unwind. Note that this behavior is true for both - // externally declared functions as well as Rust-defined function. - // - // To fix this UB rustc would like to change in the future to catch unwinds - // from function calls that may unwind within a Rust-defined `extern "C"` - // function and forcibly abort the process, thereby respecting the - // `nounwind` attribute emitted for `extern "C"`. This behavior change isn't - // ready to roll out, so determining whether or not the `C` family of ABIs - // unwinds is conditional not only on their definition but also whether the - // `#![feature(c_unwind)]` feature gate is active. - // - // Note that this means that unlike historical compilers rustc now, by - // default, unconditionally thinks that the `C` ABI may unwind. This will - // prevent some optimization opportunities, however, so we try to scope this - // change and only assume that `C` unwinds with `panic=unwind` (as opposed - // to `panic=abort`). - // - // Eventually the check against `c_unwind` here will ideally get removed and - // this'll be a little cleaner as it'll be a straightforward check of the - // ABI. - // - // [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md use SpecAbi::*; match abi { C { unwind } @@ -1224,10 +1193,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) -> | Thiscall { unwind } | Aapcs { unwind } | Win64 { unwind } - | SysV64 { unwind } => { - unwind - || (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind) - } + | SysV64 { unwind } => unwind, PtxKernel | Msp430Interrupt | X86Interrupt diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index fb16cf5bd36..96f00e1d306 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -173,7 +173,7 @@ impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for NormalizeAfterErasingRegionsFolder<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -211,7 +211,7 @@ impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> { impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for TryNormalizeAfterErasingRegionsFolder<'tcx> { type Error = NormalizationError<'tcx>; - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 08b2f9e8920..70a54e96d36 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -95,7 +95,7 @@ impl<'tcx> ReverseMapper<'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -144,7 +144,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { ) .emit(); - ty::Region::new_error(self.interner(), e) + ty::Region::new_error(self.cx(), e) } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 72cb3e13402..19700353f59 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2529,7 +2529,7 @@ struct RegionFolder<'a, 'tcx> { } impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 71e2e3e9f99..a9dca47ab43 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -335,7 +335,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Pattern<'tcx> { folder: &mut F, ) -> Result<Self, F::Error> { let pat = (*self).clone().try_fold_with(folder)?; - Ok(if pat == *self { self } else { folder.interner().mk_pat(pat) }) + Ok(if pat == *self { self } else { folder.cx().mk_pat(pat) }) } } @@ -407,7 +407,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> { | ty::Foreign(..) => return Ok(self), }; - Ok(if *self.kind() == kind { self } else { folder.interner().mk_ty_from_kind(kind) }) + Ok(if *self.kind() == kind { self } else { folder.cx().mk_ty_from_kind(kind) }) } } @@ -512,7 +512,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Predicate<'tcx> { folder: &mut F, ) -> Result<Self, F::Error> { let new = self.kind().try_fold_with(folder)?; - Ok(folder.interner().reuse_or_mk_predicate(self, new)) + Ok(folder.cx().reuse_or_mk_predicate(self, new)) } } @@ -577,7 +577,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> { ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?), ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?), }; - if kind != self.kind() { Ok(folder.interner().mk_ct_from_kind(kind)) } else { Ok(self) } + if kind != self.kind() { Ok(folder.cx().mk_ct_from_kind(kind)) } else { Ok(self) } } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index b079ed521d3..9307e380681 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1083,7 +1083,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -1130,7 +1130,7 @@ struct WeakAliasTypeExpander<'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for WeakAliasTypeExpander<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -1196,7 +1196,7 @@ impl<'tcx> Ty<'tcx> { /// Returns the minimum and maximum values for the given numeric type (including `char`s) or /// returns `None` if the type is not numeric. pub fn numeric_min_and_max_as_bits(self, tcx: TyCtxt<'tcx>) -> Option<(u128, u128)> { - use rustc_apfloat::ieee::{Double, Single}; + use rustc_apfloat::ieee::{Double, Half, Quad, Single}; Some(match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = self.int_size_and_signed(tcx); @@ -1206,12 +1206,14 @@ impl<'tcx> Ty<'tcx> { (min, max) } ty::Char => (0, std::char::MAX as u128), + ty::Float(ty::FloatTy::F16) => ((-Half::INFINITY).to_bits(), Half::INFINITY.to_bits()), ty::Float(ty::FloatTy::F32) => { ((-Single::INFINITY).to_bits(), Single::INFINITY.to_bits()) } ty::Float(ty::FloatTy::F64) => { ((-Double::INFINITY).to_bits(), Double::INFINITY.to_bits()) } + ty::Float(ty::FloatTy::F128) => ((-Quad::INFINITY).to_bits(), Quad::INFINITY.to_bits()), _ => return None, }) } @@ -1795,7 +1797,7 @@ where for t in iter { new_list.push(t.try_fold_with(folder)?) } - Ok(intern(folder.interner(), &new_list)) + Ok(intern(folder.cx(), &new_list)) } Some((_, Err(err))) => { return Err(err); diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 1ee8777c274..0c277811fda 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -103,7 +103,7 @@ mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior .label = dereference of raw pointer -mir_build_exceeds_mcdc_condition_limit = Number of conditions in decision ({$num_conditions}) exceeds limit ({$max_conditions}). MC/DC analysis will not count this expression. +mir_build_exceeds_mcdc_condition_limit = number of conditions in decision ({$num_conditions}) exceeds limit ({$max_conditions}), so MC/DC analysis will not count this expression mir_build_extern_static_requires_unsafe = use of extern static is unsafe and requires unsafe block diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index b1a305efa4c..7549481c1b3 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -193,6 +193,10 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { let source = self.parse_operand(args[0])?; Ok(Rvalue::Cast(CastKind::Transmute, source, expr.ty)) }, + @call(mir_cast_ptr_to_ptr, args) => { + let source = self.parse_operand(args[0])?; + Ok(Rvalue::Cast(CastKind::PtrToPtr, source, expr.ty)) + }, @call(mir_checked, args) => { parse_by_kind!(self, args[0], _, "binary op", ExprKind::Binary { op, lhs, rhs } => { diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 192d706bce2..dda6c88008b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -369,10 +369,10 @@ impl<'tcx> ConstToPat<'tcx> { ty::Float(flt) => { let v = cv.unwrap_leaf(); let is_nan = match flt { - ty::FloatTy::F16 => unimplemented!("f16_f128"), + ty::FloatTy::F16 => v.to_f16().is_nan(), ty::FloatTy::F32 => v.to_f32().is_nan(), ty::FloatTy::F64 => v.to_f64().is_nan(), - ty::FloatTy::F128 => unimplemented!("f16_f128"), + ty::FloatTy::F128 => v.to_f128().is_nan(), }; if is_nan { // NaNs are not ever equal to anything so they make no sense as patterns. diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index 2c692c95003..32c0d27f635 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -1,3 +1,4 @@ +use rustc_middle::bug; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; @@ -6,13 +7,16 @@ const INSTR_COST: usize = 5; const CALL_PENALTY: usize = 25; const LANDINGPAD_PENALTY: usize = 50; const RESUME_PENALTY: usize = 45; +const LARGE_SWITCH_PENALTY: usize = 20; +const CONST_SWITCH_BONUS: usize = 10; /// Verify that the callee body is compatible with the caller. #[derive(Clone)] pub(crate) struct CostChecker<'b, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, - cost: usize, + penalty: usize, + bonus: usize, callee_body: &'b Body<'tcx>, instance: Option<ty::Instance<'tcx>>, } @@ -24,11 +28,11 @@ impl<'b, 'tcx> CostChecker<'b, 'tcx> { instance: Option<ty::Instance<'tcx>>, callee_body: &'b Body<'tcx>, ) -> CostChecker<'b, 'tcx> { - CostChecker { tcx, param_env, callee_body, instance, cost: 0 } + CostChecker { tcx, param_env, callee_body, instance, penalty: 0, bonus: 0 } } pub fn cost(&self) -> usize { - self.cost + usize::saturating_sub(self.penalty, self.bonus) } fn instantiate_ty(&self, v: Ty<'tcx>) -> Ty<'tcx> { @@ -41,36 +45,49 @@ impl<'b, 'tcx> CostChecker<'b, 'tcx> { } impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { - fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { - // Don't count StorageLive/StorageDead in the inlining cost. + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + // Most costs are in rvalues and terminators, not in statements. match statement.kind { - StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Deinit(_) - | StatementKind::Nop => {} - _ => self.cost += INSTR_COST, + StatementKind::Intrinsic(ref ndi) => { + self.penalty += match **ndi { + NonDivergingIntrinsic::Assume(..) => INSTR_COST, + NonDivergingIntrinsic::CopyNonOverlapping(..) => CALL_PENALTY, + }; + } + _ => self.super_statement(statement, location), + } + } + + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, _location: Location) { + match rvalue { + Rvalue::NullaryOp(NullOp::UbChecks, ..) if !self.tcx.sess.ub_checks() => { + // If this is in optimized MIR it's because it's used later, + // so if we don't need UB checks this session, give a bonus + // here to offset the cost of the call later. + self.bonus += CALL_PENALTY; + } + // These are essentially constants that didn't end up in an Operand, + // so treat them as also being free. + Rvalue::NullaryOp(..) => {} + _ => self.penalty += INSTR_COST, } } fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _: Location) { - let tcx = self.tcx; - match terminator.kind { - TerminatorKind::Drop { ref place, unwind, .. } => { + match &terminator.kind { + TerminatorKind::Drop { place, unwind, .. } => { // If the place doesn't actually need dropping, treat it like a regular goto. - let ty = self.instantiate_ty(place.ty(self.callee_body, tcx).ty); - if ty.needs_drop(tcx, self.param_env) { - self.cost += CALL_PENALTY; + let ty = self.instantiate_ty(place.ty(self.callee_body, self.tcx).ty); + if ty.needs_drop(self.tcx, self.param_env) { + self.penalty += CALL_PENALTY; if let UnwindAction::Cleanup(_) = unwind { - self.cost += LANDINGPAD_PENALTY; + self.penalty += LANDINGPAD_PENALTY; } - } else { - self.cost += INSTR_COST; } } - TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => { - let fn_ty = self.instantiate_ty(f.const_.ty()); - self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() - && tcx.intrinsic(def_id).is_some() + TerminatorKind::Call { func, unwind, .. } => { + self.penalty += if let Some((def_id, ..)) = func.const_fn_def() + && self.tcx.intrinsic(def_id).is_some() { // Don't give intrinsics the extra penalty for calls INSTR_COST @@ -78,23 +95,50 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { CALL_PENALTY }; if let UnwindAction::Cleanup(_) = unwind { - self.cost += LANDINGPAD_PENALTY; + self.penalty += LANDINGPAD_PENALTY; + } + } + TerminatorKind::SwitchInt { discr, targets } => { + if discr.constant().is_some() { + // Not only will this become a `Goto`, but likely other + // things will be removable as unreachable. + self.bonus += CONST_SWITCH_BONUS; + } else if targets.all_targets().len() > 3 { + // More than false/true/unreachable gets extra cost. + self.penalty += LARGE_SWITCH_PENALTY; + } else { + self.penalty += INSTR_COST; } } - TerminatorKind::Assert { unwind, .. } => { - self.cost += CALL_PENALTY; + TerminatorKind::Assert { unwind, msg, .. } => { + self.penalty += + if msg.is_optional_overflow_check() && !self.tcx.sess.overflow_checks() { + INSTR_COST + } else { + CALL_PENALTY + }; if let UnwindAction::Cleanup(_) = unwind { - self.cost += LANDINGPAD_PENALTY; + self.penalty += LANDINGPAD_PENALTY; } } - TerminatorKind::UnwindResume => self.cost += RESUME_PENALTY, + TerminatorKind::UnwindResume => self.penalty += RESUME_PENALTY, TerminatorKind::InlineAsm { unwind, .. } => { - self.cost += INSTR_COST; + self.penalty += INSTR_COST; if let UnwindAction::Cleanup(_) = unwind { - self.cost += LANDINGPAD_PENALTY; + self.penalty += LANDINGPAD_PENALTY; } } - _ => self.cost += INSTR_COST, + TerminatorKind::Unreachable => { + self.bonus += INSTR_COST; + } + TerminatorKind::Goto { .. } | TerminatorKind::Return => {} + TerminatorKind::UnwindTerminate(..) => {} + kind @ (TerminatorKind::FalseUnwind { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::CoroutineDrop) => { + bug!("{kind:?} should not be in runtime MIR"); + } } } } diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs index dcc960e1e02..a0dddec185c 100644 --- a/compiler/rustc_mir_transform/src/ctfe_limit.rs +++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs @@ -1,5 +1,6 @@ //! A pass that inserts the `ConstEvalCounter` instruction into any blocks that have a back edge //! (thus indicating there is a loop in the CFG), or whose terminator is a function call. + use crate::MirPass; use rustc_data_structures::graph::dominators::Dominators; diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index 5e3cd853675..0cb304da80a 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -11,38 +11,6 @@ use rustc_target::spec::PanicStrategy; use crate::errors; -/// Some of the functions declared as "may unwind" by `fn_can_unwind` can't actually unwind. In -/// particular, `extern "C"` is still considered as can-unwind on stable, but we need to consider -/// it cannot-unwind here. So below we check `fn_can_unwind() && abi_can_unwind()` before concluding -/// that a function call can unwind. -fn abi_can_unwind(abi: Abi) -> bool { - use Abi::*; - match abi { - C { unwind } - | System { unwind } - | Cdecl { unwind } - | Stdcall { unwind } - | Fastcall { unwind } - | Vectorcall { unwind } - | Thiscall { unwind } - | Aapcs { unwind } - | Win64 { unwind } - | SysV64 { unwind } => unwind, - PtxKernel - | Msp430Interrupt - | X86Interrupt - | EfiApi - | AvrInterrupt - | AvrNonBlockingInterrupt - | RiscvInterruptM - | RiscvInterruptS - | CCmseNonSecureCall - | Wasm - | Unadjusted => false, - RustIntrinsic | Rust | RustCall | RustCold => unreachable!(), // these ABIs are already skipped earlier - } -} - // Check if the body of this def_id can possibly leak a foreign unwind into Rust code. fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { debug!("has_ffi_unwind_calls({local_def_id:?})"); @@ -103,7 +71,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { _ => bug!("invalid callee of type {:?}", ty), }; - if layout::fn_can_unwind(tcx, fn_def_id, sig.abi()) && abi_can_unwind(sig.abi()) { + if layout::fn_can_unwind(tcx, fn_def_id, sig.abi()) { // We have detected a call that can possibly leak foreign unwind. // // Because the function body itself can unwind, we are not aborting this function call diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index b2670040b14..bfdefd5a7d6 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -836,12 +836,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } Value::BinaryOp(op, lhs, rhs) } - Rvalue::UnaryOp(op, ref mut arg) => { - let arg = self.simplify_operand(arg, location)?; - if let Some(value) = self.simplify_unary(op, arg) { - return Some(value); - } - Value::UnaryOp(op, arg) + Rvalue::UnaryOp(op, ref mut arg_op) => { + return self.simplify_unary(op, arg_op, location); } Rvalue::Discriminant(ref mut place) => { let place = self.simplify_place_value(place, location)?; @@ -949,13 +945,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { was_updated = true; } - if was_updated { - if let Some(const_) = self.try_as_constant(fields[0]) { - field_ops[FieldIdx::ZERO] = Operand::Constant(Box::new(const_)); - } else if let Some(local) = self.try_as_local(fields[0], location) { - field_ops[FieldIdx::ZERO] = Operand::Copy(Place::from(local)); - self.reused_locals.insert(local); - } + if was_updated && let Some(op) = self.try_as_operand(fields[0], location) { + field_ops[FieldIdx::ZERO] = op; } } @@ -965,11 +956,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let first = fields[0]; if fields.iter().all(|&v| v == first) { let len = ty::Const::from_target_usize(self.tcx, fields.len().try_into().unwrap()); - if let Some(const_) = self.try_as_constant(first) { - *rvalue = Rvalue::Repeat(Operand::Constant(Box::new(const_)), len); - } else if let Some(local) = self.try_as_local(first, location) { - *rvalue = Rvalue::Repeat(Operand::Copy(local.into()), len); - self.reused_locals.insert(local); + if let Some(op) = self.try_as_operand(first, location) { + *rvalue = Rvalue::Repeat(op, len); } return Some(self.insert(Value::Repeat(first, len))); } @@ -979,8 +967,71 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } #[instrument(level = "trace", skip(self), ret)] - fn simplify_unary(&mut self, op: UnOp, value: VnIndex) -> Option<VnIndex> { - let value = match (op, self.get(value)) { + fn simplify_unary( + &mut self, + op: UnOp, + arg_op: &mut Operand<'tcx>, + location: Location, + ) -> Option<VnIndex> { + let mut arg_index = self.simplify_operand(arg_op, location)?; + + // PtrMetadata doesn't care about *const vs *mut vs & vs &mut, + // so start by removing those distinctions so we can update the `Operand` + if op == UnOp::PtrMetadata { + let mut was_updated = false; + loop { + match self.get(arg_index) { + // Pointer casts that preserve metadata, such as + // `*const [i32]` <-> `*mut [i32]` <-> `*mut [f32]`. + // It's critical that this not eliminate cases like + // `*const [T]` -> `*const T` which remove metadata. + // We run on potentially-generic MIR, though, so unlike codegen + // we can't always know exactly what the metadata are. + // Thankfully, equality on `ptr_metadata_ty_or_tail` gives us + // what we need: `Ok(meta_ty)` if the metadata is known, or + // `Err(tail_ty)` if not. Matching metadata is ok, but if + // that's not known, then matching tail types is also ok, + // allowing things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`. + // FIXME: Would it be worth trying to normalize, rather than + // passing the identity closure? Or are the types in the + // Cast realistically about as normalized as we can get anyway? + Value::Cast { kind: CastKind::PtrToPtr, value: inner, from, to } + if from + .builtin_deref(true) + .unwrap() + .ptr_metadata_ty_or_tail(self.tcx, |t| t) + == to + .builtin_deref(true) + .unwrap() + .ptr_metadata_ty_or_tail(self.tcx, |t| t) => + { + arg_index = *inner; + was_updated = true; + continue; + } + + // `&mut *p`, `&raw *p`, etc don't change metadata. + Value::Address { place, kind: _, provenance: _ } + if let PlaceRef { local, projection: [PlaceElem::Deref] } = + place.as_ref() + && let Some(local_index) = self.locals[local] => + { + arg_index = local_index; + was_updated = true; + continue; + } + + _ => { + if was_updated && let Some(op) = self.try_as_operand(arg_index, location) { + *arg_op = op; + } + break; + } + } + } + } + + let value = match (op, self.get(arg_index)) { (UnOp::Not, Value::UnaryOp(UnOp::Not, inner)) => return Some(*inner), (UnOp::Neg, Value::UnaryOp(UnOp::Neg, inner)) => return Some(*inner), (UnOp::Not, Value::BinaryOp(BinOp::Eq, lhs, rhs)) => { @@ -992,9 +1043,26 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { (UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => { return Some(fields[1]); } - _ => return None, + // We have an unsizing cast, which assigns the length to fat pointer metadata. + ( + UnOp::PtrMetadata, + Value::Cast { + kind: CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize), + from, + to, + .. + }, + ) if let ty::Slice(..) = to.builtin_deref(true).unwrap().kind() + && let ty::Array(_, len) = from.builtin_deref(true).unwrap().kind() => + { + return self.insert_constant(Const::from_ty_const( + *len, + self.tcx.types.usize, + self.tcx, + )); + } + _ => Value::UnaryOp(op, arg_index), }; - Some(self.insert(value)) } @@ -1174,13 +1242,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } - if was_updated { - if let Some(const_) = self.try_as_constant(value) { - *operand = Operand::Constant(Box::new(const_)); - } else if let Some(local) = self.try_as_local(value, location) { - *operand = Operand::Copy(local.into()); - self.reused_locals.insert(local); - } + if was_updated && let Some(op) = self.try_as_operand(value, location) { + *operand = op; } Some(self.insert(Value::Cast { kind: *kind, value, from, to })) @@ -1296,6 +1359,19 @@ fn op_to_prop_const<'tcx>( } impl<'tcx> VnState<'_, 'tcx> { + /// If either [`Self::try_as_constant`] as [`Self::try_as_local`] succeeds, + /// returns that result as an [`Operand`]. + fn try_as_operand(&mut self, index: VnIndex, location: Location) -> Option<Operand<'tcx>> { + if let Some(const_) = self.try_as_constant(index) { + Some(Operand::Constant(Box::new(const_))) + } else if let Some(local) = self.try_as_local(index, location) { + self.reused_locals.insert(local); + Some(Operand::Copy(local.into())) + } else { + None + } + } + /// If `index` is a `Value::Constant`, return the `Constant` to be put in the MIR. fn try_as_constant(&mut self, index: VnIndex) -> Option<ConstOperand<'tcx>> { // This was already constant in MIR, do not change it. diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index d04bb8d302e..32b5d812025 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1,4 +1,5 @@ -//! Inlining pass for MIR functions +//! Inlining pass for MIR functions. + use crate::deref_separator::deref_finder; use rustc_attr::InlineAttr; use rustc_hir::def::DefKind; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 87dd9cc11eb..fe195f0112f 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -88,7 +88,6 @@ mod lower_slice_len; mod match_branches; mod mentioned_items; mod multiple_return_terminators; -mod normalize_array_len; mod nrvo; mod prettify; mod promote_consts; @@ -581,9 +580,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &o1(simplify::SimplifyCfg::AfterUnreachableEnumBranching), // Inlining may have introduced a lot of redundant code and a large move pattern. // Now, we need to shrink the generated MIR. - - // Has to run after `slice::len` lowering - &normalize_array_len::NormalizeArrayLen, &ref_prop::ReferencePropagation, &sroa::ScalarReplacementOfAggregates, &match_branches::MatchBranchSimplification, diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs index 5b269185e87..3d1e1e48175 100644 --- a/compiler/rustc_mir_transform/src/lint.rs +++ b/compiler/rustc_mir_transform/src/lint.rs @@ -1,6 +1,7 @@ //! This pass statically detects code which has undefined behaviour or is likely to be erroneous. //! It can be used to locate problems in MIR building or optimizations. It assumes that all code //! can be executed, so it has false positives. + use rustc_data_structures::fx::FxHashSet; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{PlaceContext, Visitor}; diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 2267a621a83..77a7f4f47dd 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -1,10 +1,9 @@ -//! This pass lowers calls to core::slice::len to just Len op. +//! This pass lowers calls to core::slice::len to just PtrMetadata op. //! It should run before inlining! use rustc_hir::def_id::DefId; -use rustc_index::IndexSlice; use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::TyCtxt; pub struct LowerSliceLenCalls; @@ -29,16 +28,11 @@ pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); for block in basic_blocks { // lower `<[_]>::len` calls - lower_slice_len_call(tcx, block, &body.local_decls, slice_len_fn_item_def_id); + lower_slice_len_call(block, slice_len_fn_item_def_id); } } -fn lower_slice_len_call<'tcx>( - tcx: TyCtxt<'tcx>, - block: &mut BasicBlockData<'tcx>, - local_decls: &IndexSlice<Local, LocalDecl<'tcx>>, - slice_len_fn_item_def_id: DefId, -) { +fn lower_slice_len_call<'tcx>(block: &mut BasicBlockData<'tcx>, slice_len_fn_item_def_id: DefId) { let terminator = block.terminator(); if let TerminatorKind::Call { func, @@ -50,19 +44,17 @@ fn lower_slice_len_call<'tcx>( } = &terminator.kind // some heuristics for fast rejection && let [arg] = &args[..] - && let Some(arg) = arg.node.place() - && let ty::FnDef(fn_def_id, _) = func.ty(local_decls, tcx).kind() - && *fn_def_id == slice_len_fn_item_def_id + && let Some((fn_def_id, _)) = func.const_fn_def() + && fn_def_id == slice_len_fn_item_def_id { // perform modifications from something like: // _5 = core::slice::<impl [u8]>::len(move _6) -> bb1 // into: - // _5 = Len(*_6) + // _5 = PtrMetadata(move _6) // goto bb1 // make new RValue for Len - let deref_arg = tcx.mk_place_deref(arg); - let r_value = Rvalue::Len(deref_arg); + let r_value = Rvalue::UnaryOp(UnOp::PtrMetadata, arg.node.clone()); let len_statement_kind = StatementKind::Assign(Box::new((*destination, r_value))); let add_statement = Statement { kind: len_statement_kind, source_info: terminator.source_info }; diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs deleted file mode 100644 index d5e72706661..00000000000 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! This pass eliminates casting of arrays into slices when their length -//! is taken using `.len()` method. Handy to preserve information in MIR for const prop - -use crate::ssa::SsaLocals; -use rustc_index::IndexVec; -use rustc_middle::mir::visit::*; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt}; - -pub struct NormalizeArrayLen; - -impl<'tcx> MirPass<'tcx> for NormalizeArrayLen { - fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 3 - } - - #[instrument(level = "trace", skip(self, tcx, body))] - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - debug!(def_id = ?body.source.def_id()); - normalize_array_len_calls(tcx, body) - } -} - -fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - let ssa = SsaLocals::new(tcx, body, param_env); - - let slice_lengths = compute_slice_length(tcx, &ssa, body); - debug!(?slice_lengths); - - Replacer { tcx, slice_lengths }.visit_body_preserves_cfg(body); -} - -fn compute_slice_length<'tcx>( - tcx: TyCtxt<'tcx>, - ssa: &SsaLocals, - body: &Body<'tcx>, -) -> IndexVec<Local, Option<ty::Const<'tcx>>> { - let mut slice_lengths = IndexVec::from_elem(None, &body.local_decls); - - for (local, rvalue, _) in ssa.assignments(body) { - match rvalue { - Rvalue::Cast( - CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize), - operand, - cast_ty, - ) => { - let operand_ty = operand.ty(body, tcx); - debug!(?operand_ty); - if let Some(operand_ty) = operand_ty.builtin_deref(true) - && let ty::Array(_, len) = operand_ty.kind() - && let Some(cast_ty) = cast_ty.builtin_deref(true) - && let ty::Slice(..) = cast_ty.kind() - { - slice_lengths[local] = Some(*len); - } - } - // The length information is stored in the fat pointer, so we treat `operand` as a value. - Rvalue::Use(operand) => { - if let Some(rhs) = operand.place() - && let Some(rhs) = rhs.as_local() - { - slice_lengths[local] = slice_lengths[rhs]; - } - } - // The length information is stored in the fat pointer. - // Reborrowing copies length information from one pointer to the other. - Rvalue::Ref(_, _, rhs) | Rvalue::AddressOf(_, rhs) => { - if let [PlaceElem::Deref] = rhs.projection[..] { - slice_lengths[local] = slice_lengths[rhs.local]; - } - } - _ => {} - } - } - - slice_lengths -} - -struct Replacer<'tcx> { - tcx: TyCtxt<'tcx>, - slice_lengths: IndexVec<Local, Option<ty::Const<'tcx>>>, -} - -impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, loc: Location) { - if let Rvalue::Len(place) = rvalue - && let [PlaceElem::Deref] = &place.projection[..] - && let Some(len) = self.slice_lengths[place.local] - { - *rvalue = Rvalue::Use(Operand::Constant(Box::new(ConstOperand { - span: rustc_span::DUMMY_SP, - user_ty: None, - const_: Const::from_ty_const(len, self.tcx.types.usize, self.tcx), - }))); - } - self.super_rvalue(rvalue, loc); - } -} diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index ecdca8292b4..3f4d2b65ff2 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -60,7 +60,7 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { let ccx = ConstCx::new(tcx, body); let (mut temps, all_candidates) = collect_temps_and_candidates(&ccx); - let promotable_candidates = validate_candidates(&ccx, &mut temps, &all_candidates); + let promotable_candidates = validate_candidates(&ccx, &mut temps, all_candidates); let promoted = promote_candidates(body, tcx, temps, promotable_candidates); self.promoted_fragments.set(promoted); @@ -98,8 +98,8 @@ struct Collector<'a, 'tcx> { } impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { + #[instrument(level = "debug", skip(self))] fn visit_local(&mut self, index: Local, context: PlaceContext, location: Location) { - debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location); // We're only interested in temporaries and the return place match self.ccx.body.local_kind(index) { LocalKind::Arg => return, @@ -111,20 +111,15 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { // then it's constant and thus drop is noop. // Non-uses are also irrelevant. if context.is_drop() || !context.is_use() { - debug!( - "visit_local: context.is_drop={:?} context.is_use={:?}", - context.is_drop(), - context.is_use(), - ); + debug!(is_drop = context.is_drop(), is_use = context.is_use()); return; } let temp = &mut self.temps[index]; - debug!("visit_local: temp={:?}", temp); + debug!(?temp); *temp = match *temp { TempState::Undefined => match context { - PlaceContext::MutatingUse(MutatingUseContext::Store) - | PlaceContext::MutatingUse(MutatingUseContext::Call) => { + PlaceContext::MutatingUse(MutatingUseContext::Store | MutatingUseContext::Call) => { TempState::Defined { location, uses: 0, valid: Err(()) } } _ => TempState::Unpromotable, @@ -137,7 +132,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { | PlaceContext::NonMutatingUse(_) => true, PlaceContext::MutatingUse(_) | PlaceContext::NonUse(_) => false, }; - debug!("visit_local: allowed_use={:?}", allowed_use); + debug!(?allowed_use); if allowed_use { *uses += 1; return; @@ -146,6 +141,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { } TempState::Unpromotable | TempState::PromotedOut => TempState::Unpromotable, }; + debug!(?temp); } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { @@ -695,15 +691,12 @@ impl<'tcx> Validator<'_, 'tcx> { fn validate_candidates( ccx: &ConstCx<'_, '_>, temps: &mut IndexSlice<Local, TempState>, - candidates: &[Candidate], + mut candidates: Vec<Candidate>, ) -> Vec<Candidate> { let mut validator = Validator { ccx, temps, promotion_safe_blocks: None }; + candidates.retain(|&candidate| validator.validate_candidate(candidate).is_ok()); candidates - .iter() - .copied() - .filter(|&candidate| validator.validate_candidate(candidate).is_ok()) - .collect() } struct Promoter<'a, 'tcx> { @@ -972,7 +965,12 @@ fn promote_candidates<'tcx>( candidates: Vec<Candidate>, ) -> IndexVec<Promoted, Body<'tcx>> { // Visit candidates in reverse, in case they're nested. - debug!("promote_candidates({:?})", candidates); + debug!(promote_candidates = ?candidates); + + // eagerly fail fast + if candidates.is_empty() { + return IndexVec::new(); + } let mut promotions = IndexVec::new(); diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index f5d10521fdd..2018a8fe667 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1116,12 +1116,17 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { UnOp::PtrMetadata => { if !matches!(self.mir_phase, MirPhase::Runtime(_)) { // It would probably be fine to support this in earlier phases, - // but at the time of writing it's only ever introduced from intrinsic lowering, + // but at the time of writing it's only ever introduced from intrinsic lowering + // or other runtime-phase optimization passes, // so earlier things can just `bug!` on it. self.fail(location, "PtrMetadata should be in runtime MIR only"); } - check_kinds!(a, "Cannot PtrMetadata non-pointer type {:?}", ty::RawPtr(..)); + check_kinds!( + a, + "Cannot PtrMetadata non-pointer non-reference type {:?}", + ty::RawPtr(..) | ty::Ref(..) + ); } } } diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 3a5f438b432..07cd4ae68d9 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" # tidy-alphabetical-start bitflags = "2.4.1" derivative = "2.2.0" -rustc_ast_ir = { path = "../rustc_ast_ir" } +rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index a81fd03d034..695d02705ab 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -7,7 +7,7 @@ use rustc_type_ir::{ self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Interner, }; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; /// Whether we're canonicalizing a query input or the query response. /// @@ -38,8 +38,8 @@ pub enum CanonicalizeMode { }, } -pub struct Canonicalizer<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> { - infcx: &'a Infcx, +pub struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner> { + delegate: &'a D, canonicalize_mode: CanonicalizeMode, variables: &'a mut Vec<I::GenericArg>, @@ -47,15 +47,15 @@ pub struct Canonicalizer<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> { binder_index: ty::DebruijnIndex, } -impl<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, Infcx, I> { +impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { pub fn canonicalize<T: TypeFoldable<I>>( - infcx: &'a Infcx, + delegate: &'a D, canonicalize_mode: CanonicalizeMode, variables: &'a mut Vec<I::GenericArg>, value: T, ) -> ty::Canonical<I, T> { let mut canonicalizer = Canonicalizer { - infcx, + delegate, canonicalize_mode, variables, @@ -70,7 +70,7 @@ impl<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, Inf let (max_universe, variables) = canonicalizer.finalize(); - let defining_opaque_types = infcx.defining_opaque_types(); + let defining_opaque_types = delegate.defining_opaque_types(); Canonical { defining_opaque_types, max_universe, variables, value } } @@ -102,7 +102,7 @@ impl<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, Inf .max() .unwrap_or(ty::UniverseIndex::ROOT); - let var_infos = self.infcx.interner().mk_canonical_var_infos(&var_infos); + let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos); return (max_universe, var_infos); } } @@ -206,16 +206,14 @@ impl<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, Inf } } - let var_infos = self.infcx.interner().mk_canonical_var_infos(&var_infos); + let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos); (curr_compressed_uv, var_infos) } } -impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> - for Canonicalizer<'_, Infcx, I> -{ - fn interner(&self) -> I { - self.infcx.interner() +impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicalizer<'_, D, I> { + fn cx(&self) -> I { + self.delegate.cx() } fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> @@ -267,14 +265,14 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> ty::ReVar(vid) => { assert_eq!( - self.infcx.opportunistic_resolve_lt_var(vid), + self.delegate.opportunistic_resolve_lt_var(vid), r, "region vid should have been resolved fully before canonicalization" ); match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { .. } => { - CanonicalVarKind::Region(self.infcx.universe_of_lt(vid).unwrap()) + CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap()) } } } @@ -294,7 +292,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> var }); - Region::new_anon_bound(self.interner(), self.binder_index, var) + Region::new_anon_bound(self.cx(), self.binder_index, var) } fn fold_ty(&mut self, t: I::Ty) -> I::Ty { @@ -302,20 +300,20 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> ty::Infer(i) => match i { ty::TyVar(vid) => { assert_eq!( - self.infcx.opportunistic_resolve_ty_var(vid), + self.delegate.opportunistic_resolve_ty_var(vid), t, "ty vid should have been resolved fully before canonicalization" ); CanonicalVarKind::Ty(CanonicalTyVarKind::General( - self.infcx + self.delegate .universe_of_ty(vid) .unwrap_or_else(|| panic!("ty var should have been resolved: {t:?}")), )) } ty::IntVar(vid) => { assert_eq!( - self.infcx.opportunistic_resolve_int_var(vid), + self.delegate.opportunistic_resolve_int_var(vid), t, "ty vid should have been resolved fully before canonicalization" ); @@ -323,7 +321,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> } ty::FloatVar(vid) => { assert_eq!( - self.infcx.opportunistic_resolve_float_var(vid), + self.delegate.opportunistic_resolve_float_var(vid), t, "ty vid should have been resolved fully before canonicalization" ); @@ -383,7 +381,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> }), ); - Ty::new_anon_bound(self.interner(), self.binder_index, var) + Ty::new_anon_bound(self.cx(), self.binder_index, var) } fn fold_const(&mut self, c: I::Const) -> I::Const { @@ -391,11 +389,11 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> ty::ConstKind::Infer(i) => match i { ty::InferConst::Var(vid) => { assert_eq!( - self.infcx.opportunistic_resolve_ct_var(vid), + self.delegate.opportunistic_resolve_ct_var(vid), c, "const vid should have been resolved fully before canonicalization" ); - CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap()) + CanonicalVarKind::Const(self.delegate.universe_of_ct(vid).unwrap()) } ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect, ty::InferConst::Fresh(_) => todo!(), @@ -431,6 +429,6 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> }), ); - Const::new_anon_bound(self.interner(), self.binder_index, var) + Const::new_anon_bound(self.cx(), self.binder_index, var) } } diff --git a/compiler/rustc_next_trait_solver/src/infcx.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index c249eb94cf6..6626acfe963 100644 --- a/compiler/rustc_next_trait_solver/src/infcx.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -7,14 +7,14 @@ use rustc_type_ir::{self as ty, Interner}; pub trait SolverDelegate: Sized { type Interner: Interner; - fn interner(&self) -> Self::Interner; + fn cx(&self) -> Self::Interner; type Span: Copy; fn solver_mode(&self) -> SolverMode; fn build_with_canonical<V>( - interner: Self::Interner, + cx: Self::Interner, solver_mode: SolverMode, canonical: &ty::Canonical<Self::Interner, V>, ) -> (Self, V, ty::CanonicalVarValues<Self::Interner>) @@ -102,7 +102,7 @@ pub trait SolverDelegate: Sized { // FIXME: This is only here because elaboration lives in `rustc_infer`! fn elaborate_supertraits( - interner: Self::Interner, + cx: Self::Interner, trait_ref: ty::Binder<Self::Interner, ty::TraitRef<Self::Interner>>, ) -> impl Iterator<Item = ty::Binder<Self::Interner, ty::TraitRef<Self::Interner>>>; diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index 79c6925221e..a6a9c01faaa 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -4,9 +4,7 @@ //! but were uplifted in the process of making the new trait solver generic. //! So if you got to this crate from the old solver, it's totally normal. -#![feature(let_chains)] - pub mod canonicalizer; -pub mod infcx; +pub mod delegate; pub mod resolve; pub mod solve; diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 3d8d957eaae..6ed58d0e4fb 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -1,4 +1,4 @@ -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; @@ -8,37 +8,37 @@ use rustc_type_ir::{self as ty, Interner}; // EAGER RESOLUTION /// Resolves ty, region, and const vars to their inferred values or their root vars. -pub struct EagerResolver<'a, Infcx, I = <Infcx as SolverDelegate>::Interner> +pub struct EagerResolver<'a, D, I = <D as SolverDelegate>::Interner> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { - infcx: &'a Infcx, + delegate: &'a D, } -impl<'a, Infcx: SolverDelegate> EagerResolver<'a, Infcx> { - pub fn new(infcx: &'a Infcx) -> Self { - EagerResolver { infcx } +impl<'a, D: SolverDelegate> EagerResolver<'a, D> { + pub fn new(delegate: &'a D) -> Self { + EagerResolver { delegate } } } -impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for EagerResolver<'_, Infcx> { - fn interner(&self) -> I { - self.infcx.interner() +impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for EagerResolver<'_, D> { + fn cx(&self) -> I { + self.delegate.cx() } fn fold_ty(&mut self, t: I::Ty) -> I::Ty { match t.kind() { ty::Infer(ty::TyVar(vid)) => { - let resolved = self.infcx.opportunistic_resolve_ty_var(vid); + let resolved = self.delegate.opportunistic_resolve_ty_var(vid); if t != resolved && resolved.has_infer() { resolved.fold_with(self) } else { resolved } } - ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid), - ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid), + ty::Infer(ty::IntVar(vid)) => self.delegate.opportunistic_resolve_int_var(vid), + ty::Infer(ty::FloatVar(vid)) => self.delegate.opportunistic_resolve_float_var(vid), _ => { if t.has_infer() { t.super_fold_with(self) @@ -51,7 +51,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for EagerRe fn fold_region(&mut self, r: I::Region) -> I::Region { match r.kind() { - ty::ReVar(vid) => self.infcx.opportunistic_resolve_lt_var(vid), + ty::ReVar(vid) => self.delegate.opportunistic_resolve_lt_var(vid), _ => r, } } @@ -59,7 +59,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for EagerRe fn fold_const(&mut self, c: I::Const) -> I::Const { match c.kind() { ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { - let resolved = self.infcx.opportunistic_resolve_ct_var(vid); + let resolved = self.delegate.opportunistic_resolve_ct_var(vid); if c != resolved && resolved.has_infer() { resolved.fold_with(self) } else { @@ -67,7 +67,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for EagerRe } } ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => { - self.infcx.opportunistic_resolve_effect_var(vid) + self.delegate.opportunistic_resolve_effect_var(vid) } _ => { if c.has_infer() { diff --git a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs index fbc8ac1d5d5..5a95f4edf19 100644 --- a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs +++ b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs @@ -19,12 +19,12 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::{self as ty, Interner}; use tracing::{instrument, trace}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; -impl<Infcx, I> EvalCtxt<'_, Infcx> +impl<D, I> EvalCtxt<'_, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { #[instrument(level = "trace", skip(self), ret)] @@ -32,7 +32,7 @@ where &mut self, goal: Goal<I, (I::Term, I::Term, ty::AliasRelationDirection)>, ) -> QueryResult<I> { - let tcx = self.interner(); + let tcx = self.cx(); let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some()); diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 9a1537d2606..cae9c5c8567 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -9,7 +9,7 @@ use rustc_type_ir::visit::TypeVisitableExt as _; use rustc_type_ir::{self as ty, Interner, Upcast as _}; use tracing::{debug, instrument}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource, @@ -28,10 +28,10 @@ pub(super) struct Candidate<I: Interner> { } /// Methods used to assemble candidates for either trait or projection goals. -pub(super) trait GoalKind<Infcx, I = <Infcx as SolverDelegate>::Interner>: +pub(super) trait GoalKind<D, I = <D as SolverDelegate>::Interner>: TypeFoldable<I> + Copy + Eq + std::fmt::Display where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { fn self_ty(self) -> I::Ty; @@ -47,18 +47,18 @@ where /// work, then produce a response (typically by executing /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]). fn probe_and_match_goal_against_assumption( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, source: CandidateSource<I>, goal: Goal<I, Self>, assumption: I::Clause, - then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>, + then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, ) -> Result<Candidate<I>, NoSolution>; /// Consider a clause, which consists of a "assumption" and some "requirements", /// to satisfy a goal. If the requirements hold, then attempt to satisfy our /// goal by equating it with the assumption. fn probe_and_consider_implied_clause( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, parent_source: CandidateSource<I>, goal: Goal<I, Self>, assumption: I::Clause, @@ -76,13 +76,13 @@ where /// additionally checking all of the supertraits and object bounds to hold, /// since they're not implied by the well-formedness of the object type. fn probe_and_consider_object_bound_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, source: CandidateSource<I>, goal: Goal<I, Self>, assumption: I::Clause, ) -> Result<Candidate<I>, NoSolution> { Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else { panic!("expected object type in `probe_and_consider_object_bound_candidate`"); }; @@ -100,7 +100,7 @@ where } fn consider_impl_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, impl_def_id: I::DefId, ) -> Result<Candidate<I>, NoSolution>; @@ -112,7 +112,7 @@ where /// Trait goals always hold while projection goals never do. This is a bit arbitrary /// but prevents incorrect normalization while hiding any trait errors. fn consider_error_guaranteed_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, guar: I::ErrorGuaranteed, ) -> Result<Candidate<I>, NoSolution>; @@ -121,13 +121,13 @@ where /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_auto_trait`]. fn consider_auto_trait_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; /// A trait alias holds if the RHS traits and `where` clauses hold. fn consider_trait_alias_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; @@ -136,7 +136,7 @@ where /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`]. fn consider_builtin_sized_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; @@ -145,27 +145,27 @@ where /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_copy_clone_trait`]. fn consider_builtin_copy_clone_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; /// A type is `PointerLike` if we can compute its layout, and that layout /// matches the layout of `usize`. fn consider_builtin_pointer_like_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; /// A type is a `FnPtr` if it is of `FnPtr` type. fn consider_builtin_fn_ptr_trait_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; /// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>` /// family of traits where `A` is given by the signature of the type. fn consider_builtin_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, kind: ty::ClosureKind, ) -> Result<Candidate<I>, NoSolution>; @@ -173,7 +173,7 @@ where /// An async closure is known to implement the `AsyncFn<A>` family of traits /// where `A` is given by the signature of the type. fn consider_builtin_async_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, kind: ty::ClosureKind, ) -> Result<Candidate<I>, NoSolution>; @@ -182,13 +182,13 @@ where /// is used internally to delay computation for async closures until after /// upvar analysis is performed in HIR typeck. fn consider_builtin_async_fn_kind_helper_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; /// `Tuple` is implemented if the `Self` type is a tuple. fn consider_builtin_tuple_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; @@ -198,7 +198,7 @@ where /// the built-in types. For structs, the metadata type is given by the struct /// tail. fn consider_builtin_pointee_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; @@ -206,7 +206,7 @@ where /// `Future<Output = O>`, where `O` is given by the coroutine's return type /// that was computed during type-checking. fn consider_builtin_future_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; @@ -214,19 +214,19 @@ where /// `Iterator<Item = O>`, where `O` is given by the generator's yield type /// that was computed during type-checking. fn consider_builtin_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; /// A coroutine (that comes from a `gen` desugaring) is known to implement /// `FusedIterator` fn consider_builtin_fused_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; fn consider_builtin_async_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; @@ -234,27 +234,27 @@ where /// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield, /// and return types of the coroutine computed during type-checking. fn consider_builtin_coroutine_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; fn consider_builtin_discriminant_kind_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; fn consider_builtin_destruct_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; fn consider_builtin_transmute_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; @@ -266,17 +266,17 @@ where /// otherwise recompute this for codegen. This is a bit of a mess but the /// easiest way to maintain the existing behavior for now. fn consider_structural_builtin_unsize_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Vec<Candidate<I>>; } -impl<Infcx, I> EvalCtxt<'_, Infcx> +impl<D, I> EvalCtxt<'_, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { - pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<Infcx>>( + pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>( &mut self, goal: Goal<I, G>, ) -> Vec<Candidate<I>> { @@ -291,10 +291,8 @@ where return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect(); } - let goal: Goal<I, G> = goal.with( - self.interner(), - goal.predicate.with_self_ty(self.interner(), normalized_self_ty), - ); + let goal: Goal<I, G> = + goal.with(self.cx(), goal.predicate.with_self_ty(self.cx(), normalized_self_ty)); // Vars that show up in the rest of the goal substs may have been constrained by // normalizing the self type as well, since type variables are not uniquified. let goal = self.resolve_vars_if_possible(goal); @@ -337,12 +335,12 @@ where } #[instrument(level = "trace", skip_all)] - fn assemble_impl_candidates<G: GoalKind<Infcx>>( + fn assemble_impl_candidates<G: GoalKind<D>>( &mut self, goal: Goal<I, G>, candidates: &mut Vec<Candidate<I>>, ) { - let tcx = self.interner(); + let tcx = self.cx(); tcx.for_each_relevant_impl( goal.predicate.trait_def_id(tcx), goal.predicate.self_ty(), @@ -363,12 +361,12 @@ where } #[instrument(level = "trace", skip_all)] - fn assemble_builtin_impl_candidates<G: GoalKind<Infcx>>( + fn assemble_builtin_impl_candidates<G: GoalKind<D>>( &mut self, goal: Goal<I, G>, candidates: &mut Vec<Candidate<I>>, ) { - let tcx = self.interner(); + let tcx = self.cx(); let trait_def_id = goal.predicate.trait_def_id(tcx); // N.B. When assembling built-in candidates for lang items that are also @@ -394,9 +392,9 @@ where G::consider_builtin_pointer_like_candidate(self, goal) } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::FnPtrTrait) { G::consider_builtin_fn_ptr_trait_candidate(self, goal) - } else if let Some(kind) = self.interner().fn_trait_kind_from_def_id(trait_def_id) { + } else if let Some(kind) = self.cx().fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_fn_trait_candidates(self, goal, kind) - } else if let Some(kind) = self.interner().async_fn_trait_kind_from_def_id(trait_def_id) { + } else if let Some(kind) = self.cx().async_fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_async_fn_trait_candidates(self, goal, kind) } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncFnKindHelper) { G::consider_builtin_async_fn_kind_helper_candidate(self, goal) @@ -436,7 +434,7 @@ where } #[instrument(level = "trace", skip_all)] - fn assemble_param_env_candidates<G: GoalKind<Infcx>>( + fn assemble_param_env_candidates<G: GoalKind<D>>( &mut self, goal: Goal<I, G>, candidates: &mut Vec<Candidate<I>>, @@ -453,7 +451,7 @@ where } #[instrument(level = "trace", skip_all)] - fn assemble_alias_bound_candidates<G: GoalKind<Infcx>>( + fn assemble_alias_bound_candidates<G: GoalKind<D>>( &mut self, goal: Goal<I, G>, candidates: &mut Vec<Candidate<I>>, @@ -472,7 +470,7 @@ where /// If so, continue searching by recursively calling after normalization. // FIXME: This may recurse infinitely, but I can't seem to trigger it without // hitting another overflow error something. Add a depth parameter needed later. - fn assemble_alias_bound_candidates_recur<G: GoalKind<Infcx>>( + fn assemble_alias_bound_candidates_recur<G: GoalKind<D>>( &mut self, self_ty: I::Ty, goal: Goal<I, G>, @@ -523,15 +521,13 @@ where ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), ty::Alias(ty::Inherent | ty::Weak, _) => { - self.interner().delay_bug(format!("could not normalize {self_ty:?}, it is not WF")); + self.cx().delay_bug(format!("could not normalize {self_ty:?}, it is not WF")); return; } }; - for assumption in self - .interner() - .item_bounds(alias_ty.def_id) - .iter_instantiated(self.interner(), &alias_ty.args) + for assumption in + self.cx().item_bounds(alias_ty.def_id).iter_instantiated(self.cx(), &alias_ty.args) { candidates.extend(G::probe_and_consider_implied_clause( self, @@ -556,12 +552,12 @@ where } #[instrument(level = "trace", skip_all)] - fn assemble_object_bound_candidates<G: GoalKind<Infcx>>( + fn assemble_object_bound_candidates<G: GoalKind<D>>( &mut self, goal: Goal<I, G>, candidates: &mut Vec<Candidate<I>>, ) { - let tcx = self.interner(); + let tcx = self.cx(); if !tcx.trait_may_be_implemented_via_object(goal.predicate.trait_def_id(tcx)) { return; } @@ -629,8 +625,7 @@ where // a projection goal. if let Some(principal) = bounds.principal() { let principal_trait_ref = principal.with_self_ty(tcx, self_ty); - for (idx, assumption) in - Infcx::elaborate_supertraits(tcx, principal_trait_ref).enumerate() + for (idx, assumption) in D::elaborate_supertraits(tcx, principal_trait_ref).enumerate() { candidates.extend(G::probe_and_consider_object_bound_candidate( self, @@ -649,12 +644,12 @@ where /// To do so we add an ambiguous candidate in case such an unknown impl could /// apply to the current goal. #[instrument(level = "trace", skip_all)] - fn assemble_coherence_unknowable_candidates<G: GoalKind<Infcx>>( + fn assemble_coherence_unknowable_candidates<G: GoalKind<D>>( &mut self, goal: Goal<I, G>, candidates: &mut Vec<Candidate<I>>, ) { - let tcx = self.interner(); + let tcx = self.cx(); candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter( |ecx| { @@ -678,12 +673,12 @@ where // to improve this however. However, this should make it fairly straightforward to refine // the filtering going forward, so it seems alright-ish for now. #[instrument(level = "debug", skip(self, goal))] - fn discard_impls_shadowed_by_env<G: GoalKind<Infcx>>( + fn discard_impls_shadowed_by_env<G: GoalKind<D>>( &mut self, goal: Goal<I, G>, candidates: &mut Vec<Candidate<I>>, ) { - let tcx = self.interner(); + let tcx = self.cx(); let trait_goal: Goal<I, ty::TraitPredicate<I>> = goal.with(tcx, goal.predicate.trait_ref(tcx)); diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 202af76565a..b10be5a9ba7 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -2,7 +2,7 @@ //! traits, `Copy`/`Clone`. use rustc_ast_ir::{Movability, Mutability}; -use rustc_data_structures::fx::FxHashMap; +use rustc_type_ir::data_structures::HashMap; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; @@ -10,20 +10,20 @@ use rustc_type_ir::{self as ty, Interner, Upcast as _}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::instrument; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{EvalCtxt, Goal, NoSolution}; // Calculates the constituent types of a type for `auto trait` purposes. #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<Infcx, I>( - ecx: &EvalCtxt<'_, Infcx>, +pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<D, I>( + ecx: &EvalCtxt<'_, D>, ty: I::Ty, ) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { - let tcx = ecx.interner(); + let tcx = ecx.cx(); match ty.kind() { ty::Uint(_) | ty::Int(_) @@ -76,7 +76,7 @@ where } ty::CoroutineWitness(def_id, args) => Ok(ecx - .interner() + .cx() .bound_coroutine_hidden_types(def_id) .into_iter() .map(|bty| bty.instantiate(tcx, &args)) @@ -101,12 +101,12 @@ where } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<Infcx, I>( - ecx: &EvalCtxt<'_, Infcx>, +pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<D, I>( + ecx: &EvalCtxt<'_, D>, ty: I::Ty, ) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { match ty.kind() { @@ -159,8 +159,8 @@ where // "best effort" optimization and `sized_constraint` may return `Some`, even // if the ADT is sized for all possible args. ty::Adt(def, args) => { - if let Some(sized_crit) = def.sized_constraint(ecx.interner()) { - Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), &args))]) + if let Some(sized_crit) = def.sized_constraint(ecx.cx()) { + Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.cx(), &args))]) } else { Ok(vec![]) } @@ -169,12 +169,12 @@ where } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<Infcx, I>( - ecx: &EvalCtxt<'_, Infcx>, +pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<D, I>( + ecx: &EvalCtxt<'_, D>, ty: I::Ty, ) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { match ty.kind() { @@ -222,10 +222,10 @@ where // only when `coroutine_clone` is enabled and the coroutine is movable // impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses) - ty::Coroutine(def_id, args) => match ecx.interner().coroutine_movability(def_id) { + ty::Coroutine(def_id, args) => match ecx.cx().coroutine_movability(def_id) { Movability::Static => Err(NoSolution), Movability::Movable => { - if ecx.interner().features().coroutine_clone() { + if ecx.cx().features().coroutine_clone() { let coroutine = args.as_coroutine(); Ok(vec![ ty::Binder::dummy(coroutine.tupled_upvars_ty()), @@ -239,10 +239,10 @@ where // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types ty::CoroutineWitness(def_id, args) => Ok(ecx - .interner() + .cx() .bound_coroutine_hidden_types(def_id) .into_iter() - .map(|bty| bty.instantiate(ecx.interner(), &args)) + .map(|bty| bty.instantiate(ecx.cx(), &args)) .collect()), } } @@ -304,9 +304,10 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<I: Intern let kind_ty = args.kind_ty(); let sig = args.coroutine_closure_sig().skip_binder(); - let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() - && !args.tupled_upvars_ty().is_ty_var() - { + // FIXME: let_chains + let kind = kind_ty.to_opt_closure_kind(); + let coroutine_ty = if kind.is_some() && !args.tupled_upvars_ty().is_ty_var() { + let closure_kind = kind.unwrap(); if !closure_kind.extends(goal_kind) { return Err(NoSolution); } @@ -411,10 +412,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I: let kind_ty = args.kind_ty(); let sig = args.coroutine_closure_sig().skip_binder(); let mut nested = vec![]; - let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() - && !args.tupled_upvars_ty().is_ty_var() - { - if !closure_kind.extends(goal_kind) { + + // FIXME: let_chains + let kind = kind_ty.to_opt_closure_kind(); + let coroutine_ty = if kind.is_some() && !args.tupled_upvars_ty().is_ty_var() { + if !kind.unwrap().extends(goal_kind) { return Err(NoSolution); } @@ -654,17 +656,17 @@ fn coroutine_closure_to_ambiguous_coroutine<I: Interner>( // This is unsound in general and once that is fixed, we don't need to // normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9 // for more details. -pub(in crate::solve) fn predicates_for_object_candidate<Infcx, I>( - ecx: &EvalCtxt<'_, Infcx>, +pub(in crate::solve) fn predicates_for_object_candidate<D, I>( + ecx: &EvalCtxt<'_, D>, param_env: I::ParamEnv, trait_ref: ty::TraitRef<I>, object_bounds: I::BoundExistentialPredicates, ) -> Vec<Goal<I, I::Predicate>> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let mut requirements = vec![]; requirements .extend(tcx.super_predicates_of(trait_ref.def_id).iter_instantiated(tcx, &trait_ref.args)); @@ -683,7 +685,7 @@ where ); } - let mut replace_projection_with = FxHashMap::default(); + let mut replace_projection_with = HashMap::default(); for bound in object_bounds { if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() { let proj = proj.with_self_ty(tcx, trait_ref.self_ty()); @@ -710,39 +712,43 @@ where .collect() } -struct ReplaceProjectionWith<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> { - ecx: &'a EvalCtxt<'a, Infcx>, +struct ReplaceProjectionWith<'a, D: SolverDelegate<Interner = I>, I: Interner> { + ecx: &'a EvalCtxt<'a, D>, param_env: I::ParamEnv, - mapping: FxHashMap<I::DefId, ty::Binder<I, ty::ProjectionPredicate<I>>>, + mapping: HashMap<I::DefId, ty::Binder<I, ty::ProjectionPredicate<I>>>, nested: Vec<Goal<I, I::Predicate>>, } -impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> - for ReplaceProjectionWith<'_, Infcx, I> +impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> + for ReplaceProjectionWith<'_, D, I> { - fn interner(&self) -> I { - self.ecx.interner() + fn cx(&self) -> I { + self.ecx.cx() } fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { - if let ty::Alias(ty::Projection, alias_ty) = ty.kind() - && let Some(replacement) = self.mapping.get(&alias_ty.def_id) - { - // We may have a case where our object type's projection bound is higher-ranked, - // but the where clauses we instantiated are not. We can solve this by instantiating - // the binder at the usage site. - let proj = self.ecx.instantiate_binder_with_infer(*replacement); - // FIXME: Technically this equate could be fallible... - self.nested.extend( - self.ecx - .eq_and_get_goals( - self.param_env, - alias_ty, - proj.projection_term.expect_ty(self.ecx.interner()), - ) - .expect("expected to be able to unify goal projection with dyn's projection"), - ); - proj.term.expect_ty() + if let ty::Alias(ty::Projection, alias_ty) = ty.kind() { + if let Some(replacement) = self.mapping.get(&alias_ty.def_id) { + // We may have a case where our object type's projection bound is higher-ranked, + // but the where clauses we instantiated are not. We can solve this by instantiating + // the binder at the usage site. + let proj = self.ecx.instantiate_binder_with_infer(*replacement); + // FIXME: Technically this equate could be fallible... + self.nested.extend( + self.ecx + .eq_and_get_goals( + self.param_env, + alias_ty, + proj.projection_term.expect_ty(self.ecx.cx()), + ) + .expect( + "expected to be able to unify goal projection with dyn's projection", + ), + ); + proj.term.expect_ty() + } else { + ty.super_fold_with(self) + } } else { ty.super_fold_with(self) } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index c6611285a3b..f1d4864a84b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -18,7 +18,7 @@ use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, Interner}; use tracing::{instrument, trace}; use crate::canonicalizer::{CanonicalizeMode, Canonicalizer}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::resolve::EagerResolver; use crate::solve::eval_ctxt::NestedGoals; use crate::solve::inspect; @@ -44,9 +44,9 @@ impl<I: Interner, T> ResponseT<I> for inspect::State<I, T> { } } -impl<Infcx, I> EvalCtxt<'_, Infcx> +impl<D, I> EvalCtxt<'_, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { /// Canonicalizes the goal remembering the original values @@ -55,19 +55,19 @@ where &self, goal: Goal<I, T>, ) -> (Vec<I::GenericArg>, CanonicalInput<I, T>) { - let opaque_types = self.infcx.clone_opaque_types_for_query_response(); + let opaque_types = self.delegate.clone_opaque_types_for_query_response(); let (goal, opaque_types) = - (goal, opaque_types).fold_with(&mut EagerResolver::new(self.infcx)); + (goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate)); let mut orig_values = Default::default(); let canonical_goal = Canonicalizer::canonicalize( - self.infcx, + self.delegate, CanonicalizeMode::Input, &mut orig_values, QueryInput { goal, predefined_opaques_in_body: self - .interner() + .cx() .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }), }, ); @@ -97,7 +97,7 @@ where // We only check for leaks from universes which were entered inside // of the query. - self.infcx.leak_check(self.max_input_universe).map_err(|NoSolution| { + self.delegate.leak_check(self.max_input_universe).map_err(|NoSolution| { trace!("failed the leak check"); NoSolution })?; @@ -125,21 +125,21 @@ where let external_constraints = self.compute_external_query_constraints(certainty, normalization_nested_goals); - let (var_values, mut external_constraints) = - (self.var_values, external_constraints).fold_with(&mut EagerResolver::new(self.infcx)); + let (var_values, mut external_constraints) = (self.var_values, external_constraints) + .fold_with(&mut EagerResolver::new(self.delegate)); // Remove any trivial region constraints once we've resolved regions external_constraints .region_constraints .retain(|outlives| outlives.0.as_region().map_or(true, |re| re != outlives.1)); let canonical = Canonicalizer::canonicalize( - self.infcx, + self.delegate, CanonicalizeMode::Response { max_input_universe: self.max_input_universe }, &mut Default::default(), Response { var_values, certainty, - external_constraints: self.interner().mk_external_constraints(external_constraints), + external_constraints: self.cx().mk_external_constraints(external_constraints), }, ); @@ -155,7 +155,7 @@ where maybe_cause: MaybeCause, ) -> CanonicalResponse<I> { response_no_constraints_raw( - self.interner(), + self.cx(), self.max_input_universe, self.variables, Certainty::Maybe(maybe_cause), @@ -184,7 +184,7 @@ where // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs` and // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`. let region_constraints = if certainty == Certainty::Yes { - self.infcx.make_deduplicated_outlives_constraints() + self.delegate.make_deduplicated_outlives_constraints() } else { Default::default() }; @@ -192,7 +192,7 @@ where ExternalConstraintsData { region_constraints, opaque_types: self - .infcx + .delegate .clone_opaque_types_for_query_response() .into_iter() // Only return *newly defined* opaque types. @@ -219,15 +219,15 @@ where response: CanonicalResponse<I>, ) -> (NestedNormalizationGoals<I>, Certainty) { let instantiation = Self::compute_query_response_instantiation_values( - self.infcx, + self.delegate, &original_values, &response, ); let Response { var_values, external_constraints, certainty } = - self.infcx.instantiate_canonical(response, instantiation); + self.delegate.instantiate_canonical(response, instantiation); - Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values); + Self::unify_query_var_values(self.delegate, param_env, &original_values, var_values); let ExternalConstraintsData { region_constraints, @@ -243,17 +243,17 @@ where /// the canonical response. This depends on the `original_values` for the /// bound variables. fn compute_query_response_instantiation_values<T: ResponseT<I>>( - infcx: &Infcx, + delegate: &D, original_values: &[I::GenericArg], response: &Canonical<I, T>, ) -> CanonicalVarValues<I> { // FIXME: Longterm canonical queries should deal with all placeholders // created inside of the query directly instead of returning them to the // caller. - let prev_universe = infcx.universe(); + let prev_universe = delegate.universe(); let universes_created_in_query = response.max_universe.index(); for _ in 0..universes_created_in_query { - infcx.create_next_universe(); + delegate.create_next_universe(); } let var_values = response.value.var_values(); @@ -290,13 +290,13 @@ where } } - let var_values = infcx.interner().mk_args_from_iter( + let var_values = delegate.cx().mk_args_from_iter( response.variables.into_iter().enumerate().map(|(index, info)| { if info.universe() != ty::UniverseIndex::ROOT { // A variable from inside a binder of the query. While ideally these shouldn't // exist at all (see the FIXME at the start of this method), we have to deal with // them for now. - infcx.instantiate_canonical_var_with_infer(info, |idx| { + delegate.instantiate_canonical_var_with_infer(info, |idx| { ty::UniverseIndex::from(prev_universe.index() + idx.index()) }) } else if info.is_existential() { @@ -310,7 +310,7 @@ where if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] { v } else { - infcx.instantiate_canonical_var_with_infer(info, |_| prev_universe) + delegate.instantiate_canonical_var_with_infer(info, |_| prev_universe) } } else { // For placeholders which were already part of the input, we simply map this @@ -335,9 +335,9 @@ where /// whether an alias is rigid by using the trait solver. When instantiating a response /// from the solver we assume that the solver correctly handled aliases and therefore /// always relate them structurally here. - #[instrument(level = "trace", skip(infcx))] + #[instrument(level = "trace", skip(delegate))] fn unify_query_var_values( - infcx: &Infcx, + delegate: &D, param_env: I::ParamEnv, original_values: &[I::GenericArg], var_values: CanonicalVarValues<I>, @@ -345,7 +345,8 @@ where assert_eq!(original_values.len(), var_values.len()); for (&orig, response) in iter::zip(original_values, var_values.var_values) { - let goals = infcx.eq_structurally_relating_aliases(param_env, orig, response).unwrap(); + let goals = + delegate.eq_structurally_relating_aliases(param_env, orig, response).unwrap(); assert!(goals.is_empty()); } } @@ -365,7 +366,7 @@ where fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<I>, I::Ty)]) { for &(key, ty) in opaque_types { - self.infcx.inject_new_hidden_type_unchecked(key, ty); + self.delegate.inject_new_hidden_type_unchecked(key, ty); } } } @@ -374,22 +375,22 @@ where /// evaluating a goal. The `var_values` not only include the bound variables /// of the query input, but also contain all unconstrained inference vars /// created while evaluating this goal. -pub(in crate::solve) fn make_canonical_state<Infcx, T, I>( - infcx: &Infcx, +pub(in crate::solve) fn make_canonical_state<D, T, I>( + delegate: &D, var_values: &[I::GenericArg], max_input_universe: ty::UniverseIndex, data: T, ) -> inspect::CanonicalState<I, T> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, T: TypeFoldable<I>, { - let var_values = CanonicalVarValues { var_values: infcx.interner().mk_args(var_values) }; + let var_values = CanonicalVarValues { var_values: delegate.cx().mk_args(var_values) }; let state = inspect::State { var_values, data }; - let state = state.fold_with(&mut EagerResolver::new(infcx)); + let state = state.fold_with(&mut EagerResolver::new(delegate)); Canonicalizer::canonicalize( - infcx, + delegate, CanonicalizeMode::Response { max_input_universe }, &mut vec![], state, @@ -398,15 +399,15 @@ where // FIXME: needs to be pub to be accessed by downstream // `rustc_trait_selection::solve::inspect::analyse`. -pub fn instantiate_canonical_state<Infcx, I, T: TypeFoldable<I>>( - infcx: &Infcx, - span: Infcx::Span, +pub fn instantiate_canonical_state<D, I, T: TypeFoldable<I>>( + delegate: &D, + span: D::Span, param_env: I::ParamEnv, orig_values: &mut Vec<I::GenericArg>, state: inspect::CanonicalState<I, T>, ) -> T where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { // In case any fresh inference variables have been created between `state` @@ -415,15 +416,15 @@ where for &arg in &state.value.var_values.var_values[orig_values.len()..state.value.var_values.len()] { // FIXME: This is so ugly. - let unconstrained = infcx.fresh_var_for_kind_with_span(arg, span); + let unconstrained = delegate.fresh_var_for_kind_with_span(arg, span); orig_values.push(unconstrained); } let instantiation = - EvalCtxt::compute_query_response_instantiation_values(infcx, orig_values, &state); + EvalCtxt::compute_query_response_instantiation_values(delegate, orig_values, &state); - let inspect::State { var_values, data } = infcx.instantiate_canonical(state, instantiation); + let inspect::State { var_values, data } = delegate.instantiate_canonical(state, instantiation); - EvalCtxt::unify_query_var_values(infcx, param_env, orig_values, var_values); + EvalCtxt::unify_query_var_values(delegate, param_env, orig_values, var_values); data } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 485758b91a2..6644fff2140 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1,7 +1,8 @@ use std::ops::ControlFlow; -use rustc_data_structures::stack::ensure_sufficient_stack; +#[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir::data_structures::ensure_sufficient_stack; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; @@ -10,7 +11,7 @@ use rustc_type_ir::{self as ty, CanonicalVarValues, Interner}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::{instrument, trace}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::{ @@ -22,9 +23,9 @@ use crate::solve::{ pub(super) mod canonical; mod probe; -pub struct EvalCtxt<'a, Infcx, I = <Infcx as SolverDelegate>::Interner> +pub struct EvalCtxt<'a, D, I = <D as SolverDelegate>::Interner> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { /// The inference context that backs (mostly) inference and placeholder terms @@ -42,7 +43,7 @@ where /// If some `InferCtxt` method is missing, please first think defensively about /// the method's compatibility with this solver, or if an existing one does /// the job already. - infcx: &'a Infcx, + delegate: &'a D, /// The variable info for the `var_values`, only used to make an ambiguous response /// with no constraints. @@ -82,13 +83,13 @@ where // evaluation code. tainted: Result<(), NoSolution>, - pub(super) inspect: ProofTreeBuilder<Infcx>, + pub(super) inspect: ProofTreeBuilder<D>, } #[derive(derivative::Derivative)] #[derivative(Clone(bound = ""), Debug(bound = ""), Default(bound = ""))] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[derive(TyDecodable, TyEncodable, HashStable_NoContext)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] // FIXME: This can be made crate-private once `EvalCtxt` also lives in this crate. pub struct NestedGoals<I: Interner> { /// These normalizes-to goals are treated specially during the evaluation @@ -116,7 +117,8 @@ impl<I: Interner> NestedGoals<I> { } } -#[derive(PartialEq, Eq, Debug, Hash, HashStable_NoContext, Clone, Copy)] +#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum GenerateProofTree { Yes, No, @@ -141,9 +143,9 @@ pub trait SolverDelegateEvalExt: SolverDelegate { ); } -impl<Infcx, I> SolverDelegateEvalExt for Infcx +impl<D, I> SolverDelegateEvalExt for D where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { /// Evaluates a goal from **outside** of the trait solver. @@ -176,9 +178,9 @@ where } } -impl<'a, Infcx, I> EvalCtxt<'a, Infcx> +impl<'a, D, I> EvalCtxt<'a, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { pub(super) fn solver_mode(&self) -> SolverMode { @@ -193,22 +195,22 @@ where /// used from outside of any evaluation, and other methods should be preferred /// over using this manually (such as [`SolverDelegateEvalExt::evaluate_root_goal`]). pub(super) fn enter_root<R>( - infcx: &Infcx, + delegate: &D, generate_proof_tree: GenerateProofTree, - f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> R, + f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R, ) -> (R, Option<inspect::GoalEvaluation<I>>) { - let mut search_graph = search_graph::SearchGraph::new(infcx.solver_mode()); + let mut search_graph = search_graph::SearchGraph::new(delegate.solver_mode()); let mut ecx = EvalCtxt { - infcx, + delegate, search_graph: &mut search_graph, nested_goals: NestedGoals::new(), inspect: ProofTreeBuilder::new_maybe_root(generate_proof_tree), // Only relevant when canonicalizing the response, // which we don't do within this evaluation context. - predefined_opaques_in_body: infcx - .interner() + predefined_opaques_in_body: delegate + .cx() .mk_predefined_opaques_in_body(PredefinedOpaquesData::default()), max_input_universe: ty::UniverseIndex::ROOT, variables: Default::default(), @@ -240,14 +242,14 @@ where tcx: I, search_graph: &'a mut search_graph::SearchGraph<I>, canonical_input: CanonicalInput<I>, - canonical_goal_evaluation: &mut ProofTreeBuilder<Infcx>, - f: impl FnOnce(&mut EvalCtxt<'_, Infcx>, Goal<I, I::Predicate>) -> R, + canonical_goal_evaluation: &mut ProofTreeBuilder<D>, + f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R, ) -> R { - let (ref infcx, input, var_values) = + let (ref delegate, input, var_values) = SolverDelegate::build_with_canonical(tcx, search_graph.solver_mode(), &canonical_input); let mut ecx = EvalCtxt { - infcx, + delegate, variables: canonical_input.variables, var_values, is_normalizes_to_goal: false, @@ -260,7 +262,7 @@ where }; for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { - ecx.infcx.inject_new_hidden_type_unchecked(key, ty); + ecx.delegate.inject_new_hidden_type_unchecked(key, ty); } if !ecx.nested_goals.is_empty() { @@ -268,7 +270,7 @@ where } let result = f(&mut ecx, input.goal); - ecx.inspect.probe_final_state(ecx.infcx, ecx.max_input_universe); + ecx.inspect.probe_final_state(ecx.delegate, ecx.max_input_universe); canonical_goal_evaluation.goal_evaluation_step(ecx.inspect); // When creating a query response we clone the opaque type constraints @@ -276,7 +278,7 @@ where // assertions against dropping an `InferCtxt` without taking opaques. // FIXME: Once we remove support for the old impl we can remove this. // FIXME: Could we make `build_with_canonical` into `enter_with_canonical` and call this at the end? - infcx.reset_opaque_types(); + delegate.reset_opaque_types(); result } @@ -295,7 +297,7 @@ where tcx: I, search_graph: &'a mut search_graph::SearchGraph<I>, canonical_input: CanonicalInput<I>, - goal_evaluation: &mut ProofTreeBuilder<Infcx>, + goal_evaluation: &mut ProofTreeBuilder<D>, ) -> QueryResult<I> { let mut canonical_goal_evaluation = goal_evaluation.new_canonical_goal_evaluation(canonical_input); @@ -362,7 +364,7 @@ where let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); let canonical_response = EvalCtxt::evaluate_canonical_goal( - self.interner(), + self.cx(), self.search_graph, canonical_goal, &mut goal_evaluation, @@ -464,8 +466,8 @@ where } } } else { - self.infcx.enter_forall(kind, |kind| { - let goal = goal.with(self.interner(), ty::Binder::dummy(kind)); + self.delegate.enter_forall(kind, |kind| { + let goal = goal.with(self.cx(), ty::Binder::dummy(kind)); self.add_goal(GoalSource::InstantiateHigherRanked, goal); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) @@ -504,7 +506,7 @@ where /// /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`. fn evaluate_added_goals_step(&mut self) -> Result<Option<Certainty>, NoSolution> { - let tcx = self.interner(); + let tcx = self.cx(); let mut goals = core::mem::take(&mut self.nested_goals); // If this loop did not result in any progress, what's our final certainty. @@ -586,11 +588,11 @@ where /// Record impl args in the proof tree for later access by `InspectCandidate`. pub(crate) fn record_impl_args(&mut self, impl_args: I::GenericArgs) { - self.inspect.record_impl_args(self.infcx, self.max_input_universe, impl_args) + self.inspect.record_impl_args(self.delegate, self.max_input_universe, impl_args) } - pub(super) fn interner(&self) -> I { - self.infcx.interner() + pub(super) fn cx(&self) -> I { + self.delegate.cx() } #[instrument(level = "trace", skip(self))] @@ -598,7 +600,7 @@ where goal.predicate = goal .predicate .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); - self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal); + self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal); self.nested_goals.normalizes_to_goals.push(goal); } @@ -607,7 +609,7 @@ where goal.predicate = goal .predicate .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); - self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal); + self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); self.nested_goals.goals.push((source, goal)); } @@ -623,13 +625,13 @@ where } pub(super) fn next_ty_infer(&mut self) -> I::Ty { - let ty = self.infcx.next_ty_infer(); + let ty = self.delegate.next_ty_infer(); self.inspect.add_var_value(ty); ty } pub(super) fn next_const_infer(&mut self) -> I::Const { - let ct = self.infcx.next_const_infer(); + let ct = self.delegate.next_const_infer(); self.inspect.add_var_value(ct); ct } @@ -652,27 +654,27 @@ where let universe_of_term = match goal.predicate.term.kind() { ty::TermKind::Ty(ty) => { if let ty::Infer(ty::TyVar(vid)) = ty.kind() { - self.infcx.universe_of_ty(vid).unwrap() + self.delegate.universe_of_ty(vid).unwrap() } else { return false; } } ty::TermKind::Const(ct) => { if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { - self.infcx.universe_of_ct(vid).unwrap() + self.delegate.universe_of_ct(vid).unwrap() } else { return false; } } }; - struct ContainsTermOrNotNameable<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> { + struct ContainsTermOrNotNameable<'a, D: SolverDelegate<Interner = I>, I: Interner> { term: I::Term, universe_of_term: ty::UniverseIndex, - infcx: &'a Infcx, + delegate: &'a D, } - impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> { + impl<D: SolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, D, I> { fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> { if self.universe_of_term.can_name(universe) { ControlFlow::Continue(()) @@ -682,21 +684,24 @@ where } } - impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeVisitor<I> - for ContainsTermOrNotNameable<'_, Infcx, I> + impl<D: SolverDelegate<Interner = I>, I: Interner> TypeVisitor<I> + for ContainsTermOrNotNameable<'_, D, I> { type Result = ControlFlow<()>; fn visit_ty(&mut self, t: I::Ty) -> Self::Result { match t.kind() { ty::Infer(ty::TyVar(vid)) => { - if let ty::TermKind::Ty(term) = self.term.kind() - && let ty::Infer(ty::TyVar(term_vid)) = term.kind() - && self.infcx.root_ty_var(vid) == self.infcx.root_ty_var(term_vid) - { - ControlFlow::Break(()) - } else { - self.check_nameable(self.infcx.universe_of_ty(vid).unwrap()) + if let ty::TermKind::Ty(term) = self.term.kind() { + if let ty::Infer(ty::TyVar(term_vid)) = term.kind() { + if self.delegate.root_ty_var(vid) + == self.delegate.root_ty_var(term_vid) + { + return ControlFlow::Break(()); + } + } } + + self.check_nameable(self.delegate.universe_of_ty(vid).unwrap()) } ty::Placeholder(p) => self.check_nameable(p.universe()), _ => { @@ -712,14 +717,18 @@ where fn visit_const(&mut self, c: I::Const) -> Self::Result { match c.kind() { ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { - if let ty::TermKind::Const(term) = self.term.kind() - && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() - && self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid) - { - ControlFlow::Break(()) - } else { - self.check_nameable(self.infcx.universe_of_ct(vid).unwrap()) + if let ty::TermKind::Const(term) = self.term.kind() { + if let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() + { + if self.delegate.root_const_var(vid) + == self.delegate.root_const_var(term_vid) + { + return ControlFlow::Break(()); + } + } } + + self.check_nameable(self.delegate.universe_of_ct(vid).unwrap()) } ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe()), _ => { @@ -734,7 +743,7 @@ where } let mut visitor = ContainsTermOrNotNameable { - infcx: self.infcx, + delegate: self.delegate, universe_of_term, term: goal.predicate.term, }; @@ -768,7 +777,7 @@ where // NOTE: this check is purely an optimization, the structural eq would // always fail if the term is not an inference variable. if term.is_infer() { - let tcx = self.interner(); + let tcx = self.cx(); // We need to relate `alias` to `term` treating only the outermost // constructor as rigid, relating any contained generic arguments as // normal. We do this by first structurally equating the `term` @@ -781,7 +790,7 @@ where let rigid_ctor = ty::AliasTerm::new(tcx, alias.def_id, identity_args); let ctor_term = rigid_ctor.to_term(tcx); let obligations = - self.infcx.eq_structurally_relating_aliases(param_env, term, ctor_term)?; + self.delegate.eq_structurally_relating_aliases(param_env, term, ctor_term)?; debug_assert!(obligations.is_empty()); self.relate(param_env, alias, variance, rigid_ctor) } else { @@ -799,7 +808,7 @@ where lhs: T, rhs: T, ) -> Result<(), NoSolution> { - let result = self.infcx.eq_structurally_relating_aliases(param_env, lhs, rhs)?; + let result = self.delegate.eq_structurally_relating_aliases(param_env, lhs, rhs)?; assert_eq!(result, vec![]); Ok(()) } @@ -822,7 +831,7 @@ where variance: ty::Variance, rhs: T, ) -> Result<(), NoSolution> { - let goals = self.infcx.relate(param_env, lhs, variance, rhs)?; + let goals = self.delegate.relate(param_env, lhs, variance, rhs)?; self.add_goals(GoalSource::Misc, goals); Ok(()) } @@ -839,14 +848,14 @@ where lhs: T, rhs: T, ) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> { - self.infcx.relate(param_env, lhs, ty::Variance::Invariant, rhs) + self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs) } pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>( &self, value: ty::Binder<I, T>, ) -> T { - self.infcx.instantiate_binder_with_infer(value) + self.delegate.instantiate_binder_with_infer(value) } pub(super) fn enter_forall<T: TypeFoldable<I> + Copy, U>( @@ -854,18 +863,18 @@ where value: ty::Binder<I, T>, f: impl FnOnce(T) -> U, ) -> U { - self.infcx.enter_forall(value, f) + self.delegate.enter_forall(value, f) } pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T where T: TypeFoldable<I>, { - self.infcx.resolve_vars_if_possible(value) + self.delegate.resolve_vars_if_possible(value) } pub(super) fn fresh_args_for_item(&mut self, def_id: I::DefId) -> I::GenericArgs { - let args = self.infcx.fresh_args_for_item(def_id); + let args = self.delegate.fresh_args_for_item(def_id); for arg in args { self.inspect.add_var_value(arg); } @@ -873,12 +882,12 @@ where } pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) { - self.infcx.register_ty_outlives(ty, lt); + self.delegate.register_ty_outlives(ty, lt); } pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) { // `b : a` ==> `a <= b` - self.infcx.sub_regions(b, a); + self.delegate.sub_regions(b, a); } /// Computes the list of goals required for `arg` to be well-formed @@ -887,7 +896,7 @@ where param_env: I::ParamEnv, arg: I::GenericArg, ) -> Option<Vec<Goal<I, I::Predicate>>> { - self.infcx.well_formed_goals(param_env, arg) + self.delegate.well_formed_goals(param_env, arg) } pub(super) fn trait_ref_is_knowable( @@ -895,9 +904,9 @@ where param_env: I::ParamEnv, trait_ref: ty::TraitRef<I>, ) -> Result<bool, NoSolution> { - let infcx = self.infcx; + let delegate = self.delegate; let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty); - infcx.trait_ref_is_knowable(trait_ref, lazily_normalize_ty) + delegate.trait_ref_is_knowable(trait_ref, lazily_normalize_ty) } pub(super) fn fetch_eligible_assoc_item( @@ -907,7 +916,7 @@ where trait_assoc_def_id: I::DefId, impl_def_id: I::DefId, ) -> Result<Option<I::DefId>, NoSolution> { - self.infcx.fetch_eligible_assoc_item( + self.delegate.fetch_eligible_assoc_item( param_env, goal_trait_ref, trait_assoc_def_id, @@ -916,7 +925,7 @@ where } pub(super) fn can_define_opaque_ty(&self, def_id: I::LocalDefId) -> bool { - self.infcx.defining_opaque_types().contains(&def_id) + self.delegate.defining_opaque_types().contains(&def_id) } pub(super) fn insert_hidden_type( @@ -926,7 +935,7 @@ where hidden_ty: I::Ty, ) -> Result<(), NoSolution> { let mut goals = Vec::new(); - self.infcx.insert_hidden_type(opaque_type_key, param_env, hidden_ty, &mut goals)?; + self.delegate.insert_hidden_type(opaque_type_key, param_env, hidden_ty, &mut goals)?; self.add_goals(GoalSource::Misc, goals); Ok(()) } @@ -939,7 +948,7 @@ where hidden_ty: I::Ty, ) { let mut goals = Vec::new(); - self.infcx.add_item_bounds_for_hidden_type( + self.delegate.add_item_bounds_for_hidden_type( opaque_def_id, opaque_args, param_env, @@ -958,7 +967,7 @@ where ty: I::Ty, ) -> Vec<CanonicalResponse<I>> { // FIXME: Super inefficient to be cloning this... - let opaques = self.infcx.clone_opaque_types_for_query_response(); + let opaques = self.delegate.clone_opaque_types_for_query_response(); let mut values = vec![]; for (candidate_key, candidate_ty) in opaques { @@ -995,7 +1004,7 @@ where param_env: I::ParamEnv, unevaluated: ty::UnevaluatedConst<I>, ) -> Option<I::Const> { - self.infcx.try_const_eval_resolve(param_env, unevaluated) + self.delegate.try_const_eval_resolve(param_env, unevaluated) } pub(super) fn is_transmutable( @@ -1005,7 +1014,7 @@ where src: I::Ty, assume: I::Const, ) -> Result<Certainty, NoSolution> { - self.infcx.is_transmutable(param_env, dst, src, assume) + self.delegate.is_transmutable(param_env, dst, src, assume) } } @@ -1016,22 +1025,22 @@ where /// /// This is a performance optimization to more eagerly detect cycles during trait /// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs. -struct ReplaceAliasWithInfer<'me, 'a, Infcx, I> +struct ReplaceAliasWithInfer<'me, 'a, D, I> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { - ecx: &'me mut EvalCtxt<'a, Infcx>, + ecx: &'me mut EvalCtxt<'a, D>, param_env: I::ParamEnv, } -impl<Infcx, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, Infcx, I> +impl<D, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, D, I> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { - fn interner(&self) -> I { - self.ecx.interner() + fn cx(&self) -> I { + self.ecx.cx() } fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { @@ -1045,7 +1054,7 @@ where ); self.ecx.add_goal( GoalSource::Misc, - Goal::new(self.interner(), self.param_env, normalizes_to), + Goal::new(self.cx(), self.param_env, normalizes_to), ); infer_ty } @@ -1064,7 +1073,7 @@ where ); self.ecx.add_goal( GoalSource::Misc, - Goal::new(self.interner(), self.param_env, normalizes_to), + Goal::new(self.cx(), self.param_env, normalizes_to), ); infer_ct } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs index 1c5358b3edb..e9516c60c70 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs @@ -3,34 +3,34 @@ use std::marker::PhantomData; use rustc_type_ir::Interner; use tracing::instrument; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::assembly::Candidate; use crate::solve::inspect; use crate::solve::{BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult}; -pub(in crate::solve) struct ProbeCtxt<'me, 'a, Infcx, I, F, T> +pub(in crate::solve) struct ProbeCtxt<'me, 'a, D, I, F, T> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { - ecx: &'me mut EvalCtxt<'a, Infcx, I>, + ecx: &'me mut EvalCtxt<'a, D, I>, probe_kind: F, _result: PhantomData<T>, } -impl<Infcx, I, F, T> ProbeCtxt<'_, '_, Infcx, I, F, T> +impl<D, I, F, T> ProbeCtxt<'_, '_, D, I, F, T> where F: FnOnce(&T) -> inspect::ProbeKind<I>, - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { - pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> T) -> T { + pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T) -> T { let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self; - let infcx = outer_ecx.infcx; + let delegate = outer_ecx.delegate; let max_input_universe = outer_ecx.max_input_universe; let mut nested_ecx = EvalCtxt { - infcx, + delegate, variables: outer_ecx.variables, var_values: outer_ecx.var_values, is_normalizes_to_goal: outer_ecx.is_normalizes_to_goal, @@ -41,9 +41,9 @@ where tainted: outer_ecx.tainted, inspect: outer_ecx.inspect.take_and_enter_probe(), }; - let r = nested_ecx.infcx.probe(|| { + let r = nested_ecx.delegate.probe(|| { let r = f(&mut nested_ecx); - nested_ecx.inspect.probe_final_state(infcx, max_input_universe); + nested_ecx.inspect.probe_final_state(delegate, max_input_universe); r }); if !nested_ecx.inspect.is_noop() { @@ -55,41 +55,38 @@ where } } -pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, Infcx, I, F> +pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, D, I, F> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { - cx: ProbeCtxt<'me, 'a, Infcx, I, F, QueryResult<I>>, + cx: ProbeCtxt<'me, 'a, D, I, F, QueryResult<I>>, source: CandidateSource<I>, } -impl<Infcx, I, F> TraitProbeCtxt<'_, '_, Infcx, I, F> +impl<D, I, F> TraitProbeCtxt<'_, '_, D, I, F> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, F: FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>, { #[instrument(level = "debug", skip_all, fields(source = ?self.source))] pub(in crate::solve) fn enter( self, - f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>, + f: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, ) -> Result<Candidate<I>, NoSolution> { self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result }) } } -impl<'a, Infcx, I> EvalCtxt<'a, Infcx, I> +impl<'a, D, I> EvalCtxt<'a, D, I> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { /// `probe_kind` is only called when proof tree building is enabled so it can be /// as expensive as necessary to output the desired information. - pub(in crate::solve) fn probe<F, T>( - &mut self, - probe_kind: F, - ) -> ProbeCtxt<'_, 'a, Infcx, I, F, T> + pub(in crate::solve) fn probe<F, T>(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, D, I, F, T> where F: FnOnce(&T) -> inspect::ProbeKind<I>, { @@ -99,16 +96,14 @@ where pub(in crate::solve) fn probe_builtin_trait_candidate( &mut self, source: BuiltinImplSource, - ) -> TraitProbeCtxt<'_, 'a, Infcx, I, impl FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>> - { + ) -> TraitProbeCtxt<'_, 'a, D, I, impl FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>> { self.probe_trait_candidate(CandidateSource::BuiltinImpl(source)) } pub(in crate::solve) fn probe_trait_candidate( &mut self, source: CandidateSource<I>, - ) -> TraitProbeCtxt<'_, 'a, Infcx, I, impl FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>> - { + ) -> TraitProbeCtxt<'_, 'a, D, I, impl FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>> { TraitProbeCtxt { cx: ProbeCtxt { ecx: self, diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 5fbec4b28d4..ae59f0c5e95 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -9,7 +9,7 @@ use std::mem; use rustc_type_ir::{self as ty, Interner}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::eval_ctxt::canonical; use crate::solve::inspect; use crate::solve::{ @@ -37,12 +37,12 @@ use crate::solve::{ /// trees. At the end of trait solving `ProofTreeBuilder::finalize` /// is called to recursively convert the whole structure to a /// finished proof tree. -pub(in crate::solve) struct ProofTreeBuilder<Infcx, I = <Infcx as SolverDelegate>::Interner> +pub(in crate::solve) struct ProofTreeBuilder<D, I = <D as SolverDelegate>::Interner> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { - _infcx: PhantomData<Infcx>, + _infcx: PhantomData<D>, state: Option<Box<DebugSolver<I>>>, } @@ -235,8 +235,8 @@ impl<I: Interner> WipProbeStep<I> { } } -impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { - fn new(state: impl Into<DebugSolver<I>>) -> ProofTreeBuilder<Infcx> { +impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> { + fn new(state: impl Into<DebugSolver<I>>) -> ProofTreeBuilder<D> { ProofTreeBuilder { state: Some(Box::new(state.into())), _infcx: PhantomData } } @@ -258,7 +258,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { self.state.as_deref_mut() } - pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<Infcx> { + pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<D> { let mut nested = ProofTreeBuilder { state: self.state.take(), _infcx: PhantomData }; nested.enter_probe(); nested @@ -273,18 +273,18 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { } } - pub fn new_maybe_root(generate_proof_tree: GenerateProofTree) -> ProofTreeBuilder<Infcx> { + pub fn new_maybe_root(generate_proof_tree: GenerateProofTree) -> ProofTreeBuilder<D> { match generate_proof_tree { GenerateProofTree::No => ProofTreeBuilder::new_noop(), GenerateProofTree::Yes => ProofTreeBuilder::new_root(), } } - pub fn new_root() -> ProofTreeBuilder<Infcx> { + pub fn new_root() -> ProofTreeBuilder<D> { ProofTreeBuilder::new(DebugSolver::Root) } - pub fn new_noop() -> ProofTreeBuilder<Infcx> { + pub fn new_noop() -> ProofTreeBuilder<D> { ProofTreeBuilder { state: None, _infcx: PhantomData } } @@ -297,7 +297,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { goal: Goal<I, I::Predicate>, orig_values: &[I::GenericArg], kind: GoalEvaluationKind, - ) -> ProofTreeBuilder<Infcx> { + ) -> ProofTreeBuilder<D> { self.opt_nested(|| match kind { GoalEvaluationKind::Root => Some(WipGoalEvaluation { uncanonicalized_goal: goal, @@ -311,7 +311,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { pub fn new_canonical_goal_evaluation( &mut self, goal: CanonicalInput<I>, - ) -> ProofTreeBuilder<Infcx> { + ) -> ProofTreeBuilder<D> { self.nested(|| WipCanonicalGoalEvaluation { goal, kind: None, @@ -337,10 +337,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { }) } - pub fn canonical_goal_evaluation( - &mut self, - canonical_goal_evaluation: ProofTreeBuilder<Infcx>, - ) { + pub fn canonical_goal_evaluation(&mut self, canonical_goal_evaluation: ProofTreeBuilder<D>) { if let Some(this) = self.as_mut() { match (this, *canonical_goal_evaluation.state.unwrap()) { ( @@ -366,7 +363,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { } } - pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<Infcx>) { + pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<D>) { if let Some(this) = self.as_mut() { match this { DebugSolver::Root => *this = *goal_evaluation.state.unwrap(), @@ -382,7 +379,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { &mut self, var_values: ty::CanonicalVarValues<I>, instantiated_goal: QueryInput<I, I::Predicate>, - ) -> ProofTreeBuilder<Infcx> { + ) -> ProofTreeBuilder<D> { self.nested(|| WipCanonicalGoalEvaluationStep { var_values: var_values.var_values.to_vec(), instantiated_goal, @@ -396,7 +393,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { }) } - pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<Infcx>) { + pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<D>) { if let Some(this) = self.as_mut() { match (this, *goal_evaluation_step.state.unwrap()) { ( @@ -448,12 +445,12 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { } } - pub fn probe_final_state(&mut self, infcx: &Infcx, max_input_universe: ty::UniverseIndex) { + pub fn probe_final_state(&mut self, delegate: &D, max_input_universe: ty::UniverseIndex) { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { let final_state = canonical::make_canonical_state( - infcx, + delegate, &state.var_values, max_input_universe, (), @@ -467,21 +464,21 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { pub fn add_normalizes_to_goal( &mut self, - infcx: &Infcx, + delegate: &D, max_input_universe: ty::UniverseIndex, goal: Goal<I, ty::NormalizesTo<I>>, ) { self.add_goal( - infcx, + delegate, max_input_universe, GoalSource::Misc, - goal.with(infcx.interner(), goal.predicate), + goal.with(delegate.cx(), goal.predicate), ); } pub fn add_goal( &mut self, - infcx: &Infcx, + delegate: &D, max_input_universe: ty::UniverseIndex, source: GoalSource, goal: Goal<I, I::Predicate>, @@ -490,7 +487,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { let goal = canonical::make_canonical_state( - infcx, + delegate, &state.var_values, max_input_universe, goal, @@ -503,14 +500,14 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { pub(crate) fn record_impl_args( &mut self, - infcx: &Infcx, + delegate: &D, max_input_universe: ty::UniverseIndex, impl_args: I::GenericArgs, ) { match self.as_mut() { Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { let impl_args = canonical::make_canonical_state( - infcx, + delegate, &state.var_values, max_input_universe, impl_args, @@ -538,7 +535,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { } } - pub fn finish_probe(mut self) -> ProofTreeBuilder<Infcx> { + pub fn finish_probe(mut self) -> ProofTreeBuilder<D> { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 02069016c2b..b76b4c09852 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -29,7 +29,7 @@ use rustc_type_ir::{self as ty, Interner}; use tracing::instrument; pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; /// How many fixpoint iterations we should attempt inside of the solver before bailing /// with overflow. @@ -56,9 +56,9 @@ fn has_no_inference_or_external_constraints<I: Interner>( && response.value.external_constraints.opaque_types.is_empty() } -impl<'a, Infcx, I> EvalCtxt<'a, Infcx> +impl<'a, D, I> EvalCtxt<'a, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { #[instrument(level = "trace", skip(self))] @@ -104,7 +104,7 @@ where } fn compute_object_safe_goal(&mut self, trait_def_id: I::DefId) -> QueryResult<I> { - if self.interner().trait_is_object_safe(trait_def_id) { + if self.cx().trait_is_object_safe(trait_def_id) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) @@ -182,7 +182,7 @@ where return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } ty::ConstKind::Unevaluated(uv) => { - self.interner().type_of(uv.def).instantiate(self.interner(), &uv.args) + self.cx().type_of(uv.def).instantiate(self.cx(), &uv.args) } ty::ConstKind::Expr(_) => unimplemented!( "`feature(generic_const_exprs)` is not supported in the new trait solver" @@ -193,7 +193,7 @@ where ty::ConstKind::Bound(_, _) => panic!("escaping bound vars in {:?}", ct), ty::ConstKind::Value(ty, _) => ty, ty::ConstKind::Placeholder(placeholder) => { - self.interner().find_const_ty_from_env(goal.param_env, placeholder) + self.cx().find_const_ty_from_env(goal.param_env, placeholder) } }; @@ -202,9 +202,9 @@ where } } -impl<Infcx, I> EvalCtxt<'_, Infcx> +impl<D, I> EvalCtxt<'_, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`. @@ -267,7 +267,7 @@ where if let ty::Alias(..) = ty.kind() { let normalized_ty = self.next_ty_infer(); let alias_relate_goal = Goal::new( - self.interner(), + self.cx(), param_env, ty::PredicateKind::AliasRelate( ty.into(), diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs index 0f1c1f13c16..5d5597429da 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs @@ -1,12 +1,12 @@ use rustc_type_ir::{self as ty, Interner}; use tracing::instrument; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; -impl<Infcx, I> EvalCtxt<'_, Infcx> +impl<D, I> EvalCtxt<'_, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { #[instrument(level = "trace", skip(self), ret)] diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 8436f3ad484..827fe5f2ca4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -7,19 +7,19 @@ use rustc_type_ir::{self as ty, Interner}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; -impl<Infcx, I> EvalCtxt<'_, Infcx> +impl<D, I> EvalCtxt<'_, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { pub(super) fn normalize_inherent_associated_type( &mut self, goal: Goal<I, ty::NormalizesTo<I>>, ) -> QueryResult<I> { - let tcx = self.interner(); + let tcx = self.cx(); let inherent = goal.predicate.alias.expect_ty(tcx); let impl_def_id = tcx.parent(inherent.def_id); diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index ebc83bef513..f58384d86cd 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -9,7 +9,7 @@ use rustc_type_ir::Upcast as _; use rustc_type_ir::{self as ty, Interner, NormalizesTo}; use tracing::instrument; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes}; use crate::solve::assembly::{self, Candidate}; use crate::solve::inspect::ProbeKind; @@ -18,9 +18,9 @@ use crate::solve::{ NoSolution, QueryResult, }; -impl<Infcx, I> EvalCtxt<'_, Infcx> +impl<D, I> EvalCtxt<'_, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { #[instrument(level = "trace", skip(self), ret)] @@ -48,7 +48,7 @@ where /// returns `NoSolution`. #[instrument(level = "trace", skip(self), ret)] fn normalize_at_least_one_step(&mut self, goal: Goal<I, NormalizesTo<I>>) -> QueryResult<I> { - match goal.predicate.alias.kind(self.interner()) { + match goal.predicate.alias.kind(self.cx()) { ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { let candidates = self.assemble_and_evaluate_candidates(goal); self.merge_candidates(candidates) @@ -75,9 +75,9 @@ where } } -impl<Infcx, I> assembly::GoalKind<Infcx> for NormalizesTo<I> +impl<D, I> assembly::GoalKind<D> for NormalizesTo<I> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { fn self_ty(self) -> I::Ty { @@ -97,15 +97,15 @@ where } fn probe_and_match_goal_against_assumption( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, source: CandidateSource<I>, goal: Goal<I, Self>, assumption: I::Clause, - then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>, + then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, ) -> Result<Candidate<I>, NoSolution> { if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { - let tcx = ecx.interner(); + let tcx = ecx.cx(); ecx.probe_trait_candidate(source).enter(|ecx| { let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred); @@ -136,15 +136,15 @@ where } fn consider_impl_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, NormalizesTo<I>>, impl_def_id: I::DefId, ) -> Result<Candidate<I>, NoSolution> { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let goal_trait_ref = goal.predicate.alias.trait_ref(tcx); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); - if !ecx.interner().args_may_unify_deep( + if !ecx.cx().args_may_unify_deep( goal.predicate.alias.trait_ref(tcx).args, impl_trait_ref.skip_binder().args, ) { @@ -194,7 +194,7 @@ where return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); }; - let error_response = |ecx: &mut EvalCtxt<'_, Infcx>, msg: &str| { + let error_response = |ecx: &mut EvalCtxt<'_, D>, msg: &str| { let guar = tcx.delay_bug(msg); let error_term = match goal.predicate.alias.kind(tcx) { ty::AliasTermKind::ProjectionTy => Ty::new_error(tcx, guar).into(), @@ -262,61 +262,61 @@ where /// Fail to normalize if the predicate contains an error, alternatively, we could normalize to `ty::Error` /// and succeed. Can experiment with this to figure out what results in better error messages. fn consider_error_guaranteed_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, _guar: I::ErrorGuaranteed, ) -> Result<Candidate<I>, NoSolution> { Err(NoSolution) } fn consider_auto_trait_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, _goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { - ecx.interner().delay_bug("associated types not allowed on auto traits"); + ecx.cx().delay_bug("associated types not allowed on auto traits"); Err(NoSolution) } fn consider_trait_alias_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { panic!("trait aliases do not have associated types: {:?}", goal); } fn consider_builtin_sized_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { panic!("`Sized` does not have an associated type: {:?}", goal); } fn consider_builtin_copy_clone_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal); } fn consider_builtin_pointer_like_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { panic!("`PointerLike` does not have an associated type: {:?}", goal); } fn consider_builtin_fn_ptr_trait_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { panic!("`FnPtr` does not have an associated type: {:?}", goal); } fn consider_builtin_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, goal_kind: ty::ClosureKind, ) -> Result<Candidate<I>, NoSolution> { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( tcx, @@ -355,11 +355,11 @@ where } fn consider_builtin_async_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, goal_kind: ty::ClosureKind, ) -> Result<Candidate<I>, NoSolution> { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let env_region = match goal_kind { ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2), @@ -457,7 +457,7 @@ where } fn consider_builtin_async_fn_kind_helper_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { let [ @@ -489,7 +489,7 @@ where } let upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( - ecx.interner(), + ecx.cx(), goal_kind, tupled_inputs_ty.expect_ty(), tupled_upvars_ty.expect_ty(), @@ -504,17 +504,17 @@ where } fn consider_builtin_tuple_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { panic!("`Tuple` does not have an associated type: {:?}", goal); } fn consider_builtin_pointee_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let metadata_def_id = tcx.require_lang_item(TraitSolverLangItem::Metadata); assert_eq!(metadata_def_id, goal.predicate.def_id()); ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { @@ -592,7 +592,7 @@ where } fn consider_builtin_future_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -601,7 +601,7 @@ where }; // Coroutines are not futures unless they come from `async` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_async(def_id) { return Err(NoSolution); } @@ -613,11 +613,7 @@ where CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, ty::ProjectionPredicate { - projection_term: ty::AliasTerm::new( - ecx.interner(), - goal.predicate.def_id(), - [self_ty], - ), + projection_term: ty::AliasTerm::new(ecx.cx(), goal.predicate.def_id(), [self_ty]), term, } .upcast(tcx), @@ -628,7 +624,7 @@ where } fn consider_builtin_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -637,7 +633,7 @@ where }; // Coroutines are not Iterators unless they come from `gen` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -649,11 +645,7 @@ where CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, ty::ProjectionPredicate { - projection_term: ty::AliasTerm::new( - ecx.interner(), - goal.predicate.def_id(), - [self_ty], - ), + projection_term: ty::AliasTerm::new(ecx.cx(), goal.predicate.def_id(), [self_ty]), term, } .upcast(tcx), @@ -664,14 +656,14 @@ where } fn consider_builtin_fused_iterator_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { panic!("`FusedIterator` does not have an associated type: {:?}", goal); } fn consider_builtin_async_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -680,7 +672,7 @@ where }; // Coroutines are not AsyncIterators unless they come from `gen` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_async_gen(def_id) { return Err(NoSolution); } @@ -707,7 +699,7 @@ where } fn consider_builtin_coroutine_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -716,7 +708,7 @@ where }; // `async`-desugared coroutines do not implement the coroutine trait - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.is_general_coroutine(def_id) { return Err(NoSolution); } @@ -739,7 +731,7 @@ where goal, ty::ProjectionPredicate { projection_term: ty::AliasTerm::new( - ecx.interner(), + ecx.cx(), goal.predicate.def_id(), [self_ty, coroutine.resume_ty()], ), @@ -753,14 +745,14 @@ where } fn consider_structural_builtin_unsize_candidates( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Vec<Candidate<I>> { panic!("`Unsize` does not have an associated type: {:?}", goal); } fn consider_builtin_discriminant_kind_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -788,7 +780,7 @@ where | ty::Slice(_) | ty::Dynamic(_, _, _) | ty::Tuple(_) - | ty::Error(_) => self_ty.discriminant_ty(ecx.interner()), + | ty::Error(_) => self_ty.discriminant_ty(ecx.cx()), // We do not call `Ty::discriminant_ty` on alias, param, or placeholder // types, which return `<self_ty as DiscriminantKind>::Discriminant` @@ -812,7 +804,7 @@ where } fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -835,7 +827,7 @@ where | ty::Str | ty::Slice(_) | ty::Tuple(_) - | ty::Error(_) => self_ty.async_destructor_ty(ecx.interner()), + | ty::Error(_) => self_ty.async_destructor_ty(ecx.cx()), // We do not call `Ty::async_destructor_ty` on alias, param, or placeholder // types, which return `<self_ty as AsyncDestruct>::AsyncDestructor` @@ -865,23 +857,23 @@ where } fn consider_builtin_destruct_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { panic!("`Destruct` does not have an associated type: {:?}", goal); } fn consider_builtin_transmute_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { panic!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) } } -impl<Infcx, I> EvalCtxt<'_, Infcx> +impl<D, I> EvalCtxt<'_, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { fn translate_args( @@ -892,7 +884,7 @@ where impl_trait_ref: rustc_type_ir::TraitRef<I>, target_container_def_id: I::DefId, ) -> Result<I::GenericArgs, NoSolution> { - let tcx = self.interner(); + let tcx = self.cx(); Ok(if target_container_def_id == impl_trait_ref.def_id { // Default value from the trait definition. No need to rebase. goal.predicate.alias.args diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index 710671b45d0..f3494328d9e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -6,19 +6,19 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_type_ir::inherent::*; use rustc_type_ir::{self as ty, Interner}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, Reveal, SolverMode}; -impl<Infcx, I> EvalCtxt<'_, Infcx> +impl<D, I> EvalCtxt<'_, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { pub(super) fn normalize_opaque_type( &mut self, goal: Goal<I, ty::NormalizesTo<I>>, ) -> QueryResult<I> { - let tcx = self.interner(); + let tcx = self.cx(); let opaque_ty = goal.predicate.alias; let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const"); @@ -34,7 +34,7 @@ where return Err(NoSolution); } // FIXME: This may have issues when the args contain aliases... - match uses_unique_placeholders_ignoring_regions(self.interner(), opaque_ty.args) { + match uses_unique_placeholders_ignoring_regions(self.cx(), opaque_ty.args) { Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { return self.evaluate_added_goals_and_make_canonical_response( Certainty::AMBIGUOUS, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs index 45341917bb2..27d5ae07729 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs @@ -6,19 +6,19 @@ use rustc_type_ir::{self as ty, Interner}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; -impl<Infcx, I> EvalCtxt<'_, Infcx> +impl<D, I> EvalCtxt<'_, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { pub(super) fn normalize_weak_type( &mut self, goal: Goal<I, ty::NormalizesTo<I>>, ) -> QueryResult<I> { - let tcx = self.interner(); + let tcx = self.cx(); let weak_ty = goal.predicate.alias; // Check where clauses diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs index 4bb1fe5be6f..a430dbb408c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs @@ -1,12 +1,12 @@ use rustc_type_ir::{self as ty, Interner, ProjectionPredicate}; use tracing::instrument; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; -impl<Infcx, I> EvalCtxt<'_, Infcx> +impl<D, I> EvalCtxt<'_, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { #[instrument(level = "trace", skip(self), ret)] @@ -14,7 +14,7 @@ where &mut self, goal: Goal<I, ProjectionPredicate<I>>, ) -> QueryResult<I> { - let tcx = self.interner(); + let tcx = self.cx(); let projection_term = goal.predicate.projection_term.to_term(tcx); let goal = goal.with( tcx, diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index b923a121d81..d3ad55d6491 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -1,12 +1,12 @@ use std::mem; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::{Idx, IndexVec}; +use rustc_type_ir::data_structures::{HashMap, HashSet}; use rustc_type_ir::inherent::*; use rustc_type_ir::Interner; use tracing::debug; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::{ CacheData, CanonicalInput, Certainty, QueryResult, SolverMode, FIXPOINT_STEP_LIMIT, @@ -17,6 +17,7 @@ pub struct SolverLimit(usize); rustc_index::newtype_index! { #[orderable] + #[gate_rustc_only] pub struct StackDepth {} } @@ -70,7 +71,7 @@ struct StackEntry<I: Interner> { /// C :- D /// D :- C /// ``` - cycle_participants: FxHashSet<CanonicalInput<I>>, + cycle_participants: HashSet<CanonicalInput<I>>, /// Starts out as `None` and gets set when rerunning this /// goal in case we encounter a cycle. provisional_result: Option<QueryResult<I>>, @@ -126,7 +127,7 @@ pub(super) struct SearchGraph<I: Interner> { /// /// An element is *deeper* in the stack if its index is *lower*. stack: IndexVec<StackDepth, StackEntry<I>>, - provisional_cache: FxHashMap<CanonicalInput<I>, ProvisionalCacheEntry<I>>, + provisional_cache: HashMap<CanonicalInput<I>, ProvisionalCacheEntry<I>>, } impl<I: Interner> SearchGraph<I> { @@ -227,13 +228,17 @@ impl<I: Interner> SearchGraph<I> { } fn clear_dependent_provisional_results( - provisional_cache: &mut FxHashMap<CanonicalInput<I>, ProvisionalCacheEntry<I>>, + provisional_cache: &mut HashMap<CanonicalInput<I>, ProvisionalCacheEntry<I>>, head: StackDepth, ) { #[allow(rustc::potential_query_instability)] provisional_cache.retain(|_, entry| { - entry.with_coinductive_stack.take_if(|p| p.head == head); - entry.with_inductive_stack.take_if(|p| p.head == head); + if entry.with_coinductive_stack.as_ref().is_some_and(|p| p.head == head) { + entry.with_coinductive_stack.take(); + } + if entry.with_inductive_stack.as_ref().is_some_and(|p| p.head == head) { + entry.with_inductive_stack.take(); + } !entry.is_empty() }); } @@ -250,12 +255,12 @@ impl<I: Interner> SearchGraph<I> { /// /// Given some goal which is proven via the `prove_goal` closure, this /// handles caching, overflow, and coinductive cycles. - pub(super) fn with_new_goal<Infcx: SolverDelegate<Interner = I>>( + pub(super) fn with_new_goal<D: SolverDelegate<Interner = I>>( &mut self, tcx: I, input: CanonicalInput<I>, - inspect: &mut ProofTreeBuilder<Infcx>, - mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder<Infcx>) -> QueryResult<I>, + inspect: &mut ProofTreeBuilder<D>, + mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder<D>) -> QueryResult<I>, ) -> QueryResult<I> { self.check_invariants(); // Check for overflow. @@ -411,12 +416,12 @@ impl<I: Interner> SearchGraph<I> { /// Try to fetch a previously computed result from the global cache, /// making sure to only do so if it would match the result of reevaluating /// this goal. - fn lookup_global_cache<Infcx: SolverDelegate<Interner = I>>( + fn lookup_global_cache<D: SolverDelegate<Interner = I>>( &mut self, tcx: I, input: CanonicalInput<I>, available_depth: SolverLimit, - inspect: &mut ProofTreeBuilder<Infcx>, + inspect: &mut ProofTreeBuilder<D>, ) -> Option<QueryResult<I>> { let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self .global_cache(tcx) @@ -460,16 +465,16 @@ impl<I: Interner> SearchGraph<I> { /// of this we continuously recompute the cycle until the result /// of the previous iteration is equal to the final result, at which /// point we are done. - fn fixpoint_step_in_task<Infcx, F>( + fn fixpoint_step_in_task<D, F>( &mut self, tcx: I, input: CanonicalInput<I>, - inspect: &mut ProofTreeBuilder<Infcx>, + inspect: &mut ProofTreeBuilder<D>, prove_goal: &mut F, ) -> StepResult<I> where - Infcx: SolverDelegate<Interner = I>, - F: FnMut(&mut Self, &mut ProofTreeBuilder<Infcx>) -> QueryResult<I>, + D: SolverDelegate<Interner = I>, + F: FnMut(&mut Self, &mut ProofTreeBuilder<D>) -> QueryResult<I>, { let result = prove_goal(self, inspect); let stack_entry = self.pop_stack(); diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index d1419bf5db9..2ddb3c981db 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1,14 +1,14 @@ //! Dealing with trait goals, i.e. `T: Trait<'a, U>`. use rustc_ast_ir::Movability; -use rustc_data_structures::fx::FxIndexSet; +use rustc_type_ir::data_structures::IndexSet; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::visit::TypeVisitableExt as _; use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _}; use tracing::{instrument, trace}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes}; use crate::solve::assembly::{self, Candidate}; use crate::solve::inspect::ProbeKind; @@ -17,9 +17,9 @@ use crate::solve::{ NoSolution, QueryResult, Reveal, SolverMode, }; -impl<Infcx, I> assembly::GoalKind<Infcx> for TraitPredicate<I> +impl<D, I> assembly::GoalKind<D> for TraitPredicate<I> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { fn self_ty(self) -> I::Ty { @@ -39,11 +39,11 @@ where } fn consider_impl_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, TraitPredicate<I>>, impl_def_id: I::DefId, ) -> Result<Candidate<I>, NoSolution> { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); if !tcx @@ -91,7 +91,7 @@ where } fn consider_error_guaranteed_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, _guar: I::ErrorGuaranteed, ) -> Result<Candidate<I>, NoSolution> { // FIXME: don't need to enter a probe here. @@ -100,11 +100,11 @@ where } fn probe_and_match_goal_against_assumption( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, source: CandidateSource<I>, goal: Goal<I, Self>, assumption: I::Clause, - then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>, + then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, ) -> Result<Candidate<I>, NoSolution> { if let Some(trait_clause) = assumption.as_trait_clause() { if trait_clause.def_id() == goal.predicate.def_id() @@ -128,7 +128,7 @@ where } fn consider_auto_trait_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -174,14 +174,14 @@ where } fn consider_trait_alias_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - let tcx = ecx.interner(); + let tcx = ecx.cx(); ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let nested_obligations = tcx @@ -195,7 +195,7 @@ where } fn consider_builtin_sized_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -210,7 +210,7 @@ where } fn consider_builtin_copy_clone_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -225,14 +225,14 @@ where } fn consider_builtin_pointer_like_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - let tcx = ecx.interner(); + let tcx = ecx.cx(); // But if there are inference variables, we have to wait until it's resolved. if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() { return ecx.forced_ambiguity(MaybeCause::Ambiguity); @@ -247,7 +247,7 @@ where } fn consider_builtin_fn_ptr_trait_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -278,7 +278,7 @@ where } fn consider_builtin_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, goal_kind: ty::ClosureKind, ) -> Result<Candidate<I>, NoSolution> { @@ -286,7 +286,7 @@ where return Err(NoSolution); } - let tcx = ecx.interner(); + let tcx = ecx.cx(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( tcx, @@ -319,7 +319,7 @@ where } fn consider_builtin_async_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, goal_kind: ty::ClosureKind, ) -> Result<Candidate<I>, NoSolution> { @@ -327,7 +327,7 @@ where return Err(NoSolution); } - let tcx = ecx.interner(); + let tcx = ecx.cx(); let (tupled_inputs_and_output_and_coroutine, nested_preds) = structural_traits::extract_tupled_inputs_and_output_from_async_callable( tcx, @@ -370,7 +370,7 @@ where } fn consider_builtin_async_fn_kind_helper_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else { @@ -397,7 +397,7 @@ where /// impl Tuple for (T1, .., Tn) {} /// ``` fn consider_builtin_tuple_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -413,7 +413,7 @@ where } fn consider_builtin_pointee_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -425,7 +425,7 @@ where } fn consider_builtin_future_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -437,7 +437,7 @@ where }; // Coroutines are not futures unless they come from `async` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_async(def_id) { return Err(NoSolution); } @@ -451,7 +451,7 @@ where } fn consider_builtin_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -463,7 +463,7 @@ where }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -477,7 +477,7 @@ where } fn consider_builtin_fused_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -489,7 +489,7 @@ where }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -501,7 +501,7 @@ where } fn consider_builtin_async_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -513,7 +513,7 @@ where }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_async_gen(def_id) { return Err(NoSolution); } @@ -527,7 +527,7 @@ where } fn consider_builtin_coroutine_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -540,7 +540,7 @@ where }; // `async`-desugared coroutines do not implement the coroutine trait - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.is_general_coroutine(def_id) { return Err(NoSolution); } @@ -559,7 +559,7 @@ where } fn consider_builtin_discriminant_kind_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -572,7 +572,7 @@ where } fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -585,7 +585,7 @@ where } fn consider_builtin_destruct_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -601,7 +601,7 @@ where } fn consider_builtin_transmute_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -634,7 +634,7 @@ where /// impl<'a, T: Trait + 'a> Unsize<dyn Trait + 'a> for T {} /// ``` fn consider_structural_builtin_unsize_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Vec<Candidate<I>> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -657,7 +657,7 @@ where return vec![]; }; - let goal = goal.with(ecx.interner(), (a_ty, b_ty)); + let goal = goal.with(ecx.cx(), (a_ty, b_ty)); match (a_ty.kind(), b_ty.kind()) { (ty::Infer(ty::TyVar(..)), ..) => panic!("unexpected infer {a_ty:?} {b_ty:?}"), @@ -705,9 +705,9 @@ where } } -impl<Infcx, I> EvalCtxt<'_, Infcx> +impl<D, I> EvalCtxt<'_, D> where - Infcx: SolverDelegate<Interner = I>, + D: SolverDelegate<Interner = I>, I: Interner, { /// Trait upcasting allows for coercions between trait objects: @@ -727,7 +727,7 @@ where b_data: I::BoundExistentialPredicates, b_region: I::Region, ) -> Vec<Candidate<I>> { - let tcx = self.interner(); + let tcx = self.cx(); let Goal { predicate: (a_ty, _b_ty), .. } = goal; let mut responses = vec![]; @@ -745,8 +745,7 @@ where )); } else if let Some(a_principal) = a_data.principal() { for new_a_principal in - Infcx::elaborate_supertraits(self.interner(), a_principal.with_self_ty(tcx, a_ty)) - .skip(1) + D::elaborate_supertraits(self.cx(), a_principal.with_self_ty(tcx, a_ty)).skip(1) { responses.extend(self.consider_builtin_upcast_to_principal( goal, @@ -771,7 +770,7 @@ where b_data: I::BoundExistentialPredicates, b_region: I::Region, ) -> Result<Candidate<I>, NoSolution> { - let tcx = self.interner(); + let tcx = self.cx(); let Goal { predicate: (a_ty, _), .. } = goal; // Can only unsize to an object-safe trait. @@ -821,14 +820,14 @@ where // We may upcast to auto traits that are either explicitly listed in // the object type's bounds, or implied by the principal trait ref's // supertraits. - let a_auto_traits: FxIndexSet<I::DefId> = a_data + let a_auto_traits: IndexSet<I::DefId> = a_data .auto_traits() .into_iter() .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { - self.interner() + self.cx() .supertrait_def_ids(principal_def_id) .into_iter() - .filter(|def_id| self.interner().trait_is_auto(*def_id)) + .filter(|def_id| self.cx().trait_is_auto(*def_id)) })) .collect(); @@ -837,7 +836,7 @@ where // having any inference side-effects. We process obligations because // unification may initially succeed due to deferred projection equality. let projection_may_match = - |ecx: &mut EvalCtxt<'_, Infcx>, + |ecx: &mut EvalCtxt<'_, D>, source_projection: ty::Binder<I, ty::ExistentialProjection<I>>, target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| { source_projection.item_def_id() == target_projection.item_def_id() @@ -896,7 +895,7 @@ where // Also require that a_ty's lifetime outlives b_ty's lifetime. ecx.add_goal( GoalSource::ImplWhereBound, - Goal::new(ecx.interner(), param_env, ty::OutlivesPredicate(a_region, b_region)), + Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)), ); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) @@ -942,7 +941,7 @@ where a_args: I::GenericArgs, b_args: I::GenericArgs, ) -> Result<Candidate<I>, NoSolution> { - let tcx = self.interner(); + let tcx = self.cx(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; let unsizing_params = tcx.unsizing_params_for_adt(def.def_id()); @@ -1002,7 +1001,7 @@ where a_tys: I::Tys, b_tys: I::Tys, ) -> Result<Candidate<I>, NoSolution> { - let tcx = self.interner(); + let tcx = self.cx(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; let (&a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); @@ -1062,11 +1061,9 @@ where // takes precedence over the structural auto trait candidate being // assembled. ty::Coroutine(def_id, _) - if self - .interner() - .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) => + if self.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) => { - match self.interner().coroutine_movability(def_id) { + match self.cx().coroutine_movability(def_id) { Movability::Static => Some(Err(NoSolution)), Movability::Movable => Some( self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { @@ -1111,7 +1108,7 @@ where | ty::Tuple(_) | ty::Adt(_, _) => { let mut disqualifying_impl = None; - self.interner().for_each_relevant_impl( + self.cx().for_each_relevant_impl( goal.predicate.def_id(), goal.predicate.self_ty(), |impl_def_id| { @@ -1140,7 +1137,7 @@ where source: CandidateSource<I>, goal: Goal<I, TraitPredicate<I>>, constituent_tys: impl Fn( - &EvalCtxt<'_, Infcx>, + &EvalCtxt<'_, D>, I::Ty, ) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>, ) -> Result<Candidate<I>, NoSolution> { @@ -1151,10 +1148,7 @@ where .into_iter() .map(|ty| { ecx.enter_forall(ty, |ty| { - goal.with( - ecx.interner(), - goal.predicate.with_self_ty(ecx.interner(), ty), - ) + goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty)) }) }) .collect::<Vec<_>>(), diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c2b91488a11..81d5f0fca0e 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2965,9 +2965,10 @@ impl<'a> Parser<'a> { /// This checks if this is a conflict marker, depending of the parameter passed. /// - /// * `>>>>>` - /// * `=====` - /// * `<<<<<` + /// * `<<<<<<<` + /// * `|||||||` + /// * `=======` + /// * `>>>>>>>` /// pub(super) fn is_vcs_conflict_marker( &mut self, @@ -2997,14 +2998,18 @@ impl<'a> Parser<'a> { } pub(crate) fn err_vcs_conflict_marker(&mut self) -> PResult<'a, ()> { + // <<<<<<< let Some(start) = self.conflict_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) else { return Ok(()); }; let mut spans = Vec::with_capacity(3); spans.push(start); + // ||||||| let mut middlediff3 = None; + // ======= let mut middle = None; + // >>>>>>> let mut end = None; loop { if self.token.kind == TokenKind::Eof { @@ -3025,29 +3030,50 @@ impl<'a> Parser<'a> { } self.bump(); } + let mut err = self.dcx().struct_span_err(spans, "encountered diff marker"); - err.span_label(start, "after this is the code before the merge"); - if let Some(middle) = middlediff3 { - err.span_label(middle, ""); - } + match middlediff3 { + // We're using diff3 + Some(middlediff3) => { + err.span_label( + start, + "between this marker and `|||||||` is the code that we're merging into", + ); + err.span_label(middlediff3, "between this marker and `=======` is the base code (what the two refs diverged from)"); + } + None => { + err.span_label( + start, + "between this marker and `=======` is the code that we're merging into", + ); + } + }; + if let Some(middle) = middle { - err.span_label(middle, ""); + err.span_label(middle, "between this marker and `>>>>>>>` is the incoming code"); } if let Some(end) = end { - err.span_label(end, "above this are the incoming code changes"); + err.span_label(end, "this marker concludes the conflict region"); } - err.help( - "if you're having merge conflicts after pulling new code, the top section is the code \ - you already had and the bottom section is the remote code", + err.note( + "conflict markers indicate that a merge was started but could not be completed due \ + to merge conflicts\n\ + to resolve a conflict, keep only the code you want and then delete the lines \ + containing conflict markers", ); err.help( - "if you're in the middle of a rebase, the top section is the code being rebased onto \ - and the bottom section is the code coming from the current commit being rebased", + "if you're having merge conflicts after pulling new code:\n\ + the top section is the code you already had and the bottom section is the remote code\n\ + if you're in the middle of a rebase:\n\ + the top section is the code being rebased onto and the bottom section is the code \ + coming from the current commit being rebased", ); + err.note( - "for an explanation on these markers from the `git` documentation, visit \ - <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>", + "for an explanation on these markers from the `git` documentation:\n\ + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>", ); + Err(err) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 09f706143fa..9fad954adda 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,4 +1,5 @@ // ignore-tidy-filelength + use super::diagnostics::SnapshotParser; use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 2db777a9f70..abb6b51cebd 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1228,7 +1228,7 @@ impl<'a> Parser<'a> { ident_span: ident.span, const_span, }); - ForeignItemKind::Static(Box::new(StaticForeignItem { + ForeignItemKind::Static(Box::new(StaticItem { ty, mutability: Mutability::Not, expr, @@ -1259,7 +1259,7 @@ impl<'a> Parser<'a> { self.token.is_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Extern]) && self.look_ahead( - 2 + self.look_ahead(2, |t| t.can_begin_literal_maybe_minus() as usize), + 2 + self.look_ahead(2, |t| t.can_begin_string_literal() as usize), |t| t.kind == token::OpenDelim(Delimiter::Brace), ) } @@ -2448,7 +2448,7 @@ impl<'a> Parser<'a> { }) // `extern ABI fn` || self.check_keyword_case(kw::Extern, case) - && self.look_ahead(1, |t| t.can_begin_literal_maybe_minus()) + && self.look_ahead(1, |t| t.can_begin_string_literal()) && (self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case)) || // this branch is only for better diagnostic in later, `pub` is not allowed here (self.may_recover() diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 2f12459da57..cfd0a72c056 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1214,6 +1214,9 @@ impl<'a> Parser<'a> { if self.eat_keyword_case(kw::Unsafe, case) { Safety::Unsafe(self.prev_token.uninterpolated_span()) } else if self.eat_keyword_case(kw::Safe, case) { + self.psess + .gated_spans + .gate(sym::unsafe_extern_blocks, self.prev_token.uninterpolated_span()); Safety::Safe(self.prev_token.uninterpolated_span()) } else { Safety::Default diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index a0b704aeea5..59f6eff07b3 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -36,7 +36,7 @@ impl<'a> Parser<'a> { } match kind { - NonterminalKind::Expr2021 => { + NonterminalKind::Expr2021 { inferred: _ } => { token.can_begin_expr() // This exception is here for backwards compatibility. && !token.is_keyword(kw::Let) @@ -47,7 +47,6 @@ impl<'a> Parser<'a> { token.can_begin_expr() // This exception is here for backwards compatibility. && !token.is_keyword(kw::Let) - && (!token.is_keyword(kw::Const) || token.span.edition().at_least_rust_2024()) } NonterminalKind::Ty => token.can_begin_type(), NonterminalKind::Ident => get_macro_ident(token).is_some(), @@ -149,7 +148,7 @@ impl<'a> Parser<'a> { })?) } - NonterminalKind::Expr | NonterminalKind::Expr2021 => { + NonterminalKind::Expr | NonterminalKind::Expr2021 { inferred: _ } => { NtExpr(self.parse_expr_force_collect()?) } NonterminalKind::Literal => { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 03aea0888d9..6f2b7177159 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -939,7 +939,8 @@ impl<'a> Parser<'a> { || self.look_ahead(dist, |t| { t.is_path_start() // e.g. `MY_CONST`; || t.kind == token::Dot // e.g. `.5` for recovery; - || t.can_begin_literal_maybe_minus() // e.g. `42`. + || matches!(t.kind, token::Literal(..) | token::BinOp(token::Minus)) + || t.is_bool_lit() || t.is_whole_expr() || t.is_lifetime() // recover `'a` instead of `'a'` || (self.may_recover() // recover leading `(` diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 84dbd192723..84c71c4bed2 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -14,7 +14,7 @@ passes_abi_of = fn_abi_of({$fn_name}) = {$fn_abi} passes_allow_incoherent_impl = - `rustc_allow_incoherent_impl` attribute should be applied to impl items. + `rustc_allow_incoherent_impl` attribute should be applied to impl items .label = the only currently supported targets are inherent methods passes_allow_internal_unstable = @@ -253,8 +253,8 @@ passes_doc_test_unknown_spotlight = .no_op_note = `doc(spotlight)` is now a no-op passes_duplicate_diagnostic_item_in_crate = - duplicate diagnostic item in crate `{$crate_name}`: `{$name}`. - .note = the diagnostic item is first defined in crate `{$orig_crate_name}`. + duplicate diagnostic item in crate `{$crate_name}`: `{$name}` + .note = the diagnostic item is first defined in crate `{$orig_crate_name}` passes_duplicate_feature_err = the feature `{$feature}` has already been declared @@ -263,27 +263,27 @@ passes_duplicate_lang_item = found duplicate lang item `{$lang_item_name}` .first_defined_span = the lang item is first defined here .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) - .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. + .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}` .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) .second_definition_local = second definition in the local crate (`{$crate_name}`) .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} passes_duplicate_lang_item_crate = - duplicate lang item in crate `{$crate_name}`: `{$lang_item_name}`. + duplicate lang item in crate `{$crate_name}`: `{$lang_item_name}` .first_defined_span = the lang item is first defined here .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) - .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. + .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}` .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) .second_definition_local = second definition in the local crate (`{$crate_name}`) .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} passes_duplicate_lang_item_crate_depends = - duplicate lang item in crate `{$crate_name}` (which `{$dependency_of}` depends on): `{$lang_item_name}`. + duplicate lang item in crate `{$crate_name}` (which `{$dependency_of}` depends on): `{$lang_item_name}` .first_defined_span = the lang item is first defined here .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) - .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. + .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}` .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) .second_definition_local = second definition in the local crate (`{$crate_name}`) .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} @@ -315,7 +315,7 @@ passes_ffi_pure_invalid_target = `#[ffi_pure]` may only be used on foreign functions passes_has_incoherent_inherent_impl = - `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. + `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits .label = only adts, extern types and traits are supported passes_ignored_attr = diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 44f09b66bf6..fb103705475 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -182,7 +182,7 @@ use std::iter::once; use smallvec::SmallVec; -use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS}; +use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, SingleS}; use rustc_index::bit_set::{BitSet, GrowableBitSet}; use rustc_index::IndexVec; @@ -692,8 +692,10 @@ pub enum Constructor<Cx: PatCx> { /// Ranges of integer literal values (`2`, `2..=5` or `2..5`). IntRange(IntRange), /// Ranges of floating-point literal values (`2.0..=5.2`). + F16Range(IeeeFloat<HalfS>, IeeeFloat<HalfS>, RangeEnd), F32Range(IeeeFloat<SingleS>, IeeeFloat<SingleS>, RangeEnd), F64Range(IeeeFloat<DoubleS>, IeeeFloat<DoubleS>, RangeEnd), + F128Range(IeeeFloat<QuadS>, IeeeFloat<QuadS>, RangeEnd), /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. Str(Cx::StrLit), /// Constants that must not be matched structurally. They are treated as black boxes for the @@ -735,8 +737,10 @@ impl<Cx: PatCx> Clone for Constructor<Cx> { Constructor::UnionField => Constructor::UnionField, Constructor::Bool(b) => Constructor::Bool(*b), Constructor::IntRange(range) => Constructor::IntRange(*range), + Constructor::F16Range(lo, hi, end) => Constructor::F16Range(lo.clone(), *hi, *end), Constructor::F32Range(lo, hi, end) => Constructor::F32Range(lo.clone(), *hi, *end), Constructor::F64Range(lo, hi, end) => Constructor::F64Range(lo.clone(), *hi, *end), + Constructor::F128Range(lo, hi, end) => Constructor::F128Range(lo.clone(), *hi, *end), Constructor::Str(value) => Constructor::Str(value.clone()), Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()), Constructor::Or => Constructor::Or, @@ -812,6 +816,14 @@ impl<Cx: PatCx> Constructor<Cx> { (Bool(self_b), Bool(other_b)) => self_b == other_b, (IntRange(self_range), IntRange(other_range)) => self_range.is_subrange(other_range), + (F16Range(self_from, self_to, self_end), F16Range(other_from, other_to, other_end)) => { + self_from.ge(other_from) + && match self_to.partial_cmp(other_to) { + Some(Ordering::Less) => true, + Some(Ordering::Equal) => other_end == self_end, + _ => false, + } + } (F32Range(self_from, self_to, self_end), F32Range(other_from, other_to, other_end)) => { self_from.ge(other_from) && match self_to.partial_cmp(other_to) { @@ -828,6 +840,17 @@ impl<Cx: PatCx> Constructor<Cx> { _ => false, } } + ( + F128Range(self_from, self_to, self_end), + F128Range(other_from, other_to, other_end), + ) => { + self_from.ge(other_from) + && match self_to.partial_cmp(other_to) { + Some(Ordering::Less) => true, + Some(Ordering::Equal) => other_end == self_end, + _ => false, + } + } (Str(self_val), Str(other_val)) => { // FIXME Once valtrees are available we can directly use the bytes // in the `Str` variant of the valtree for the comparison here. @@ -906,8 +929,10 @@ impl<Cx: PatCx> Constructor<Cx> { Bool(b) => write!(f, "{b}")?, // Best-effort, will render signed ranges incorrectly IntRange(range) => write!(f, "{range:?}")?, + F16Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, + F128Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, Str(value) => write!(f, "{value:?}")?, Opaque(..) => write!(f, "<constant pattern>")?, Or => { diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index 5f388ee9f89..5e75976621e 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -1,5 +1,6 @@ //! As explained in [`crate::usefulness`], values and patterns are made from constructors applied to //! fields. This file defines types that represent patterns in this way. + use std::fmt; use smallvec::{smallvec, SmallVec}; diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 8391c694c64..d4dd4dd858c 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -247,8 +247,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } _ => bug!("bad slice pattern {:?} {:?}", ctor, ty), }, - Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => &[], + Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) + | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing + | PrivateUninhabited | Wildcard => &[], Or => { bug!("called `Fields::wildcards` on an `Or` ctor") } @@ -275,8 +276,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { }, Ref => 1, Slice(slice) => slice.arity(), - Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => 0, + Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) + | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing + | PrivateUninhabited | Wildcard => 0, Or => bug!("The `Or` constructor doesn't have a fixed arity"), } } @@ -546,6 +548,18 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { fields = vec![]; arity = 0; } + ty::Float(ty::FloatTy::F16) => { + ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { + Some(bits) => { + use rustc_apfloat::Float; + let value = rustc_apfloat::ieee::Half::from_bits(bits); + F16Range(value, value, RangeEnd::Included) + } + None => Opaque(OpaqueId::new()), + }; + fields = vec![]; + arity = 0; + } ty::Float(ty::FloatTy::F32) => { ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { Some(bits) => { @@ -570,6 +584,18 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { fields = vec![]; arity = 0; } + ty::Float(ty::FloatTy::F128) => { + ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { + Some(bits) => { + use rustc_apfloat::Float; + let value = rustc_apfloat::ieee::Quad::from_bits(bits); + F128Range(value, value, RangeEnd::Included) + } + None => Opaque(OpaqueId::new()), + }; + fields = vec![]; + arity = 0; + } ty::Ref(_, t, _) if t.is_str() => { // We want a `&str` constant to behave like a `Deref` pattern, to be compatible // with other `Deref` patterns. This could have been done in `const_to_pat`, @@ -611,7 +637,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let lo = lo.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env)); let hi = hi.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env)); match fty { - ty::FloatTy::F16 => unimplemented!("f16_f128"), + ty::FloatTy::F16 => { + use rustc_apfloat::ieee::Half; + let lo = lo.map(Half::from_bits).unwrap_or(-Half::INFINITY); + let hi = hi.map(Half::from_bits).unwrap_or(Half::INFINITY); + F16Range(lo, hi, end) + } ty::FloatTy::F32 => { use rustc_apfloat::ieee::Single; let lo = lo.map(Single::from_bits).unwrap_or(-Single::INFINITY); @@ -624,7 +655,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let hi = hi.map(Double::from_bits).unwrap_or(Double::INFINITY); F64Range(lo, hi, end) } - ty::FloatTy::F128 => unimplemented!("f16_f128"), + ty::FloatTy::F128 => { + use rustc_apfloat::ieee::Quad; + let lo = lo.map(Quad::from_bits).unwrap_or(-Quad::INFINITY); + let hi = hi.map(Quad::from_bits).unwrap_or(Quad::INFINITY); + F128Range(lo, hi, end) + } } } _ => bug!("invalid type for range pattern: {}", ty.inner()), @@ -837,7 +873,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, `Missing` should have been processed in `apply_constructors`" ), - F32Range(..) | F64Range(..) | Opaque(..) | Or => { + F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Opaque(..) | Or => { bug!("can't convert to pattern: {:?}", pat) } }; diff --git a/compiler/rustc_pattern_analysis/tests/complexity.rs b/compiler/rustc_pattern_analysis/tests/complexity.rs index 93f455c6257..19242d44e35 100644 --- a/compiler/rustc_pattern_analysis/tests/complexity.rs +++ b/compiler/rustc_pattern_analysis/tests/complexity.rs @@ -1,4 +1,5 @@ //! Test the pattern complexity limit. + use common::*; use rustc_pattern_analysis::{pat::DeconstructedPat, usefulness::PlaceValidity, MatchArm}; diff --git a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs index 4c6c72fa8ec..4f8d68d5514 100644 --- a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs +++ b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs @@ -1,4 +1,5 @@ //! Test exhaustiveness checking. + use common::*; use rustc_pattern_analysis::{ pat::{DeconstructedPat, WitnessPat}, diff --git a/compiler/rustc_pattern_analysis/tests/intersection.rs b/compiler/rustc_pattern_analysis/tests/intersection.rs index 4d8a21506d7..4a96b7248da 100644 --- a/compiler/rustc_pattern_analysis/tests/intersection.rs +++ b/compiler/rustc_pattern_analysis/tests/intersection.rs @@ -1,4 +1,5 @@ //! Test the computation of arm intersections. + use common::*; use rustc_pattern_analysis::{pat::DeconstructedPat, usefulness::PlaceValidity, MatchArm}; diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index cbd80295887..cfb25ec905f 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -51,20 +51,24 @@ pub trait DepContext: Copy { } /// Try to force a dep node to execute and see if it's green. + /// + /// Returns true if the query has actually been forced. It is valid that a query + /// fails to be forced, e.g. when the query key cannot be reconstructed from the + /// dep-node or when the query kind outright does not support it. #[inline] #[instrument(skip(self, frame), level = "debug")] fn try_force_from_dep_node(self, dep_node: DepNode, frame: Option<&MarkFrame<'_>>) -> bool { let cb = self.dep_kind_info(dep_node.kind); if let Some(f) = cb.force_from_dep_node { - if let Err(value) = panic::catch_unwind(panic::AssertUnwindSafe(|| { - f(self, dep_node); - })) { - if !value.is::<rustc_errors::FatalErrorMarker>() { - print_markframe_trace(self.dep_graph(), frame); + match panic::catch_unwind(panic::AssertUnwindSafe(|| f(self, dep_node))) { + Err(value) => { + if !value.is::<rustc_errors::FatalErrorMarker>() { + print_markframe_trace(self.dep_graph(), frame); + } + panic::resume_unwind(value) } - panic::resume_unwind(value) + Ok(query_has_been_forced) => query_has_been_forced, } - true } else { false } diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 358f25e2334..4b9c36ad39f 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -240,7 +240,7 @@ resolve_label_with_similar_name_reachable = resolve_lending_iterator_report_error = associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type - .note = you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type. + .note = you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type resolve_lifetime_param_in_enum_discriminant = lifetime parameters may not be used in enum discriminant values diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index fb6e55f2b7b..1bca5602a4e 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -217,12 +217,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { let def_kind = match fi.kind { - ForeignItemKind::Static(box StaticForeignItem { - ty: _, - mutability, - expr: _, - safety, - }) => { + ForeignItemKind::Static(box StaticItem { ty: _, mutability, expr: _, safety }) => { let safety = match safety { ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe, ast::Safety::Safe(_) => hir::Safety::Safe, @@ -343,6 +338,9 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) } ExprKind::ConstBlock(ref constant) => { + for attr in &expr.attrs { + visit::walk_attribute(self, attr); + } let def = self.create_def( constant.id, kw::Empty, diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 0be8b5d5718..f998fd599b7 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -4,6 +4,7 @@ //! //! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, //! see design document in the tracking issue #89653. + use rustc_data_structures::base_n::ToBaseN; use rustc_data_structures::base_n::ALPHANUMERIC_ONLY; use rustc_data_structures::base_n::CASE_INSENSITIVE; diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs index b6182dc4e63..ac664c53f44 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs @@ -3,6 +3,7 @@ //! //! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, //! see design document in the tracking issue #89653. + use rustc_data_structures::fx::FxHashMap; use rustc_middle::bug; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 742ec4c377c..44b31f2659c 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -3,6 +3,7 @@ //! //! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, //! see design document in the tracking issue #89653. + use rustc_hir as hir; use rustc_hir::LangItem; use rustc_middle::bug; @@ -213,7 +214,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> { } } - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/mod.rs index ad8b1804439..f37ffcbc4db 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/mod.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/mod.rs @@ -3,6 +3,7 @@ //! //! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, //! see design document in the tracking issue #89653. + use bitflags::bitflags; use rustc_middle::ty::{Instance, Ty, TyCtxt}; use rustc_target::abi::call::FnAbi; diff --git a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs index 651ba612469..bfe907e3cf6 100644 --- a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs +++ b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs @@ -3,6 +3,7 @@ //! //! For more information about LLVM KCFI and cross-language LLVM KCFI support for the Rust compiler, //! see the tracking issue #123479. + use rustc_middle::ty::{Instance, InstanceKind, ReifyReason, Ty, TyCtxt}; use rustc_target::abi::call::FnAbi; use std::hash::Hasher; diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index b8dacc6968d..b84280a3ccf 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -82,9 +82,9 @@ session_octal_float_literal_not_supported = octal float literal is not supported session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg} -session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist. +session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist -session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist. +session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi` diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 24143808ef4..839cc51efce 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -19,7 +19,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm}; -use rustc_target::spec::{LinkSelfContainedComponents, LinkerFeatures}; +use rustc_target::spec::{FramePointer, LinkSelfContainedComponents, LinkerFeatures}; use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple}; use std::collections::btree_map::{ Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, @@ -2524,6 +2524,15 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M } } + if !nightly_options::is_unstable_enabled(matches) + && cg.force_frame_pointers == FramePointer::NonLeaf + { + early_dcx.early_fatal( + "`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \ + and a nightly compiler", + ) + } + // For testing purposes, until we have more feedback about these options: ensure `-Z // unstable-options` is required when using the unstable `-C link-self-contained` and `-C // linker-flavor` options. @@ -2966,10 +2975,8 @@ pub(crate) mod dep_tracking { use rustc_span::edition::Edition; use rustc_span::RealFileName; use rustc_target::spec::{ - CodeModel, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, WasmCAbi, - }; - use rustc_target::spec::{ - RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, + CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, + RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, WasmCAbi, }; use std::collections::BTreeMap; use std::hash::{DefaultHasher, Hash}; @@ -3023,6 +3030,7 @@ pub(crate) mod dep_tracking { lint::Level, WasiExecModel, u32, + FramePointer, RelocModel, CodeModel, TlsModel, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 145af50117c..f068d093889 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -12,10 +12,9 @@ use rustc_span::edition::Edition; use rustc_span::RealFileName; use rustc_span::SourceFileHashAlgorithm; use rustc_target::spec::{ - CodeModel, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, SanitizerSet, WasmCAbi, -}; -use rustc_target::spec::{ - RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, + CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, + RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, + WasmCAbi, }; use std::collections::BTreeMap; use std::hash::{DefaultHasher, Hasher}; @@ -374,6 +373,7 @@ mod desc { pub const parse_opt_comma_list: &str = parse_comma_list; pub const parse_number: &str = "a number"; pub const parse_opt_number: &str = parse_number; + pub const parse_frame_pointer: &str = "one of `true`/`yes`/`on`, `false`/`no`/`off`, or (with -Zunstable-options) `non-leaf` or `always`"; pub const parse_threads: &str = parse_number; pub const parse_time_passes_format: &str = "`text` (default) or `json`"; pub const parse_passes: &str = "a space-separated list of passes, or `all`"; @@ -672,6 +672,18 @@ mod parse { } } + pub(crate) fn parse_frame_pointer(slot: &mut FramePointer, v: Option<&str>) -> bool { + let mut yes = false; + match v { + _ if parse_bool(&mut yes, v) && yes => slot.ratchet(FramePointer::Always), + _ if parse_bool(&mut yes, v) => slot.ratchet(FramePointer::MayOmit), + Some("always") => slot.ratchet(FramePointer::Always), + Some("non-leaf") => slot.ratchet(FramePointer::NonLeaf), + _ => return false, + }; + true + } + pub(crate) fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool { match v { Some("all") => { @@ -1479,7 +1491,7 @@ options! { "emit bitcode in rlibs (default: yes)"), extra_filename: String = (String::new(), parse_string, [UNTRACKED], "extra data to put in each output filename"), - force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED], + force_frame_pointers: FramePointer = (FramePointer::MayOmit, parse_frame_pointer, [TRACKED], "force use of the frame pointers"), #[rustc_lint_opt_deny_field_access("use `Session::must_emit_unwind_tables` instead of this field")] force_unwind_tables: Option<bool> = (None, parse_opt_bool, [TRACKED], diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 35cd3cbab66..9a5314312e5 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -1,4 +1,5 @@ //! Related to out filenames of compilation (e.g. binaries). + use crate::config::{self, CrateType, Input, OutFileName, OutputFilenames, OutputType}; use crate::errors::{ self, CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable, diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs index 42fa6989ddc..09866515a2a 100644 --- a/compiler/rustc_smir/src/rustc_smir/builder.rs +++ b/compiler/rustc_smir/src/rustc_smir/builder.rs @@ -3,6 +3,7 @@ //! We first retrieve and monomorphize the rustc body representation, i.e., we generate a //! monomorphic body using internal representation. //! After that, we convert the internal representation into a stable one. + use crate::rustc_smir::{Stable, Tables}; use rustc_hir::def::DefKind; use rustc_middle::mir; diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 9afd507ce11..dde5e30c3d0 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -533,6 +533,13 @@ impl<'tcx> Context for TablesWrapper<'tcx> { Ok(tables.fn_abi_of_instance(instance, List::empty())?.stable(&mut *tables)) } + fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error> { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let sig = fn_ptr.internal(&mut *tables, tcx); + Ok(tables.fn_abi_of_fn_ptr(sig, List::empty())?.stable(&mut *tables)) + } + fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId { let mut tables = self.0.borrow_mut(); let def_id = tables.instances[def].def_id(); diff --git a/compiler/rustc_smir/src/rustc_smir/convert/error.rs b/compiler/rustc_smir/src/rustc_smir/convert/error.rs index 8298450f741..3d689708915 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/error.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/error.rs @@ -1,6 +1,7 @@ //! Handle the conversion of different internal errors into a stable version. //! //! Currently we encode everything as [stable_mir::Error], which is represented as a string. + use crate::rustc_smir::{Stable, Tables}; use rustc_middle::mir::interpret::AllocError; use rustc_middle::ty::layout::LayoutError; diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 98ed985738a..83a554fe31d 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +derivative = "2.2.0" indexmap = { version = "2.0.0" } itoa = "1.0" md5 = { package = "md-5", version = "0.10.0" } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index ba0ad9230c8..483e32c6453 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -43,9 +43,15 @@ use std::hash::Hash; use tracing::{debug, trace}; /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks". -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct SyntaxContext(u32); +// To ensure correctness of incremental compilation, +// `SyntaxContext` must not implement `Ord` or `PartialOrd`. +// See https://github.com/rust-lang/rust/issues/90317. +impl !Ord for SyntaxContext {} +impl !PartialOrd for SyntaxContext {} + #[derive(Debug, Encodable, Decodable, Clone)] pub struct SyntaxContextData { outer_expn: ExpnId, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 99ac973497e..266956d63d7 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -467,46 +467,23 @@ impl FileName { /// `SpanData` is public because `Span` uses a thread-local interner and can't be /// sent to other threads, but some pieces of performance infra run in a separate thread. /// Using `Span` is generally preferred. -#[derive(Clone, Copy, Hash, PartialEq, Eq)] +#[derive(Clone, Copy, Hash, PartialEq, Eq, derivative::Derivative)] +#[derivative(PartialOrd, Ord)] pub struct SpanData { pub lo: BytePos, pub hi: BytePos, /// Information about where the macro came from, if this piece of /// code was created by a macro expansion. + #[derivative(PartialOrd = "ignore", Ord = "ignore")] + // `SyntaxContext` does not implement `Ord`. + // The other fields are enough to determine in-file order. pub ctxt: SyntaxContext, + #[derivative(PartialOrd = "ignore", Ord = "ignore")] + // `LocalDefId` does not implement `Ord`. + // The other fields are enough to determine in-file order. pub parent: Option<LocalDefId>, } -// Order spans by position in the file. -impl Ord for SpanData { - fn cmp(&self, other: &Self) -> Ordering { - let SpanData { - lo: s_lo, - hi: s_hi, - ctxt: s_ctxt, - // `LocalDefId` does not implement `Ord`. - // The other fields are enough to determine in-file order. - parent: _, - } = self; - let SpanData { - lo: o_lo, - hi: o_hi, - ctxt: o_ctxt, - // `LocalDefId` does not implement `Ord`. - // The other fields are enough to determine in-file order. - parent: _, - } = other; - - (s_lo, s_hi, s_ctxt).cmp(&(o_lo, o_hi, o_ctxt)) - } -} - -impl PartialOrd for SpanData { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - impl SpanData { #[inline] pub fn span(&self) -> Span { @@ -525,8 +502,9 @@ impl SpanData { fn with_ctxt(&self, ctxt: SyntaxContext) -> Span { Span::new(self.lo, self.hi, ctxt, self.parent) } + /// Avoid if possible, `Span::with_parent` should be preferred. #[inline] - pub fn with_parent(&self, parent: Option<LocalDefId>) -> Span { + fn with_parent(&self, parent: Option<LocalDefId>) -> Span { Span::new(self.lo, self.hi, self.ctxt, parent) } /// Returns `true` if this is a dummy span with any hygienic context. @@ -580,14 +558,6 @@ impl Span { pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span { self.map_ctxt(|_| ctxt) } - #[inline] - pub fn parent(self) -> Option<LocalDefId> { - self.data().parent - } - #[inline] - pub fn with_parent(self, ctxt: Option<LocalDefId>) -> Span { - self.data().with_parent(ctxt) - } #[inline] pub fn is_visible(self, sm: &SourceMap) -> bool { diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 116056a69c1..53d7b7511a6 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -257,17 +257,17 @@ impl Span { std::mem::swap(&mut lo, &mut hi); } - // Small len may enable one of fully inline formats (or may not). + // Small len and ctxt may enable one of fully inline formats (or may not). let (len, ctxt32) = (hi.0 - lo.0, ctxt.as_u32()); - if len <= MAX_LEN { - if ctxt32 <= MAX_CTXT && parent.is_none() { - return InlineCtxt::span(lo.0, len as u16, ctxt32 as u16); - } else if ctxt32 == 0 - && let Some(parent) = parent - && let parent32 = parent.local_def_index.as_u32() - && parent32 <= MAX_CTXT - { - return InlineParent::span(lo.0, len as u16, parent32 as u16); + if len <= MAX_LEN && ctxt32 <= MAX_CTXT { + match parent { + None => return InlineCtxt::span(lo.0, len as u16, ctxt32 as u16), + Some(parent) => { + let parent32 = parent.local_def_index.as_u32(); + if ctxt32 == 0 && parent32 <= MAX_CTXT { + return InlineParent::span(lo.0, len as u16, parent32 as u16); + } + } } } @@ -322,29 +322,28 @@ impl Span { } } - // For optimization we are interested in cases in which the context is inline and the context - // update doesn't change format. All non-inline or format changing scenarios require accessing - // interner and can fall back to `Span::new`. #[inline] - pub fn map_ctxt(self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) -> Span { - match_span_kind! { + pub fn map_ctxt(self, map: impl FnOnce(SyntaxContext) -> SyntaxContext) -> Span { + let data = match_span_kind! { self, InlineCtxt(span) => { - let updated_ctxt32 = update(SyntaxContext::from_u16(span.ctxt)).as_u32(); - // Any small new context including zero will preserve the format. - return if updated_ctxt32 <= MAX_CTXT { - InlineCtxt::span(span.lo, span.len, updated_ctxt32 as u16) + // This format occurs 1-2 orders of magnitude more often than others (#125017), + // so it makes sense to micro-optimize it to avoid `span.data()` and `Span::new()`. + let new_ctxt = map(SyntaxContext::from_u16(span.ctxt)); + let new_ctxt32 = new_ctxt.as_u32(); + return if new_ctxt32 <= MAX_CTXT { + // Any small new context including zero will preserve the format. + InlineCtxt::span(span.lo, span.len, new_ctxt32 as u16) } else { - span.data().with_ctxt(SyntaxContext::from_u32(updated_ctxt32)) + span.data().with_ctxt(new_ctxt) }; }, - InlineParent(_span) => {}, - PartiallyInterned(_span) => {}, - Interned(_span) => {}, - } + InlineParent(span) => span.data(), + PartiallyInterned(span) => span.data(), + Interned(span) => span.data(), + }; - let data = self.data_untracked(); - data.with_ctxt(update(data.ctxt)) + data.with_ctxt(map(data.ctxt)) } // Returns either syntactic context, if it can be retrieved without taking the interner lock, @@ -381,6 +380,49 @@ impl Span { }), } } + + #[inline] + pub fn with_parent(self, parent: Option<LocalDefId>) -> Span { + let data = match_span_kind! { + self, + InlineCtxt(span) => { + // This format occurs 1-2 orders of magnitude more often than others (#126544), + // so it makes sense to micro-optimize it to avoid `span.data()` and `Span::new()`. + // Copypaste from `Span::new`, the small len & ctxt conditions are known to hold. + match parent { + None => return self, + Some(parent) => { + let parent32 = parent.local_def_index.as_u32(); + if span.ctxt == 0 && parent32 <= MAX_CTXT { + return InlineParent::span(span.lo, span.len, parent32 as u16); + } + } + } + span.data() + }, + InlineParent(span) => span.data(), + PartiallyInterned(span) => span.data(), + Interned(span) => span.data(), + }; + + if let Some(old_parent) = data.parent { + (*SPAN_TRACK)(old_parent); + } + data.with_parent(parent) + } + + #[inline] + pub fn parent(self) -> Option<LocalDefId> { + let interned_parent = + |index: u32| with_span_interner(|interner| interner.spans[index as usize].parent); + match_span_kind! { + self, + InlineCtxt(_span) => None, + InlineParent(span) => Some(LocalDefId { local_def_index: DefIndex::from_u16(span.parent) }), + PartiallyInterned(span) => interned_parent(span.index), + Interned(span) => interned_parent(span.index), + } + } } #[derive(Default)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 55eba257ca2..8d8f4927e99 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -167,6 +167,7 @@ symbols! { Break, C, CStr, + C_dash_unwind: "C-unwind", CallOnceFuture, CallRefFuture, Capture, @@ -1175,6 +1176,7 @@ symbols! { mir_assume, mir_basic_block, mir_call, + mir_cast_ptr_to_ptr, mir_cast_transmute, mir_checked, mir_copy_for_deref, @@ -1592,6 +1594,8 @@ symbols! { rustc_do_not_const_check, rustc_doc_primitive, rustc_dummy, + rustc_dump_item_bounds, + rustc_dump_predicates, rustc_dump_user_args, rustc_dump_vtable, rustc_effective_visibility, @@ -2053,6 +2057,8 @@ symbols! { yes, yield_expr, ymm_reg, + zfh, + zfhmin, zmm_reg, } } diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs index 37184393a73..9d79faadd61 100644 --- a/compiler/rustc_target/src/asm/arm.rs +++ b/compiler/rustc_target/src/asm/arm.rs @@ -47,16 +47,18 @@ impl ArmInlineAsmRegClass { _arch: InlineAsmArch, ) -> &'static [(InlineAsmType, Option<Symbol>)] { match self { - Self::reg => types! { _: I8, I16, I32, F32; }, - Self::sreg | Self::sreg_low16 => types! { vfp2: I32, F32; }, + Self::reg => types! { _: I8, I16, I32, F16, F32; }, + Self::sreg | Self::sreg_low16 => types! { vfp2: I32, F16, F32; }, Self::dreg_low16 | Self::dreg_low8 => types! { - vfp2: I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2); + vfp2: I64, F64; + neon: VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF16(4), VecF32(2); }, Self::dreg => types! { - d32: I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2); + d32: I64, F64; + neon: VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF16(4), VecF32(2); }, Self::qreg | Self::qreg_low8 | Self::qreg_low4 => types! { - neon: VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4); + neon: VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4); }, } } diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs index 3845a0e14af..02a4a5e2ece 100644 --- a/compiler/rustc_target/src/asm/riscv.rs +++ b/compiler/rustc_target/src/asm/riscv.rs @@ -40,12 +40,13 @@ impl RiscVInlineAsmRegClass { match self { Self::reg => { if arch == InlineAsmArch::RiscV64 { - types! { _: I8, I16, I32, I64, F32, F64; } + types! { _: I8, I16, I32, I64, F16, F32, F64; } } else { - types! { _: I8, I16, I32, F32; } + types! { _: I8, I16, I32, F16, F32; } } } - Self::freg => types! { f: F32; d: F64; }, + // FIXME(f16_f128): Add `q: F128;` once LLVM support the `Q` extension. + Self::freg => types! { f: F16, F32; d: F64; }, Self::vreg => &[], } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 42860b1059e..81ada30a594 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1413,6 +1413,20 @@ pub enum FramePointer { MayOmit, } +impl FramePointer { + /// It is intended that the "force frame pointer" transition is "one way" + /// so this convenience assures such if used + #[inline] + pub fn ratchet(&mut self, rhs: FramePointer) -> FramePointer { + *self = match (*self, rhs) { + (FramePointer::Always, _) | (_, FramePointer::Always) => FramePointer::Always, + (FramePointer::NonLeaf, _) | (_, FramePointer::NonLeaf) => FramePointer::NonLeaf, + _ => FramePointer::MayOmit, + }; + *self + } +} + impl FromStr for FramePointer { type Err = (); fn from_str(s: &str) -> Result<Self, ()> { @@ -1768,8 +1782,11 @@ supported_targets! { ("nvptx64-nvidia-cuda", nvptx64_nvidia_cuda), ("xtensa-esp32-none-elf", xtensa_esp32_none_elf), + ("xtensa-esp32-espidf", xtensa_esp32_espidf), ("xtensa-esp32s2-none-elf", xtensa_esp32s2_none_elf), + ("xtensa-esp32s2-espidf", xtensa_esp32s2_espidf), ("xtensa-esp32s3-none-elf", xtensa_esp32s3_none_elf), + ("xtensa-esp32s3-espidf", xtensa_esp32s3_espidf), ("i686-wrs-vxworks", i686_wrs_vxworks), ("x86_64-wrs-vxworks", x86_64_wrs_vxworks), diff --git a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs index b8bdfc943de..9df7b2b670f 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs @@ -1,5 +1,5 @@ -/// A target tuple for OpenWrt MIPS64 targets -/// +//! A target tuple for OpenWrt MIPS64 targets. + use crate::abi::Endian; use crate::spec::{base, Target, TargetOptions}; diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs new file mode 100644 index 00000000000..1b66fdbd2af --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs @@ -0,0 +1,36 @@ +use crate::abi::Endian; +use crate::spec::{base::xtensa, cvs, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "xtensa-none-elf".into(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(), + arch: "xtensa".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: None, + host_tools: None, + std: None, + }, + + options: TargetOptions { + endian: Endian::Little, + c_int_width: "32".into(), + families: cvs!["unix"], + os: "espidf".into(), + env: "newlib".into(), + vendor: "espressif".into(), + + executables: true, + cpu: "esp32".into(), + linker: Some("xtensa-esp32-elf-gcc".into()), + + // The esp32 only supports native 32bit atomics. + max_atomic_width: Some(32), + atomic_cas: true, + + ..xtensa::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs new file mode 100644 index 00000000000..ad5fda8a4ae --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs @@ -0,0 +1,43 @@ +use crate::abi::Endian; +use crate::spec::{base::xtensa, cvs, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "xtensa-none-elf".into(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(), + arch: "xtensa".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: None, + host_tools: None, + std: None, + }, + + options: TargetOptions { + endian: Endian::Little, + c_int_width: "32".into(), + families: cvs!["unix"], + os: "espidf".into(), + env: "newlib".into(), + vendor: "espressif".into(), + + executables: true, + cpu: "esp32-s2".into(), + linker: Some("xtensa-esp32s2-elf-gcc".into()), + + // See https://github.com/espressif/rust-esp32-example/issues/3#issuecomment-861054477 + // + // While the ESP32-S2 chip does not natively support atomics, ESP-IDF does support + // the __atomic* and __sync* compiler builtins. Setting `max_atomic_width` and `atomic_cas` + // and `atomic_cas: true` will cause the compiler to emit libcalls to these builtins. On the + // ESP32-S2, these are guaranteed to be lock-free. + // + // Support for atomics is necessary for the Rust STD library, which is supported by ESP-IDF. + max_atomic_width: Some(32), + atomic_cas: true, + + ..xtensa::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs new file mode 100644 index 00000000000..ab1d1df43dd --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs @@ -0,0 +1,36 @@ +use crate::abi::Endian; +use crate::spec::{base::xtensa, cvs, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "xtensa-none-elf".into(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(), + arch: "xtensa".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: None, + host_tools: None, + std: None, + }, + + options: TargetOptions { + endian: Endian::Little, + c_int_width: "32".into(), + families: cvs!["unix"], + os: "espidf".into(), + env: "newlib".into(), + vendor: "espressif".into(), + + executables: true, + cpu: "esp32-s3".into(), + linker: Some("xtensa-esp32s3-elf-gcc".into()), + + // The esp32s3 only supports native 32bit atomics. + max_atomic_width: Some(32), + atomic_cas: true, + + ..xtensa::opts() + }, + } +} diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index d9812540e49..017fd3072fd 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -208,6 +208,11 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[ ("avx512vnni", Unstable(sym::avx512_target_feature)), ("avx512vp2intersect", Unstable(sym::avx512_target_feature)), ("avx512vpopcntdq", Unstable(sym::avx512_target_feature)), + ("avxifma", Unstable(sym::avx512_target_feature)), + ("avxneconvert", Unstable(sym::avx512_target_feature)), + ("avxvnni", Unstable(sym::avx512_target_feature)), + ("avxvnniint16", Unstable(sym::avx512_target_feature)), + ("avxvnniint8", Unstable(sym::avx512_target_feature)), ("bmi1", Stable), ("bmi2", Stable), ("cmpxchg16b", Stable), diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index a7c8cc5a32b..e47f5389cd1 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -1,7 +1,7 @@ pub use rustc_next_trait_solver::solve::*; +mod delegate; mod fulfill; -mod infcx; pub mod inspect; mod normalize; mod select; diff --git a/compiler/rustc_trait_selection/src/solve/infcx.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index e574166cbfc..643d5f80480 100644 --- a/compiler/rustc_trait_selection/src/solve/infcx.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -39,10 +39,10 @@ impl<'tcx> Deref for SolverDelegate<'tcx> { } } -impl<'tcx> rustc_next_trait_solver::infcx::SolverDelegate for SolverDelegate<'tcx> { +impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<'tcx> { type Interner = TyCtxt<'tcx>; - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.0.tcx } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 8937ed467a1..76b88aeb0f7 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -17,7 +17,7 @@ use rustc_span::symbol::sym; use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError}; -use super::infcx::SolverDelegate; +use super::delegate::SolverDelegate; use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; use super::Certainty; diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index cb621487125..e8de8457440 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -22,7 +22,7 @@ use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state} use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _}; use rustc_span::{Span, DUMMY_SP}; -use crate::solve::infcx::SolverDelegate; +use crate::solve::delegate::SolverDelegate; use crate::traits::ObligationCtxt; pub struct InspectConfig { diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index f42edebfcc4..2679da942b7 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -156,7 +156,7 @@ where { type Error = Vec<E>; - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.at.infcx.tcx } @@ -244,7 +244,7 @@ struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.at.infcx.tcx } 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 038f11c60b8..b2fa3489dda 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2776,97 +2776,115 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut this = "this bound"; let mut note = None; let mut help = None; - if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() - && let ty::ClauseKind::Trait(trait_pred) = clause - { - let def_id = trait_pred.def_id(); - let visible_item = if let Some(local) = def_id.as_local() { - // Check for local traits being reachable. - let vis = &tcx.resolutions(()).effective_visibilities; - // Account for non-`pub` traits in the root of the local crate. - let is_locally_reachable = tcx.parent(def_id).is_crate_root(); - vis.is_reachable(local) || is_locally_reachable - } else { - // Check for foreign traits being reachable. - tcx.visible_parent_map(()).get(&def_id).is_some() - }; - if tcx.is_lang_item(def_id, LangItem::Sized) { - // Check if this is an implicit bound, even in foreign crates. - if tcx - .generics_of(item_def_id) - .own_params - .iter() - .any(|param| tcx.def_span(param.def_id) == span) - { - a = "an implicit `Sized`"; - this = "the implicit `Sized` requirement on this type parameter"; - } - if let Some(hir::Node::TraitItem(hir::TraitItem { - generics, - kind: hir::TraitItemKind::Type(bounds, None), - .. - })) = tcx.hir().get_if_local(item_def_id) - // Do not suggest relaxing if there is an explicit `Sized` obligation. - && !bounds.iter() - .filter_map(|bound| bound.trait_ref()) - .any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait()) - { - let (span, separator) = if let [.., last] = bounds { - (last.span().shrink_to_hi(), " +") + if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() { + match clause { + ty::ClauseKind::Trait(trait_pred) => { + let def_id = trait_pred.def_id(); + let visible_item = if let Some(local) = def_id.as_local() { + // Check for local traits being reachable. + let vis = &tcx.resolutions(()).effective_visibilities; + // Account for non-`pub` traits in the root of the local crate. + let is_locally_reachable = tcx.parent(def_id).is_crate_root(); + vis.is_reachable(local) || is_locally_reachable } else { - (generics.span.shrink_to_hi(), ":") + // Check for foreign traits being reachable. + tcx.visible_parent_map(()).get(&def_id).is_some() }; - err.span_suggestion_verbose( - span, - "consider relaxing the implicit `Sized` restriction", - format!("{separator} ?Sized"), - Applicability::MachineApplicable, - ); + if tcx.is_lang_item(def_id, LangItem::Sized) { + // Check if this is an implicit bound, even in foreign crates. + if tcx + .generics_of(item_def_id) + .own_params + .iter() + .any(|param| tcx.def_span(param.def_id) == span) + { + a = "an implicit `Sized`"; + this = + "the implicit `Sized` requirement on this type parameter"; + } + if let Some(hir::Node::TraitItem(hir::TraitItem { + generics, + kind: hir::TraitItemKind::Type(bounds, None), + .. + })) = tcx.hir().get_if_local(item_def_id) + // Do not suggest relaxing if there is an explicit `Sized` obligation. + && !bounds.iter() + .filter_map(|bound| bound.trait_ref()) + .any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait()) + { + let (span, separator) = if let [.., last] = bounds { + (last.span().shrink_to_hi(), " +") + } else { + (generics.span.shrink_to_hi(), ":") + }; + err.span_suggestion_verbose( + span, + "consider relaxing the implicit `Sized` restriction", + format!("{separator} ?Sized"), + Applicability::MachineApplicable, + ); + } + } + if let DefKind::Trait = tcx.def_kind(item_def_id) + && !visible_item + { + note = Some(format!( + "`{short_item_name}` is a \"sealed trait\", because to implement it \ + you also need to implement `{}`, which is not accessible; this is \ + usually done to force you to use one of the provided types that \ + already implement it", + with_no_trimmed_paths!(tcx.def_path_str(def_id)), + )); + let impls_of = tcx.trait_impls_of(def_id); + let impls = impls_of + .non_blanket_impls() + .values() + .flatten() + .chain(impls_of.blanket_impls().iter()) + .collect::<Vec<_>>(); + if !impls.is_empty() { + let len = impls.len(); + let mut types = impls + .iter() + .map(|t| { + with_no_trimmed_paths!(format!( + " {}", + tcx.type_of(*t).instantiate_identity(), + )) + }) + .collect::<Vec<_>>(); + let post = if types.len() > 9 { + types.truncate(8); + format!("\nand {} others", len - 8) + } else { + String::new() + }; + help = Some(format!( + "the following type{} implement{} the trait:\n{}{post}", + pluralize!(len), + if len == 1 { "s" } else { "" }, + types.join("\n"), + )); + } + } } - } - if let DefKind::Trait = tcx.def_kind(item_def_id) - && !visible_item - { - note = Some(format!( - "`{short_item_name}` is a \"sealed trait\", because to implement it \ - you also need to implement `{}`, which is not accessible; this is \ - usually done to force you to use one of the provided types that \ - already implement it", - with_no_trimmed_paths!(tcx.def_path_str(def_id)), - )); - let impls_of = tcx.trait_impls_of(def_id); - let impls = impls_of - .non_blanket_impls() - .values() - .flatten() - .chain(impls_of.blanket_impls().iter()) - .collect::<Vec<_>>(); - if !impls.is_empty() { - let len = impls.len(); - let mut types = impls - .iter() - .map(|t| { - with_no_trimmed_paths!(format!( - " {}", - tcx.type_of(*t).instantiate_identity(), - )) - }) - .collect::<Vec<_>>(); - let post = if types.len() > 9 { - types.truncate(8); - format!("\nand {} others", len - 8) + ty::ClauseKind::ConstArgHasType(..) => { + let descr = + format!("required by a const generic parameter in `{item_name}`"); + if span.is_visible(sm) { + let msg = format!( + "required by this const generic parameter in `{short_item_name}`" + ); + multispan.push_span_label(span, msg); + err.span_note(multispan, descr); } else { - String::new() - }; - help = Some(format!( - "the following type{} implement{} the trait:\n{}{post}", - pluralize!(len), - if len == 1 { "s" } else { "" }, - types.join("\n"), - )); + err.span_note(tcx.def_span(item_def_id), descr); + } + return; } + _ => (), } - }; + } let descr = format!("required by {a} bound in `{item_name}`"); if span.is_visible(sm) { let msg = format!("required by {this} in `{short_item_name}`"); @@ -4918,7 +4936,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceImplTraitFolder<'tcx> { t.super_fold_with(self) } - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } } 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 e38f7951197..d3096cf4b52 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 @@ -179,6 +179,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { for (error, suppressed) in iter::zip(&errors, &is_suppressed) { if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion { let guar = self.report_fulfillment_error(error); + self.infcx.set_tainted_by_errors(guar); reported = Some(guar); // We want to ignore desugarings here: spans are equivalent even // if one is the result of a desugaring and the other is not. @@ -2686,22 +2687,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - // Given some `ConstArgHasType(?x, usize)`, we should not emit an error such as - // "type annotations needed: cannot satisfy the constant `_` has type `usize`" - // Instead we should emit a normal error suggesting the user to turbofish the - // const parameter that is currently being inferred. Unfortunately we cannot - // nicely emit such an error so we delay an ICE incase nobody else reports it - // for us. - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { - return self.tcx.sess.dcx().span_delayed_bug( + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ..)) => self + .emit_inference_failure_err( + obligation.cause.body_id, span, - format!( - "`ambiguous ConstArgHasType({:?}, {:?}) unaccompanied by inference error`", - ct, ty - ), - ); - } - + ct.into(), + ErrorCode::E0284, + true, + ), ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) if term.is_infer() => { @@ -2847,7 +2840,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ParamToVarFolder<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index af6bfdae440..662d95db8ba 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -350,7 +350,7 @@ pub fn normalize_param_env_or_error<'tcx>( struct ConstNormalizer<'tcx>(TyCtxt<'tcx>); impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ConstNormalizer<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.0 } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index e7ab0b7791c..a9ac0f7eb25 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -1,4 +1,5 @@ //! Deeply normalize types using the old trait solver. + use super::error_reporting::OverflowCause; use super::error_reporting::TypeErrCtxtExt; use super::SelectionContext; @@ -162,7 +163,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { } impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.selcx.tcx() } @@ -216,7 +217,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx Reveal::UserFacing => ty.super_fold_with(self), Reveal::All => { - let recursion_limit = self.interner().recursion_limit(); + let recursion_limit = self.cx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { self.selcx.infcx.err_ctxt().report_overflow_error( OverflowCause::DeeplyNormalize(data.into()), @@ -227,8 +228,8 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx } let args = data.args.fold_with(self); - let generic_ty = self.interner().type_of(data.def_id); - let concrete_ty = generic_ty.instantiate(self.interner(), args); + let generic_ty = self.cx().type_of(data.def_id); + let concrete_ty = generic_ty.instantiate(self.cx(), args); self.depth += 1; let folded_ty = self.fold_ty(concrete_ty); self.depth -= 1; @@ -312,7 +313,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx normalized_ty } ty::Weak => { - let recursion_limit = self.interner().recursion_limit(); + let recursion_limit = self.cx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { self.selcx.infcx.err_ctxt().report_overflow_error( OverflowCause::DeeplyNormalize(data.into()), diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index e170d7cae93..bed76b84ee0 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -172,7 +172,7 @@ struct QueryNormalizer<'cx, 'tcx> { impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> { type Error = NoSolution; - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -217,7 +217,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> Reveal::All => { let args = data.args.try_fold_with(self)?; - let recursion_limit = self.interner().recursion_limit(); + let recursion_limit = self.cx().recursion_limit(); if !recursion_limit.value_within_limit(self.anon_depth) { let guar = self @@ -229,15 +229,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> true, ) .delay_as_bug(); - return Ok(Ty::new_error(self.interner(), guar)); + return Ok(Ty::new_error(self.cx(), guar)); } - let generic_ty = self.interner().type_of(data.def_id); - let mut concrete_ty = generic_ty.instantiate(self.interner(), args); + let generic_ty = self.cx().type_of(data.def_id); + let mut concrete_ty = generic_ty.instantiate(self.cx(), args); self.anon_depth += 1; if concrete_ty == ty { concrete_ty = Ty::new_error_with_message( - self.interner(), + self.cx(), DUMMY_SP, "recursive opaque type", ); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index af599108c49..b50f6260ab3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -6,6 +6,7 @@ //! //! [rustc dev guide]: //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation + use rustc_ast::Mutability; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index c3fe816028e..f132e36468a 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -394,7 +394,7 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -509,7 +509,7 @@ impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -550,7 +550,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - ty::Region::new_bound(self.interner(), db, *replace_var) + ty::Region::new_bound(self.cx(), db, *replace_var) } None => r1, } diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 18a09067a2c..e4bf6069caf 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -7,7 +7,8 @@ edition = "2021" # tidy-alphabetical-start bitflags = "2.4.1" derivative = "2.2.0" -rustc_ast_ir = { path = "../rustc_ast_ir" } +indexmap = "2.0.0" +rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 5042a38fdb8..18b34f8d99b 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -5,14 +5,16 @@ use std::ops::{ControlFlow, Deref}; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +#[cfg(feature = "nightly")] use rustc_serialize::Decodable; use tracing::debug; +use crate::data_structures::SsoHashSet; use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::inherent::*; use crate::lift::Lift; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use crate::{self as ty, Interner, SsoHashSet}; +use crate::{self as ty, Interner}; /// Binder is a binder for higher-ranked lifetimes or types. It is part of the /// compiler's representation for things like `for<'a> Fn(&'a isize)` @@ -55,6 +57,7 @@ where } } +#[cfg(feature = "nightly")] macro_rules! impl_binder_encode_decode { ($($t:ty),+ $(,)?) => { $( @@ -82,6 +85,7 @@ macro_rules! impl_binder_encode_decode { } } +#[cfg(feature = "nightly")] impl_binder_encode_decode! { ty::FnSig<I>, ty::TraitPredicate<I>, @@ -621,7 +625,7 @@ struct ArgFolder<'a, I: Interner> { impl<'a, I: Interner> TypeFolder<I> for ArgFolder<'a, I> { #[inline] - fn interner(&self) -> I { + fn cx(&self) -> I { self.tcx } @@ -841,7 +845,7 @@ impl<'a, I: Interner> ArgFolder<'a, I> { return val; } - let result = ty::fold::shift_vars(TypeFolder::interner(self), val, self.binders_passed); + let result = ty::fold::shift_vars(TypeFolder::cx(self), val, self.binders_passed); debug!("shift_vars: shifted result = {:?}", result); result diff --git a/compiler/rustc_type_ir/src/data_structures.rs b/compiler/rustc_type_ir/src/data_structures.rs new file mode 100644 index 00000000000..6d8ab61b722 --- /dev/null +++ b/compiler/rustc_type_ir/src/data_structures.rs @@ -0,0 +1,29 @@ +#[cfg(feature = "nightly")] +mod impl_ { + pub use rustc_data_structures::fx::FxHashMap as HashMap; + pub use rustc_data_structures::fx::FxHashSet as HashSet; + pub use rustc_data_structures::fx::FxIndexMap as IndexMap; + pub use rustc_data_structures::fx::FxIndexSet as IndexSet; + pub use rustc_data_structures::sso::SsoHashMap; + pub use rustc_data_structures::sso::SsoHashSet; + pub use rustc_data_structures::stack::ensure_sufficient_stack; + pub use rustc_data_structures::sync::Lrc; +} + +#[cfg(not(feature = "nightly"))] +mod impl_ { + pub use indexmap::IndexMap; + pub use indexmap::IndexSet; + pub use std::collections::HashMap; + pub use std::collections::HashMap as SsoHashMap; + pub use std::collections::HashSet; + pub use std::collections::HashSet as SsoHashSet; + pub use std::sync::Arc as Lrc; + + #[inline] + pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R { + f() + } +} + +pub use impl_::*; diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs index 27623ea9cac..8b59e9a6f48 100644 --- a/compiler/rustc_type_ir/src/error.rs +++ b/compiler/rustc_type_ir/src/error.rs @@ -30,7 +30,7 @@ impl<T> ExpectedFound<T> { Debug(bound = "") )] #[derive(TypeVisitable_Generic)] -#[rustc_pass_by_value] +#[cfg_attr(feature = "nightly", rustc_pass_by_value)] pub enum TypeError<I: Interner> { Mismatch, ConstnessMismatch(ExpectedFound<ty::BoundConstness>), diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index ee3e5ce66d0..953a438cb14 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -49,9 +49,10 @@ use rustc_index::{Idx, IndexVec}; use std::mem; use tracing::debug; +use crate::data_structures::Lrc; use crate::inherent::*; use crate::visit::{TypeVisitable, TypeVisitableExt as _}; -use crate::{self as ty, Interner, Lrc}; +use crate::{self as ty, Interner}; #[cfg(feature = "nightly")] type Never = !; @@ -128,7 +129,7 @@ pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> { /// the infallible methods of this trait to ensure that the two APIs /// are coherent. pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = Never> { - fn interner(&self) -> I; + fn cx(&self) -> I; fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> where @@ -166,7 +167,7 @@ pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = Never> { pub trait FallibleTypeFolder<I: Interner>: Sized { type Error; - fn interner(&self) -> I; + fn cx(&self) -> I; fn try_fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> Result<ty::Binder<I, T>, Self::Error> where @@ -202,8 +203,8 @@ where { type Error = Never; - fn interner(&self) -> I { - TypeFolder::interner(self) + fn cx(&self) -> I { + TypeFolder::cx(self) } fn try_fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> Result<ty::Binder<I, T>, Never> @@ -350,7 +351,7 @@ impl<I: Interner> Shifter<I> { } impl<I: Interner> TypeFolder<I> for Shifter<I> { - fn interner(&self) -> I { + fn cx(&self) -> I { self.tcx } diff --git a/compiler/rustc_type_ir/src/generic_arg.rs b/compiler/rustc_type_ir/src/generic_arg.rs index cc8c4444657..b158f0f5eee 100644 --- a/compiler/rustc_type_ir/src/generic_arg.rs +++ b/compiler/rustc_type_ir/src/generic_arg.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use crate::Interner; diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 64d3400976a..be6deee011b 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -8,8 +8,8 @@ use std::hash::Hash; use std::ops::Deref; use rustc_ast_ir::Mutability; -use rustc_data_structures::fx::FxHashSet; +use crate::data_structures::HashSet; use crate::fold::{TypeFoldable, TypeSuperFoldable}; use crate::relate::Relate; use crate::solve::{CacheData, CanonicalInput, QueryResult, Reveal}; @@ -530,7 +530,7 @@ pub trait EvaluationCache<I: Interner> { proof_tree: Option<I::CanonicalGoalEvaluationStepRef>, additional_depth: usize, encountered_overflow: bool, - cycle_participants: FxHashSet<CanonicalInput<I>>, + cycle_participants: HashSet<CanonicalInput<I>>, dep_node: I::DepNodeIndex, result: QueryResult<I>, ); diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 130ea231bf7..9b8ca5efdda 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -7,27 +7,19 @@ #![cfg_attr(feature = "nightly", allow(internal_features))] // tidy-alphabetical-end -#[cfg(feature = "nightly")] extern crate self as rustc_type_ir; #[cfg(feature = "nightly")] -use rustc_data_structures::sso::SsoHashSet; -#[cfg(feature = "nightly")] -use rustc_data_structures::sync::Lrc; -#[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable, HashStable_NoContext}; -#[cfg(not(feature = "nightly"))] -use std::collections::HashSet as SsoHashSet; use std::fmt; use std::hash::Hash; -#[cfg(not(feature = "nightly"))] -use std::sync::Arc as Lrc; // These modules are `pub` since they are not glob-imported. #[macro_use] pub mod visit; #[cfg(feature = "nightly")] pub mod codec; +pub mod data_structures; pub mod error; pub mod fold; pub mod inherent; diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs index 60737066597..738350f1b34 100644 --- a/compiler/rustc_type_ir/src/opaque_ty.rs +++ b/compiler/rustc_type_ir/src/opaque_ty.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 8a6ba87b60e..429bc3197d4 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -1,12 +1,13 @@ use std::iter; use rustc_ast_ir::Mutability; -use rustc_type_ir::error::{ExpectedFound, TypeError}; -use rustc_type_ir::fold::TypeFoldable; -use rustc_type_ir::inherent::*; -use rustc_type_ir::{self as ty, Interner}; use tracing::{debug, instrument}; +use crate::error::{ExpectedFound, TypeError}; +use crate::fold::TypeFoldable; +use crate::inherent::*; +use crate::{self as ty, Interner}; + pub type RelateResult<I, T> = Result<T, TypeError<I>>; /// Extra information about why we ended up with a particular variance. diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index 97752934632..3a17a27bd03 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -521,7 +521,7 @@ struct FoldEscapingRegions<I: Interner> { } impl<I: Interner> TypeFolder<I> for FoldEscapingRegions<I> { - fn interner(&self) -> I { + fn cx(&self) -> I { self.interner } diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 6880c7b8cef..473a0aa250f 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -47,8 +47,9 @@ use rustc_index::{Idx, IndexVec}; use std::fmt; use std::ops::ControlFlow; +use crate::data_structures::Lrc; use crate::inherent::*; -use crate::{self as ty, Interner, Lrc, TypeFlags}; +use crate::{self as ty, Interner, TypeFlags}; /// This trait is implemented for every type that can be visited, /// providing the skeleton of the traversal. diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 3e138e3c2e0..44dbf549c1a 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -215,6 +215,9 @@ pub trait Context { /// Get an instance ABI. fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error>; + /// Get the ABI of a function pointer. + fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error>; + /// Get the layout of a type. fn ty_layout(&self, ty: Ty) -> Result<Layout, Error>; diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs index 408e0bafa58..ef1568151f2 100644 --- a/compiler/stable_mir/src/mir/alloc.rs +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -1,4 +1,5 @@ //! This module provides methods to retrieve allocation information, such as static variables. + use crate::mir::mono::{Instance, StaticDef}; use crate::target::{Endian, MachineInfo}; use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty}; diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 35927237281..8c120a96e75 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -2,7 +2,7 @@ use super::{ mir::{Body, Mutability, Safety}, with, DefId, Error, Symbol, }; -use crate::abi::Layout; +use crate::abi::{FnAbi, Layout}; use crate::crate_def::{CrateDef, CrateDefType}; use crate::mir::alloc::{read_target_int, read_target_uint, AllocId}; use crate::mir::mono::StaticDef; @@ -996,6 +996,16 @@ pub struct AliasTerm { pub type PolyFnSig = Binder<FnSig>; +impl PolyFnSig { + /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. + /// + /// NB: this doesn't handle virtual calls - those should use `Instance::fn_abi` + /// instead, where the instance is an `InstanceKind::Virtual`. + pub fn fn_ptr_abi(self) -> Result<FnAbi, Error> { + with(|cx| cx.fn_ptr_abi(self)) + } +} + #[derive(Clone, Debug, Eq, PartialEq)] pub struct FnSig { pub inputs_and_output: Vec<Ty>, diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 6677534eafc..1833a7f477f 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -424,29 +424,3 @@ pub mod __alloc_error_handler { } } } - -#[cfg(not(no_global_oom_handling))] -/// Specialize clones into pre-allocated, uninitialized memory. -/// Used by `Box::clone` and `Rc`/`Arc::make_mut`. -pub(crate) trait WriteCloneIntoRaw: Sized { - unsafe fn write_clone_into_raw(&self, target: *mut Self); -} - -#[cfg(not(no_global_oom_handling))] -impl<T: Clone> WriteCloneIntoRaw for T { - #[inline] - default unsafe fn write_clone_into_raw(&self, target: *mut Self) { - // Having allocated *first* may allow the optimizer to create - // the cloned value in-place, skipping the local and move. - unsafe { target.write(self.clone()) }; - } -} - -#[cfg(not(no_global_oom_handling))] -impl<T: Copy> WriteCloneIntoRaw for T { - #[inline] - unsafe fn write_clone_into_raw(&self, target: *mut Self) { - // We can always copy in-place, without ever involving a local value. - unsafe { target.copy_from_nonoverlapping(self, 1) }; - } -} diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 01a954ed75b..1ec095a46f7 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -188,6 +188,8 @@ use core::any::Any; use core::async_iter::AsyncIterator; use core::borrow; +#[cfg(not(no_global_oom_handling))] +use core::clone::CloneToUninit; use core::cmp::Ordering; use core::error::Error; use core::fmt; @@ -207,7 +209,7 @@ use core::slice; use core::task::{Context, Poll}; #[cfg(not(no_global_oom_handling))] -use crate::alloc::{handle_alloc_error, WriteCloneIntoRaw}; +use crate::alloc::handle_alloc_error; use crate::alloc::{AllocError, Allocator, Global, Layout}; #[cfg(not(no_global_oom_handling))] use crate::borrow::Cow; @@ -1346,7 +1348,7 @@ impl<T: Clone, A: Allocator + Clone> Clone for Box<T, A> { // Pre-allocate memory to allow writing the cloned value directly. let mut boxed = Self::new_uninit_in(self.1.clone()); unsafe { - (**self).write_clone_into_raw(boxed.as_mut_ptr()); + (**self).clone_to_uninit(boxed.as_mut_ptr()); boxed.assume_init() } } diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 8b145b67bf1..e9bfecba160 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -1,6 +1,7 @@ -// Based on -// https://github.com/matthieu-m/rfc2580/blob/b58d1d3cba0d4b5e859d3617ea2d0943aaa31329/examples/thin.rs -// by matthieu-m +//! Based on +//! <https://github.com/matthieu-m/rfc2580/blob/b58d1d3cba0d4b5e859d3617ea2d0943aaa31329/examples/thin.rs> +//! by matthieu-m + use crate::alloc::{self, Layout, LayoutError}; use core::error::Error; use core::fmt::{self, Debug, Display, Formatter}; diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 895d1b8d59f..ecb019b49c6 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -103,6 +103,7 @@ #![feature(assert_matches)] #![feature(async_fn_traits)] #![feature(async_iterator)] +#![feature(clone_to_uninit)] #![feature(coerce_unsized)] #![feature(const_align_of_val)] #![feature(const_box)] @@ -165,17 +166,16 @@ // // Language features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(c_unwind))] #![cfg_attr(not(test), feature(coroutine_trait))] #![cfg_attr(test, feature(panic_update_hook))] #![cfg_attr(test, feature(test))] #![feature(allocator_internals)] #![feature(allow_internal_unstable)] -#![feature(c_unwind)] #![feature(cfg_sanitize)] #![feature(const_mut_refs)] #![feature(const_precise_live_drops)] #![feature(const_ptr_write)] -#![feature(const_trait_impl)] #![feature(const_try)] #![feature(decl_macro)] #![feature(dropck_eyepatch)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 2b7ab2f6e25..3745ecb48c1 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -249,6 +249,8 @@ use std::boxed::Box; use core::any::Any; use core::borrow; use core::cell::Cell; +#[cfg(not(no_global_oom_handling))] +use core::clone::CloneToUninit; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; @@ -268,8 +270,6 @@ use core::slice::from_raw_parts_mut; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; -#[cfg(not(no_global_oom_handling))] -use crate::alloc::WriteCloneIntoRaw; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; #[cfg(not(no_global_oom_handling))] @@ -1749,7 +1749,8 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> { } } -impl<T: Clone, A: Allocator + Clone> Rc<T, A> { +#[cfg(not(no_global_oom_handling))] +impl<T: ?Sized + CloneToUninit, A: Allocator + Clone> Rc<T, A> { /// Makes a mutable reference into the given `Rc`. /// /// If there are other `Rc` pointers to the same allocation, then `make_mut` will @@ -1800,31 +1801,52 @@ impl<T: Clone, A: Allocator + Clone> Rc<T, A> { /// assert!(76 == *data); /// assert!(weak.upgrade().is_none()); /// ``` - #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rc_unique", since = "1.4.0")] pub fn make_mut(this: &mut Self) -> &mut T { + let size_of_val = size_of_val::<T>(&**this); + if Rc::strong_count(this) != 1 { // Gotta clone the data, there are other Rcs. - // Pre-allocate memory to allow writing the cloned value directly. - let mut rc = Self::new_uninit_in(this.alloc.clone()); - unsafe { - let data = Rc::get_mut_unchecked(&mut rc); - (**this).write_clone_into_raw(data.as_mut_ptr()); - *this = rc.assume_init(); - } + + let this_data_ref: &T = &**this; + // `in_progress` drops the allocation if we panic before finishing initializing it. + let mut in_progress: UniqueRcUninit<T, A> = + UniqueRcUninit::new(this_data_ref, this.alloc.clone()); + + // Initialize with clone of this. + let initialized_clone = unsafe { + // Clone. If the clone panics, `in_progress` will be dropped and clean up. + this_data_ref.clone_to_uninit(in_progress.data_ptr()); + // Cast type of pointer, now that it is initialized. + in_progress.into_rc() + }; + + // Replace `this` with newly constructed Rc. + *this = initialized_clone; } else if Rc::weak_count(this) != 0 { // Can just steal the data, all that's left is Weaks - let mut rc = Self::new_uninit_in(this.alloc.clone()); + + // We don't need panic-protection like the above branch does, but we might as well + // use the same mechanism. + let mut in_progress: UniqueRcUninit<T, A> = + UniqueRcUninit::new(&**this, this.alloc.clone()); unsafe { - let data = Rc::get_mut_unchecked(&mut rc); - data.as_mut_ptr().copy_from_nonoverlapping(&**this, 1); + // Initialize `in_progress` with move of **this. + // We have to express this in terms of bytes because `T: ?Sized`; there is no + // operation that just copies a value based on its `size_of_val()`. + ptr::copy_nonoverlapping( + ptr::from_ref(&**this).cast::<u8>(), + in_progress.data_ptr().cast::<u8>(), + size_of_val, + ); this.inner().dec_strong(); // Remove implicit strong-weak ref (no need to craft a fake // Weak here -- we know other Weaks can clean up for us) this.inner().dec_weak(); - ptr::write(this, rc.assume_init()); + // Replace `this` with newly constructed Rc that has the moved data. + ptr::write(this, in_progress.into_rc()); } } // This unsafety is ok because we're guaranteed that the pointer @@ -3686,3 +3708,67 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc<T, A> { } } } + +/// A unique owning pointer to a [`RcBox`] **that does not imply the contents are initialized,** +/// but will deallocate it (without dropping the value) when dropped. +/// +/// This is a helper for [`Rc::make_mut()`] to ensure correct cleanup on panic. +/// It is nearly a duplicate of `UniqueRc<MaybeUninit<T>, A>` except that it allows `T: !Sized`, +/// which `MaybeUninit` does not. +#[cfg(not(no_global_oom_handling))] +struct UniqueRcUninit<T: ?Sized, A: Allocator> { + ptr: NonNull<RcBox<T>>, + layout_for_value: Layout, + alloc: Option<A>, +} + +#[cfg(not(no_global_oom_handling))] +impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> { + /// Allocate a RcBox with layout suitable to contain `for_value` or a clone of it. + fn new(for_value: &T, alloc: A) -> UniqueRcUninit<T, A> { + let layout = Layout::for_value(for_value); + let ptr = unsafe { + Rc::allocate_for_layout( + layout, + |layout_for_rcbox| alloc.allocate(layout_for_rcbox), + |mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const RcBox<T>), + ) + }; + Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) } + } + + /// Returns the pointer to be written into to initialize the [`Rc`]. + fn data_ptr(&mut self) -> *mut T { + let offset = data_offset_align(self.layout_for_value.align()); + unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } + } + + /// Upgrade this into a normal [`Rc`]. + /// + /// # Safety + /// + /// The data must have been initialized (by writing to [`Self::data_ptr()`]). + unsafe fn into_rc(mut self) -> Rc<T, A> { + let ptr = self.ptr; + let alloc = self.alloc.take().unwrap(); + mem::forget(self); + // SAFETY: The pointer is valid as per `UniqueRcUninit::new`, and the caller is responsible + // for having initialized the data. + unsafe { Rc::from_ptr_in(ptr.as_ptr(), alloc) } + } +} + +#[cfg(not(no_global_oom_handling))] +impl<T: ?Sized, A: Allocator> Drop for UniqueRcUninit<T, A> { + fn drop(&mut self) { + // SAFETY: + // * new() produced a pointer safe to deallocate. + // * We own the pointer unless into_rc() was called, which forgets us. + unsafe { + self.alloc + .take() + .unwrap() + .deallocate(self.ptr.cast(), rcbox_layout_for_value_layout(self.layout_for_value)); + } + } +} diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index 0f09be7721f..5e2e4beb94a 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -316,6 +316,24 @@ fn test_cowrc_clone_weak() { assert!(cow1_weak.upgrade().is_none()); } +/// This is similar to the doc-test for `Rc::make_mut()`, but on an unsized type (slice). +#[test] +fn test_cowrc_unsized() { + use std::rc::Rc; + + let mut data: Rc<[i32]> = Rc::new([10, 20, 30]); + + Rc::make_mut(&mut data)[0] += 1; // Won't clone anything + let mut other_data = Rc::clone(&data); // Won't clone inner data + Rc::make_mut(&mut data)[1] += 1; // Clones inner data + Rc::make_mut(&mut data)[2] += 1; // Won't clone anything + Rc::make_mut(&mut other_data)[0] *= 10; // Won't clone anything + + // Now `data` and `other_data` point to different allocations. + assert_eq!(*data, [11, 21, 31]); + assert_eq!(*other_data, [110, 20, 30]); +} + #[test] fn test_show() { let foo = Rc::new(75); diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index ebe6f7e7caa..c7960b3fb49 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -16,7 +16,7 @@ use core::borrow::{Borrow, BorrowMut}; #[cfg(not(no_global_oom_handling))] use core::cmp::Ordering::{self, Less}; #[cfg(not(no_global_oom_handling))] -use core::mem::{self, SizedTypeProperties}; +use core::mem::{self, MaybeUninit}; #[cfg(not(no_global_oom_handling))] use core::ptr; #[cfg(not(no_global_oom_handling))] @@ -24,7 +24,7 @@ use core::slice::sort; use crate::alloc::Allocator; #[cfg(not(no_global_oom_handling))] -use crate::alloc::{self, Global}; +use crate::alloc::Global; #[cfg(not(no_global_oom_handling))] use crate::borrow::ToOwned; use crate::boxed::Box; @@ -174,23 +174,32 @@ pub(crate) mod hack { #[cfg(not(test))] impl<T> [T] { - /// Sorts the slice. + /// Sorts the slice, preserving initial order of equal elements. /// - /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) worst-case. + /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) + /// worst-case. + /// + /// If `T: Ord` does not implement a total order the resulting order is unspecified. All + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if `T: Ord` panics. /// /// When applicable, unstable sorting is preferred because it is generally faster than stable - /// sorting and it doesn't allocate auxiliary memory. - /// See [`sort_unstable`](slice::sort_unstable). + /// sorting and it doesn't allocate auxiliary memory. See + /// [`sort_unstable`](slice::sort_unstable). The exception are partially sorted slices, which + /// may be better served with `slice::sort`. /// /// # Current implementation /// - /// The current algorithm is an adaptive, iterative merge sort inspired by - /// [timsort](https://en.wikipedia.org/wiki/Timsort). - /// It is designed to be very fast in cases where the slice is nearly sorted, or consists of - /// two or more sorted sequences concatenated one after another. + /// The current implementation is based on [driftsort] by Orson Peters and Lukas Bergdoll, which + /// combines the fast average case of quicksort with the fast worst case and partial run + /// detection of mergesort, achieving linear time on fully sorted and reversed inputs. On inputs + /// with k distinct elements, the expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// The auxiliary memory allocation behavior depends on the input length. Short slices are + /// handled without allocation, medium sized slices allocate `self.len()` and beyond that it + /// clamps at `self.len() / 2`. /// - /// Also, it allocates temporary storage half the size of `self`, but for short slices a - /// non-allocating insertion sort is used instead. + /// If `T: Ord` does not implement a total order, the implementation may panic. /// /// # Examples /// @@ -200,6 +209,8 @@ impl<T> [T] { /// v.sort(); /// assert!(v == [-5, -3, 1, 2, 4]); /// ``` + /// + /// [driftsort]: https://github.com/Voultapher/driftsort #[cfg(not(no_global_oom_handling))] #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] @@ -211,13 +222,18 @@ impl<T> [T] { stable_sort(self, T::lt); } - /// Sorts the slice with a comparator function. + /// Sorts the slice with a comparator function, preserving initial order of equal elements. /// - /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) worst-case. + /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) + /// worst-case. /// - /// The comparator function must define a total ordering for the elements in the slice. If - /// the ordering is not total, the order of the elements is unspecified. An order is a - /// total order if it is (for all `a`, `b` and `c`): + /// The comparator function should define a total ordering for the elements in the slice. If the + /// ordering is not total, the order of the elements is unspecified. + /// + /// If the comparator function does not implement a total order the resulting order is + /// unspecified. All original elements will remain in the slice and any possible modifications + /// via interior mutability are observed in the input. Same is true if the comparator function + /// panics. A total order (for all `a`, `b` and `c`): /// /// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and /// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. @@ -227,23 +243,22 @@ impl<T> [T] { /// /// ``` /// let mut floats = [5f64, 4.0, 1.0, 3.0, 2.0]; - /// floats.sort_by(|a, b| a.partial_cmp(b).unwrap()); + /// floats.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap()); /// assert_eq!(floats, [1.0, 2.0, 3.0, 4.0, 5.0]); /// ``` /// - /// When applicable, unstable sorting is preferred because it is generally faster than stable - /// sorting and it doesn't allocate auxiliary memory. - /// See [`sort_unstable_by`](slice::sort_unstable_by). - /// /// # Current implementation /// - /// The current algorithm is an adaptive, iterative merge sort inspired by - /// [timsort](https://en.wikipedia.org/wiki/Timsort). - /// It is designed to be very fast in cases where the slice is nearly sorted, or consists of - /// two or more sorted sequences concatenated one after another. + /// The current implementation is based on [driftsort] by Orson Peters and Lukas Bergdoll, which + /// combines the fast average case of quicksort with the fast worst case and partial run + /// detection of mergesort, achieving linear time on fully sorted and reversed inputs. On inputs + /// with k distinct elements, the expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// The auxiliary memory allocation behavior depends on the input length. Short slices are + /// handled without allocation, medium sized slices allocate `self.len()` and beyond that it + /// clamps at `self.len() / 2`. /// - /// Also, it allocates temporary storage half the size of `self`, but for short slices a - /// non-allocating insertion sort is used instead. + /// If `T: Ord` does not implement a total order, the implementation may panic. /// /// # Examples /// @@ -256,6 +271,8 @@ impl<T> [T] { /// v.sort_by(|a, b| b.cmp(a)); /// assert!(v == [5, 4, 3, 2, 1]); /// ``` + /// + /// [driftsort]: https://github.com/Voultapher/driftsort #[cfg(not(no_global_oom_handling))] #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] @@ -267,28 +284,27 @@ impl<T> [T] { stable_sort(self, |a, b| compare(a, b) == Less); } - /// Sorts the slice with a key extraction function. + /// Sorts the slice with a key extraction function, preserving initial order of equal elements. /// /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*)) /// worst-case, where the key function is *O*(*m*). /// - /// For expensive key functions (e.g. functions that are not simple property accesses or - /// basic operations), [`sort_by_cached_key`](slice::sort_by_cached_key) is likely to be - /// significantly faster, as it does not recompute element keys. - /// - /// When applicable, unstable sorting is preferred because it is generally faster than stable - /// sorting and it doesn't allocate auxiliary memory. - /// See [`sort_unstable_by_key`](slice::sort_unstable_by_key). + /// If `K: Ord` does not implement a total order the resulting order is unspecified. + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if `K: Ord` panics. /// /// # Current implementation /// - /// The current algorithm is an adaptive, iterative merge sort inspired by - /// [timsort](https://en.wikipedia.org/wiki/Timsort). - /// It is designed to be very fast in cases where the slice is nearly sorted, or consists of - /// two or more sorted sequences concatenated one after another. + /// The current implementation is based on [driftsort] by Orson Peters and Lukas Bergdoll, which + /// combines the fast average case of quicksort with the fast worst case and partial run + /// detection of mergesort, achieving linear time on fully sorted and reversed inputs. On inputs + /// with k distinct elements, the expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// The auxiliary memory allocation behavior depends on the input length. Short slices are + /// handled without allocation, medium sized slices allocate `self.len()` and beyond that it + /// clamps at `self.len() / 2`. /// - /// Also, it allocates temporary storage half the size of `self`, but for short slices a - /// non-allocating insertion sort is used instead. + /// If `K: Ord` does not implement a total order, the implementation may panic. /// /// # Examples /// @@ -298,6 +314,8 @@ impl<T> [T] { /// v.sort_by_key(|k| k.abs()); /// assert!(v == [1, 2, -3, 4, -5]); /// ``` + /// + /// [driftsort]: https://github.com/Voultapher/driftsort #[cfg(not(no_global_oom_handling))] #[rustc_allow_incoherent_impl] #[stable(feature = "slice_sort_by_key", since = "1.7.0")] @@ -310,27 +328,30 @@ impl<T> [T] { stable_sort(self, |a, b| f(a).lt(&f(b))); } - /// Sorts the slice with a key extraction function. + /// Sorts the slice with a key extraction function, preserving initial order of equal elements. /// - /// During sorting, the key function is called at most once per element, by using - /// temporary storage to remember the results of key evaluation. - /// The order of calls to the key function is unspecified and may change in future versions - /// of the standard library. + /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* + *n* \* + /// log(*n*)) worst-case, where the key function is *O*(*m*). /// - /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* + *n* \* log(*n*)) - /// worst-case, where the key function is *O*(*m*). + /// During sorting, the key function is called at most once per element, by using temporary + /// storage to remember the results of key evaluation. The order of calls to the key function is + /// unspecified and may change in future versions of the standard library. /// - /// For simple key functions (e.g., functions that are property accesses or - /// basic operations), [`sort_by_key`](slice::sort_by_key) is likely to be - /// faster. + /// If `K: Ord` does not implement a total order the resulting order is unspecified. + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if `K: Ord` panics. + /// + /// For simple key functions (e.g., functions that are property accesses or basic operations), + /// [`sort_by_key`](slice::sort_by_key) is likely to be faster. /// /// # Current implementation /// - /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, - /// which combines the fast average case of randomized quicksort with the fast worst case of - /// heapsort, while achieving linear time on slices with certain patterns. It uses some - /// randomization to avoid degenerate cases, but with a fixed seed to always provide - /// deterministic behavior. + /// The current implementation is based on [instruction-parallel-network sort][ipnsort] by Lukas + /// Bergdoll, which combines the fast average case of randomized quicksort with the fast worst + /// case of heapsort, while achieving linear time on fully sorted and reversed inputs. And + /// *O*(*k* \* log(*n*)) where *k* is the number of distinct elements in the input. It leverages + /// superscalar out-of-order execution capabilities commonly found in CPUs, to efficiently + /// perform the operation. /// /// In the worst case, the algorithm allocates temporary storage in a `Vec<(K, usize)>` the /// length of the slice. @@ -344,7 +365,7 @@ impl<T> [T] { /// assert!(v == [-3, -5, 2, 32, 4]); /// ``` /// - /// [pdqsort]: https://github.com/orlp/pdqsort + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort #[cfg(not(no_global_oom_handling))] #[rustc_allow_incoherent_impl] #[stable(feature = "slice_sort_by_cached_key", since = "1.34.0")] @@ -361,7 +382,7 @@ impl<T> [T] { $slice.iter().map($f).enumerate().map(|(i, k)| (k, i as $t)).collect(); // The elements of `indices` are unique, as they are indexed, so any sort will be // stable with respect to the original slice. We use `sort_unstable` here because - // it requires less memory allocation. + // it requires no memory allocation. indices.sort_unstable(); for i in 0..$slice.len() { let mut index = indices[i].1; @@ -374,24 +395,24 @@ impl<T> [T] { }}; } - let sz_u8 = mem::size_of::<(K, u8)>(); - let sz_u16 = mem::size_of::<(K, u16)>(); - let sz_u32 = mem::size_of::<(K, u32)>(); - let sz_usize = mem::size_of::<(K, usize)>(); - let len = self.len(); if len < 2 { return; } - if sz_u8 < sz_u16 && len <= (u8::MAX as usize) { - return sort_by_key!(u8, self, f); - } - if sz_u16 < sz_u32 && len <= (u16::MAX as usize) { - return sort_by_key!(u16, self, f); - } - if sz_u32 < sz_usize && len <= (u32::MAX as usize) { + + // Avoids binary-size usage in cases where the alignment doesn't work out to make this + // beneficial or on 32-bit platforms. + let is_using_u32_as_idx_type_helpful = + const { mem::size_of::<(K, u32)>() < mem::size_of::<(K, usize)>() }; + + // It's possible to instantiate this for u8 and u16 but, doing so is very wasteful in terms + // of compile-times and binary-size, the peak saved heap memory for u16 is (u8 + u16) -> 4 + // bytes * u16::MAX vs (u8 + u32) -> 8 bytes * u16::MAX, the saved heap memory is at peak + // ~262KB. + if is_using_u32_as_idx_type_helpful && len <= (u32::MAX as usize) { return sort_by_key!(u32, self, f); } + sort_by_key!(usize, self, f) } @@ -843,46 +864,17 @@ fn stable_sort<T, F>(v: &mut [T], mut is_less: F) where F: FnMut(&T, &T) -> bool, { - if T::IS_ZST { - // Sorting has no meaningful behavior on zero-sized types. Do nothing. - return; - } - - let elem_alloc_fn = |len: usize| -> *mut T { - // SAFETY: Creating the layout is safe as long as merge_sort never calls this with len > - // v.len(). Alloc in general will only be used as 'shadow-region' to store temporary swap - // elements. - unsafe { alloc::alloc(alloc::Layout::array::<T>(len).unwrap_unchecked()) as *mut T } - }; - - let elem_dealloc_fn = |buf_ptr: *mut T, len: usize| { - // SAFETY: Creating the layout is safe as long as merge_sort never calls this with len > - // v.len(). The caller must ensure that buf_ptr was created by elem_alloc_fn with the same - // len. - unsafe { - alloc::dealloc(buf_ptr as *mut u8, alloc::Layout::array::<T>(len).unwrap_unchecked()); - } - }; - - let run_alloc_fn = |len: usize| -> *mut sort::TimSortRun { - // SAFETY: Creating the layout is safe as long as merge_sort never calls this with an - // obscene length or 0. - unsafe { - alloc::alloc(alloc::Layout::array::<sort::TimSortRun>(len).unwrap_unchecked()) - as *mut sort::TimSortRun - } - }; + sort::stable::sort::<T, F, Vec<T>>(v, &mut is_less); +} - let run_dealloc_fn = |buf_ptr: *mut sort::TimSortRun, len: usize| { - // SAFETY: The caller must ensure that buf_ptr was created by elem_alloc_fn with the same - // len. - unsafe { - alloc::dealloc( - buf_ptr as *mut u8, - alloc::Layout::array::<sort::TimSortRun>(len).unwrap_unchecked(), - ); - } - }; +#[cfg(not(no_global_oom_handling))] +#[unstable(issue = "none", feature = "std_internals")] +impl<T> sort::stable::BufGuard<T> for Vec<T> { + fn with_capacity(capacity: usize) -> Self { + Vec::with_capacity(capacity) + } - sort::merge_sort(v, &mut is_less, elem_alloc_fn, elem_dealloc_fn, run_alloc_fn, run_dealloc_fn); + fn as_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<T>] { + self.spare_capacity_mut() + } } diff --git a/library/alloc/src/slice/tests.rs b/library/alloc/src/slice/tests.rs index 54bc4e77b16..0156b9928da 100644 --- a/library/alloc/src/slice/tests.rs +++ b/library/alloc/src/slice/tests.rs @@ -34,7 +34,7 @@ macro_rules! do_test { } let v = $input.to_owned(); - let _ = std::panic::catch_unwind(move || { + let _ = panic::catch_unwind(move || { let mut v = v; let mut panic_countdown = panic_countdown; v.$func(|a, b| { @@ -294,15 +294,20 @@ fn test_sort() { } } - // Sort using a completely random comparison function. - // This will reorder the elements *somehow*, but won't panic. - let mut v = [0; 500]; - for i in 0..v.len() { + const ORD_VIOLATION_MAX_LEN: usize = 500; + let mut v = [0; ORD_VIOLATION_MAX_LEN]; + for i in 0..ORD_VIOLATION_MAX_LEN { v[i] = i as i32; } - v.sort_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap()); + + // Sort using a completely random comparison function. This will reorder the elements *somehow*, + // it may panic but the original elements must still be present. + let _ = panic::catch_unwind(move || { + v.sort_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap()); + }); + v.sort(); - for i in 0..v.len() { + for i in 0..ORD_VIOLATION_MAX_LEN { assert_eq!(v[i], i as i32); } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index f9d884e0ea5..90672164cb9 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -10,6 +10,8 @@ use core::any::Any; use core::borrow; +#[cfg(not(no_global_oom_handling))] +use core::clone::CloneToUninit; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; @@ -30,8 +32,6 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; -#[cfg(not(no_global_oom_handling))] -use crate::alloc::WriteCloneIntoRaw; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; @@ -2150,7 +2150,8 @@ unsafe impl<T: ?Sized, A: Allocator> DerefPure for Arc<T, A> {} #[unstable(feature = "receiver_trait", issue = "none")] impl<T: ?Sized> Receiver for Arc<T> {} -impl<T: Clone, A: Allocator + Clone> Arc<T, A> { +#[cfg(not(no_global_oom_handling))] +impl<T: ?Sized + CloneToUninit, A: Allocator + Clone> Arc<T, A> { /// Makes a mutable reference into the given `Arc`. /// /// If there are other `Arc` pointers to the same allocation, then `make_mut` will @@ -2201,10 +2202,11 @@ impl<T: Clone, A: Allocator + Clone> Arc<T, A> { /// assert!(76 == *data); /// assert!(weak.upgrade().is_none()); /// ``` - #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "arc_unique", since = "1.4.0")] pub fn make_mut(this: &mut Self) -> &mut T { + let size_of_val = mem::size_of_val::<T>(&**this); + // Note that we hold both a strong reference and a weak reference. // Thus, releasing our strong reference only will not, by itself, cause // the memory to be deallocated. @@ -2215,13 +2217,19 @@ impl<T: Clone, A: Allocator + Clone> Arc<T, A> { // deallocated. if this.inner().strong.compare_exchange(1, 0, Acquire, Relaxed).is_err() { // Another strong pointer exists, so we must clone. - // Pre-allocate memory to allow writing the cloned value directly. - let mut arc = Self::new_uninit_in(this.alloc.clone()); - unsafe { - let data = Arc::get_mut_unchecked(&mut arc); - (**this).write_clone_into_raw(data.as_mut_ptr()); - *this = arc.assume_init(); - } + + let this_data_ref: &T = &**this; + // `in_progress` drops the allocation if we panic before finishing initializing it. + let mut in_progress: UniqueArcUninit<T, A> = + UniqueArcUninit::new(this_data_ref, this.alloc.clone()); + + let initialized_clone = unsafe { + // Clone. If the clone panics, `in_progress` will be dropped and clean up. + this_data_ref.clone_to_uninit(in_progress.data_ptr()); + // Cast type of pointer, now that it is initialized. + in_progress.into_arc() + }; + *this = initialized_clone; } else if this.inner().weak.load(Relaxed) != 1 { // Relaxed suffices in the above because this is fundamentally an // optimization: we are always racing with weak pointers being @@ -2240,11 +2248,22 @@ impl<T: Clone, A: Allocator + Clone> Arc<T, A> { let _weak = Weak { ptr: this.ptr, alloc: this.alloc.clone() }; // Can just steal the data, all that's left is Weaks - let mut arc = Self::new_uninit_in(this.alloc.clone()); + // + // We don't need panic-protection like the above branch does, but we might as well + // use the same mechanism. + let mut in_progress: UniqueArcUninit<T, A> = + UniqueArcUninit::new(&**this, this.alloc.clone()); unsafe { - let data = Arc::get_mut_unchecked(&mut arc); - data.as_mut_ptr().copy_from_nonoverlapping(&**this, 1); - ptr::write(this, arc.assume_init()); + // Initialize `in_progress` with move of **this. + // We have to express this in terms of bytes because `T: ?Sized`; there is no + // operation that just copies a value based on its `size_of_val()`. + ptr::copy_nonoverlapping( + ptr::from_ref(&**this).cast::<u8>(), + in_progress.data_ptr().cast::<u8>(), + size_of_val, + ); + + ptr::write(this, in_progress.into_arc()); } } else { // We were the sole reference of either kind; bump back up the @@ -3809,6 +3828,68 @@ fn data_offset_align(align: usize) -> usize { layout.size() + layout.padding_needed_for(align) } +/// A unique owning pointer to a [`ArcInner`] **that does not imply the contents are initialized,** +/// but will deallocate it (without dropping the value) when dropped. +/// +/// This is a helper for [`Arc::make_mut()`] to ensure correct cleanup on panic. +#[cfg(not(no_global_oom_handling))] +struct UniqueArcUninit<T: ?Sized, A: Allocator> { + ptr: NonNull<ArcInner<T>>, + layout_for_value: Layout, + alloc: Option<A>, +} + +#[cfg(not(no_global_oom_handling))] +impl<T: ?Sized, A: Allocator> UniqueArcUninit<T, A> { + /// Allocate a ArcInner with layout suitable to contain `for_value` or a clone of it. + fn new(for_value: &T, alloc: A) -> UniqueArcUninit<T, A> { + let layout = Layout::for_value(for_value); + let ptr = unsafe { + Arc::allocate_for_layout( + layout, + |layout_for_arcinner| alloc.allocate(layout_for_arcinner), + |mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const ArcInner<T>), + ) + }; + Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) } + } + + /// Returns the pointer to be written into to initialize the [`Arc`]. + fn data_ptr(&mut self) -> *mut T { + let offset = data_offset_align(self.layout_for_value.align()); + unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } + } + + /// Upgrade this into a normal [`Arc`]. + /// + /// # Safety + /// + /// The data must have been initialized (by writing to [`Self::data_ptr()`]). + unsafe fn into_arc(mut self) -> Arc<T, A> { + let ptr = self.ptr; + let alloc = self.alloc.take().unwrap(); + mem::forget(self); + // SAFETY: The pointer is valid as per `UniqueArcUninit::new`, and the caller is responsible + // for having initialized the data. + unsafe { Arc::from_ptr_in(ptr.as_ptr(), alloc) } + } +} + +#[cfg(not(no_global_oom_handling))] +impl<T: ?Sized, A: Allocator> Drop for UniqueArcUninit<T, A> { + fn drop(&mut self) { + // SAFETY: + // * new() produced a pointer safe to deallocate. + // * We own the pointer unless into_arc() was called, which forgets us. + unsafe { + self.alloc.take().unwrap().deallocate( + self.ptr.cast(), + arcinner_layout_for_value_layout(self.layout_for_value), + ); + } + } +} + #[stable(feature = "arc_error", since = "1.52.0")] impl<T: core::error::Error + ?Sized> core::error::Error for Arc<T> { #[allow(deprecated, deprecated_in_future)] diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index 22541a2b9d8..0dc193d82c5 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -154,6 +154,7 @@ //! } //! vec.truncate(write_idx); //! ``` + use crate::alloc::{handle_alloc_error, Global}; use core::alloc::Allocator; use core::alloc::Layout; diff --git a/library/alloc/tests/arc.rs b/library/alloc/tests/arc.rs index d564a30b103..c37a80dca95 100644 --- a/library/alloc/tests/arc.rs +++ b/library/alloc/tests/arc.rs @@ -209,3 +209,21 @@ fn weak_may_dangle() { // `val` dropped here while still borrowed // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak` } + +/// This is similar to the doc-test for `Arc::make_mut()`, but on an unsized type (slice). +#[test] +fn make_mut_unsized() { + use alloc::sync::Arc; + + let mut data: Arc<[i32]> = Arc::new([10, 20, 30]); + + Arc::make_mut(&mut data)[0] += 1; // Won't clone anything + let mut other_data = Arc::clone(&data); // Won't clone inner data + Arc::make_mut(&mut data)[1] += 1; // Clones inner data + Arc::make_mut(&mut data)[2] += 1; // Won't clone anything + Arc::make_mut(&mut other_data)[0] *= 10; // Won't clone anything + + // Now `data` and `other_data` point to different allocations. + assert_eq!(*data, [11, 21, 31]); + assert_eq!(*other_data, [110, 20, 30]); +} diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index d448c5338fc..d7ce65f6c53 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -36,6 +36,9 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::mem::{self, MaybeUninit}; +use crate::ptr; + /// A common trait for the ability to explicitly duplicate an object. /// /// Differs from [`Copy`] in that [`Copy`] is implicit and an inexpensive bit-wise copy, while @@ -204,6 +207,189 @@ pub struct AssertParamIsCopy<T: Copy + ?Sized> { _field: crate::marker::PhantomData<T>, } +/// A generalization of [`Clone`] to dynamically-sized types stored in arbitrary containers. +/// +/// This trait is implemented for all types implementing [`Clone`], and also [slices](slice) of all +/// such types. You may also implement this trait to enable cloning trait objects and custom DSTs +/// (structures containing dynamically-sized fields). +/// +/// # Safety +/// +/// Implementations must ensure that when `.clone_to_uninit(dst)` returns normally rather than +/// panicking, it always leaves `*dst` initialized as a valid value of type `Self`. +/// +/// # See also +/// +/// * [`Clone::clone_from`] is a safe function which may be used instead when `Self` is a [`Sized`] +/// and the destination is already initialized; it may be able to reuse allocations owned by +/// the destination. +/// * [`ToOwned`], which allocates a new destination container. +/// +/// [`ToOwned`]: ../../std/borrow/trait.ToOwned.html +#[unstable(feature = "clone_to_uninit", issue = "126799")] +pub unsafe trait CloneToUninit { + /// Performs copy-assignment from `self` to `dst`. + /// + /// This is analogous to to `std::ptr::write(dst, self.clone())`, + /// except that `self` may be a dynamically-sized type ([`!Sized`](Sized)). + /// + /// Before this function is called, `dst` may point to uninitialized memory. + /// After this function is called, `dst` will point to initialized memory; it will be + /// sound to create a `&Self` reference from the pointer. + /// + /// # Safety + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * `dst` must be [valid] for writes. + /// * `dst` must be properly aligned. + /// * `dst` must have the same [pointer metadata] (slice length or `dyn` vtable) as `self`. + /// + /// [valid]: ptr#safety + /// [pointer metadata]: crate::ptr::metadata() + /// + /// # Panics + /// + /// This function may panic. (For example, it might panic if memory allocation for a clone + /// of a value owned by `self` fails.) + /// If the call panics, then `*dst` should be treated as uninitialized memory; it must not be + /// read or dropped, because even if it was previously valid, it may have been partially + /// overwritten. + /// + /// The caller may also need to take care to deallocate the allocation pointed to by `dst`, + /// if applicable, to avoid a memory leak, and may need to take other precautions to ensure + /// soundness in the presence of unwinding. + /// + /// Implementors should avoid leaking values by, upon unwinding, dropping all component values + /// that might have already been created. (For example, if a `[Foo]` of length 3 is being + /// cloned, and the second of the three calls to `Foo::clone()` unwinds, then the first `Foo` + /// cloned should be dropped.) + unsafe fn clone_to_uninit(&self, dst: *mut Self); +} + +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl<T: Clone> CloneToUninit for T { + default unsafe fn clone_to_uninit(&self, dst: *mut Self) { + // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of + // ptr::write(). + unsafe { + // We hope the optimizer will figure out to create the cloned value in-place, + // skipping ever storing it on the stack and the copy to the destination. + ptr::write(dst, self.clone()); + } + } +} + +// Specialized implementation for types that are [`Copy`], not just [`Clone`], +// and can therefore be copied bitwise. +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl<T: Copy> CloneToUninit for T { + unsafe fn clone_to_uninit(&self, dst: *mut Self) { + // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of + // ptr::copy_nonoverlapping(). + unsafe { + ptr::copy_nonoverlapping(self, dst, 1); + } + } +} + +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl<T: Clone> CloneToUninit for [T] { + #[cfg_attr(debug_assertions, track_caller)] + default unsafe fn clone_to_uninit(&self, dst: *mut Self) { + let len = self.len(); + // This is the most likely mistake to make, so check it as a debug assertion. + debug_assert_eq!( + len, + dst.len(), + "clone_to_uninit() source and destination must have equal lengths", + ); + + // SAFETY: The produced `&mut` is valid because: + // * The caller is obligated to provide a pointer which is valid for writes. + // * All bytes pointed to are in MaybeUninit, so we don't care about the memory's + // initialization status. + let uninit_ref = unsafe { &mut *(dst as *mut [MaybeUninit<T>]) }; + + // Copy the elements + let mut initializing = InitializingSlice::from_fully_uninit(uninit_ref); + for element_ref in self.iter() { + // If the clone() panics, `initializing` will take care of the cleanup. + initializing.push(element_ref.clone()); + } + // If we reach here, then the entire slice is initialized, and we've satisfied our + // responsibilities to the caller. Disarm the cleanup guard by forgetting it. + mem::forget(initializing); + } +} + +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl<T: Copy> CloneToUninit for [T] { + #[cfg_attr(debug_assertions, track_caller)] + unsafe fn clone_to_uninit(&self, dst: *mut Self) { + let len = self.len(); + // This is the most likely mistake to make, so check it as a debug assertion. + debug_assert_eq!( + len, + dst.len(), + "clone_to_uninit() source and destination must have equal lengths", + ); + + // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of + // ptr::copy_nonoverlapping(). + unsafe { + ptr::copy_nonoverlapping(self.as_ptr(), dst.as_mut_ptr(), len); + } + } +} + +/// Ownership of a collection of values stored in a non-owned `[MaybeUninit<T>]`, some of which +/// are not yet initialized. This is sort of like a `Vec` that doesn't own its allocation. +/// Its responsibility is to provide cleanup on unwind by dropping the values that *are* +/// initialized, unless disarmed by forgetting. +/// +/// This is a helper for `impl<T: Clone> CloneToUninit for [T]`. +struct InitializingSlice<'a, T> { + data: &'a mut [MaybeUninit<T>], + /// Number of elements of `*self.data` that are initialized. + initialized_len: usize, +} + +impl<'a, T> InitializingSlice<'a, T> { + #[inline] + fn from_fully_uninit(data: &'a mut [MaybeUninit<T>]) -> Self { + Self { data, initialized_len: 0 } + } + + /// Push a value onto the end of the initialized part of the slice. + /// + /// # Panics + /// + /// Panics if the slice is already fully initialized. + #[inline] + fn push(&mut self, value: T) { + MaybeUninit::write(&mut self.data[self.initialized_len], value); + self.initialized_len += 1; + } +} + +impl<'a, T> Drop for InitializingSlice<'a, T> { + #[cold] // will only be invoked on unwind + fn drop(&mut self) { + let initialized_slice = ptr::slice_from_raw_parts_mut( + MaybeUninit::slice_as_mut_ptr(self.data), + self.initialized_len, + ); + // SAFETY: + // * the pointer is valid because it was made from a mutable reference + // * `initialized_len` counts the initialized elements as an invariant of this type, + // so each of the pointed-to elements is initialized and may be dropped. + unsafe { + ptr::drop_in_place::<[T]>(initialized_slice); + } + } +} + /// Implementations of `Clone` for primitive types. /// /// Implementations that cannot be described in Rust diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index f3f757ce69d..cff75870790 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -245,7 +245,6 @@ use self::Ordering::*; append_const_msg )] #[rustc_diagnostic_item = "PartialEq"] -#[const_trait] pub trait PartialEq<Rhs: ?Sized = Self> { /// This method tests for `self` and `other` values to be equal, and is used /// by `==`. @@ -1475,8 +1474,7 @@ mod impls { macro_rules! partial_eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const PartialEq for $t { + impl PartialEq for $t { #[inline] fn eq(&self, other: &$t) -> bool { (*self) == (*other) } #[inline] diff --git a/library/core/src/escape.rs b/library/core/src/escape.rs index f6ec30b9f79..b213cc2b916 100644 --- a/library/core/src/escape.rs +++ b/library/core/src/escape.rs @@ -60,7 +60,7 @@ const fn escape_ascii<const N: usize>(byte: u8) -> ([ascii::Char; N], Range<u8>) const fn escape_unicode<const N: usize>(c: char) -> ([ascii::Char; N], Range<u8>) { const { assert!(N >= 10 && N < u8::MAX as usize) }; - let c = u32::from(c); + let c = c as u32; // OR-ing `1` ensures that for `c == 0` the code computes that // one digit should be printed. diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 297f52e756b..d2a408485d1 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -515,7 +515,10 @@ impl CStr { #[inline] #[must_use] const fn as_non_null_ptr(&self) -> NonNull<c_char> { - NonNull::from(&self.inner).as_non_null_ptr() + // FIXME(effects) replace with `NonNull::from` + // SAFETY: a reference is never null + unsafe { NonNull::new_unchecked(&self.inner as *const [c_char] as *mut [c_char]) } + .as_non_null_ptr() } /// Returns the length of `self`. Like C's `strlen`, this does not include the nul terminator. diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 6e2d88c6b83..c3b16c34293 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -263,7 +263,7 @@ pub fn spin_loop() { /// extent to which it can block optimisations may vary depending upon the platform and code-gen /// backend used. Programs cannot rely on `black_box` for *correctness*, beyond it behaving as the /// identity function. As such, it **must not be relied upon to control critical program behavior.** -/// This _immediately_ precludes any direct use of this function for cryptographic or security +/// This also means that this function does not offer any guarantees for cryptographic or security /// purposes. /// /// [`std::convert::identity`]: crate::convert::identity diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index ec8488009b9..1daf1d723fb 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -445,6 +445,13 @@ define!( fn CastTransmute<T, U>(operand: T) -> U ); define!( + "mir_cast_ptr_to_ptr", + /// Emits a `CastKind::PtrToPtr` cast. + /// + /// This allows bypassing normal validation to generate strange casts. + fn CastPtrToPtr<T, U>(operand: T) -> U +); +define!( "mir_make_place", #[doc(hidden)] fn __internal_make_place<T>(place: T) -> *mut T diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index ef28bc99c4f..2d0b8825f43 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -199,29 +199,27 @@ // // Language features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(c_unwind))] +#![cfg_attr(bootstrap, feature(effects))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(asm_const)] #![feature(auto_traits)] -#![feature(c_unwind)] #![feature(cfg_sanitize)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_has_atomic_equal_alignment)] -#![feature(const_closures)] #![feature(const_fn_floating_point_arithmetic)] #![feature(const_for)] #![feature(const_mut_refs)] #![feature(const_precise_live_drops)] #![feature(const_refs_to_cell)] -#![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] #![feature(doc_cfg_hide)] #![feature(doc_notable_trait)] -#![feature(effects)] #![feature(extern_types)] #![feature(f128)] #![feature(f16)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 1d073a6d649..2e8be7bde4b 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -944,7 +944,6 @@ marker_impls! { #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] #[rustc_deny_explicit_impl(implement_via_object = false)] -#[const_trait] pub trait Destruct {} /// A marker for tuple types. diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 44889484963..d40e02352a1 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -484,7 +484,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_add(self, rhs: Self) -> Self { let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) { overflow_panic::add() } else { a } + if b { overflow_panic::add() } else { a } } /// Unchecked integer addition. Computes `self + rhs`, assuming overflow @@ -580,7 +580,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_add_unsigned(self, rhs: $UnsignedT) -> Self { let (a, b) = self.overflowing_add_unsigned(rhs); - if unlikely!(b) { overflow_panic::add() } else { a } + if b { overflow_panic::add() } else { a } } /// Checked integer subtraction. Computes `self - rhs`, returning `None` if @@ -636,7 +636,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_sub(self, rhs: Self) -> Self { let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) { overflow_panic::sub() } else { a } + if b { overflow_panic::sub() } else { a } } /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow @@ -732,7 +732,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_sub_unsigned(self, rhs: $UnsignedT) -> Self { let (a, b) = self.overflowing_sub_unsigned(rhs); - if unlikely!(b) { overflow_panic::sub() } else { a } + if b { overflow_panic::sub() } else { a } } /// Checked integer multiplication. Computes `self * rhs`, returning `None` if @@ -788,7 +788,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_mul(self, rhs: Self) -> Self { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) { overflow_panic::mul() } else { a } + if b { overflow_panic::mul() } else { a } } /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow @@ -902,7 +902,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_div(self, rhs: Self) -> Self { let (a, b) = self.overflowing_div(rhs); - if unlikely!(b) { overflow_panic::div() } else { a } + if b { overflow_panic::div() } else { a } } /// Checked Euclidean division. Computes `self.div_euclid(rhs)`, @@ -976,7 +976,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_div_euclid(self, rhs: Self) -> Self { let (a, b) = self.overflowing_div_euclid(rhs); - if unlikely!(b) { overflow_panic::div() } else { a } + if b { overflow_panic::div() } else { a } } /// Checked integer remainder. Computes `self % rhs`, returning `None` if @@ -1049,7 +1049,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_rem(self, rhs: Self) -> Self { let (a, b) = self.overflowing_rem(rhs); - if unlikely!(b) { overflow_panic::rem() } else { a } + if b { overflow_panic::rem() } else { a } } /// Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` @@ -1122,7 +1122,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_rem_euclid(self, rhs: Self) -> Self { let (a, b) = self.overflowing_rem_euclid(rhs); - if unlikely!(b) { overflow_panic::rem() } else { a } + if b { overflow_panic::rem() } else { a } } /// Checked negation. Computes `-self`, returning `None` if `self == MIN`. @@ -1210,7 +1210,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_neg(self) -> Self { let (a, b) = self.overflowing_neg(); - if unlikely!(b) { overflow_panic::neg() } else { a } + if b { overflow_panic::neg() } else { a } } /// Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger @@ -1273,7 +1273,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_shl(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) { overflow_panic::shl() } else { a } + if b { overflow_panic::shl() } else { a } } /// Unchecked shift left. Computes `self << rhs`, assuming that @@ -1371,7 +1371,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_shr(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) { overflow_panic::shr() } else { a } + if b { overflow_panic::shr() } else { a } } /// Unchecked shift right. Computes `self >> rhs`, assuming that diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 5956a08593a..0c6f06dc017 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -33,7 +33,6 @@ use super::{IntErrorKind, ParseIntError}; reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] -#[const_trait] pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed { #[doc(hidden)] type NonZeroInner: Sized + Copy; @@ -47,7 +46,6 @@ macro_rules! impl_zeroable_primitive { reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] - #[const_trait] pub trait Sealed {} $( @@ -70,14 +68,14 @@ macro_rules! impl_zeroable_primitive { reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] - impl const private::Sealed for $primitive {} + impl private::Sealed for $primitive {} #[unstable( feature = "nonzero_internals", reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] - unsafe impl const ZeroablePrimitive for $primitive { + unsafe impl ZeroablePrimitive for $primitive { type NonZeroInner = private::$NonZeroInner; } )+ diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index cdbd695008e..00450c2cda3 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -491,7 +491,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_add(self, rhs: Self) -> Self { let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) { overflow_panic ::add()} else {a} + if b { overflow_panic::add() } else { a } } /// Unchecked integer addition. Computes `self + rhs`, assuming overflow @@ -593,7 +593,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_add_signed(self, rhs: $SignedT) -> Self { let (a, b) = self.overflowing_add_signed(rhs); - if unlikely!(b) { overflow_panic ::add()} else {a} + if b { overflow_panic::add() } else { a } } /// Checked integer subtraction. Computes `self - rhs`, returning @@ -658,7 +658,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_sub(self, rhs: Self) -> Self { let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) { overflow_panic ::sub()} else {a} + if b { overflow_panic::sub() } else { a } } /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow @@ -779,7 +779,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_mul(self, rhs: Self) -> Self { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) { overflow_panic ::mul()} else {a} + if b { overflow_panic::mul() } else { a } } /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow @@ -1304,7 +1304,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_neg(self) -> Self { let (a, b) = self.overflowing_neg(); - if unlikely!(b) { overflow_panic::neg() } else { a } + if b { overflow_panic::neg() } else { a } } /// Checked shift left. Computes `self << rhs`, returning `None` @@ -1367,7 +1367,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_shl(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) { overflow_panic::shl() } else { a } + if b { overflow_panic::shl() } else { a } } /// Unchecked shift left. Computes `self << rhs`, assuming that @@ -1465,7 +1465,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_shr(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) { overflow_panic::shr() } else { a } + if b { overflow_panic::shr() } else { a } } /// Unchecked shift right. Computes `self >> rhs`, assuming that diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 5e77788d8ea..133ae04f026 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -73,7 +73,6 @@ append_const_msg )] #[doc(alias = "+")] -#[const_trait] pub trait Add<Rhs = Self> { /// The resulting type after applying the `+` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -95,8 +94,7 @@ pub trait Add<Rhs = Self> { macro_rules! add_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ops", issue = "90080")] - impl const Add for $t { + impl Add for $t { type Output = $t; #[inline] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 4d6ba2fa3b3..8ec7716012f 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -797,7 +797,8 @@ impl<T> Option<T> { #[inline] #[must_use] #[stable(feature = "option_as_slice", since = "1.75.0")] - pub fn as_slice(&self) -> &[T] { + #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] + pub const fn as_slice(&self) -> &[T] { // SAFETY: When the `Option` is `Some`, we're using the actual pointer // to the payload, with a length of 1, so this is equivalent to // `slice::from_ref`, and thus is safe. @@ -811,7 +812,7 @@ impl<T> Option<T> { unsafe { slice::from_raw_parts( (self as *const Self).byte_add(core::mem::offset_of!(Self, Some.0)).cast(), - usize::from(self.is_some()), + self.is_some() as usize, ) } } @@ -851,7 +852,8 @@ impl<T> Option<T> { #[inline] #[must_use] #[stable(feature = "option_as_slice", since = "1.75.0")] - pub fn as_mut_slice(&mut self) -> &mut [T] { + #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] + pub const fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: When the `Option` is `Some`, we're using the actual pointer // to the payload, with a length of 1, so this is equivalent to // `slice::from_mut`, and thus is safe. @@ -867,7 +869,7 @@ impl<T> Option<T> { unsafe { slice::from_raw_parts_mut( (self as *mut Self).byte_add(core::mem::offset_of!(Self, Some.0)).cast(), - usize::from(self.is_some()), + self.is_some() as usize, ) } } diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 0b8ff5cc012..c2a38194644 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -103,7 +103,8 @@ macro_rules! iterator { // so this new pointer is inside `self` and thus guaranteed to be non-null. unsafe { if_zst!(mut self, - len => *len = len.unchecked_sub(offset), + // Using the intrinsic directly avoids emitting a UbCheck + len => *len = crate::intrinsics::unchecked_sub(*len, offset), _end => self.ptr = self.ptr.add(offset), ); } @@ -119,7 +120,8 @@ macro_rules! iterator { // SAFETY: By our precondition, `offset` can be at most the // current length, so the subtraction can never overflow. len => unsafe { - *len = len.unchecked_sub(offset); + // Using the intrinsic directly avoids emitting a UbCheck + *len = crate::intrinsics::unchecked_sub(*len, offset); self.ptr }, // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 17b4f9ece9d..521c3248204 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -39,7 +39,6 @@ pub(crate) mod index; mod iter; mod raw; mod rotate; -mod select; mod specialize; #[unstable(feature = "str_internals", issue = "none")] @@ -83,10 +82,6 @@ pub use raw::{from_mut, from_ref}; #[unstable(feature = "slice_from_ptr_range", issue = "89792")] pub use raw::{from_mut_ptr_range, from_ptr_range}; -// This function is public only because there is no other way to unit test heapsort. -#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] -pub use sort::heapsort; - #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use index::SliceIndex; @@ -2884,21 +2879,26 @@ impl<T> [T] { self.binary_search_by(|k| f(k).cmp(b)) } - /// Sorts the slice, but might not preserve the order of equal elements. + /// Sorts the slice **without** preserving the initial order of equal elements. + /// + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. /// - /// This sort is unstable (i.e., may reorder equal elements), in-place - /// (i.e., does not allocate), and *O*(*n* \* log(*n*)) worst-case. + /// If `T: Ord` does not implement a total order the resulting order is unspecified. All + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if `T: Ord` panics. /// /// # Current implementation /// - /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, - /// which combines the fast average case of randomized quicksort with the fast worst case of - /// heapsort, while achieving linear time on slices with certain patterns. It uses some - /// randomization to avoid degenerate cases, but with a fixed seed to always provide - /// deterministic behavior. + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). /// /// It is typically faster than stable sorting, except in a few special cases, e.g., when the - /// slice consists of several concatenated sorted sequences. + /// slice is partially sorted. + /// + /// If `T: Ord` does not implement a total order, the implementation may panic. /// /// # Examples /// @@ -2909,25 +2909,29 @@ impl<T> [T] { /// assert!(v == [-5, -3, 1, 2, 4]); /// ``` /// - /// [pdqsort]: https://github.com/orlp/pdqsort + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort #[stable(feature = "sort_unstable", since = "1.20.0")] #[inline] pub fn sort_unstable(&mut self) where T: Ord, { - sort::quicksort(self, T::lt); + sort::unstable::sort(self, &mut T::lt); } - /// Sorts the slice with a comparator function, but might not preserve the order of equal - /// elements. + /// Sorts the slice with a comparator function, **without** preserving the initial order of + /// equal elements. /// - /// This sort is unstable (i.e., may reorder equal elements), in-place - /// (i.e., does not allocate), and *O*(*n* \* log(*n*)) worst-case. + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. /// - /// The comparator function must define a total ordering for the elements in the slice. If - /// the ordering is not total, the order of the elements is unspecified. An order is a - /// total order if it is (for all `a`, `b` and `c`): + /// The comparator function should define a total ordering for the elements in the slice. If the + /// ordering is not total, the order of the elements is unspecified. + /// + /// If the comparator function does not implement a total order the resulting order is + /// unspecified. All original elements will remain in the slice and any possible modifications + /// via interior mutability are observed in the input. Same is true if the comparator function + /// panics. A total order (for all `a`, `b` and `c`): /// /// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and /// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. @@ -2943,14 +2947,15 @@ impl<T> [T] { /// /// # Current implementation /// - /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, - /// which combines the fast average case of randomized quicksort with the fast worst case of - /// heapsort, while achieving linear time on slices with certain patterns. It uses some - /// randomization to avoid degenerate cases, but with a fixed seed to always provide - /// deterministic behavior. + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). /// /// It is typically faster than stable sorting, except in a few special cases, e.g., when the - /// slice consists of several concatenated sorted sequences. + /// slice is partially sorted. + /// + /// If `T: Ord` does not implement a total order, the implementation may panic. /// /// # Examples /// @@ -2964,34 +2969,37 @@ impl<T> [T] { /// assert!(v == [5, 4, 3, 2, 1]); /// ``` /// - /// [pdqsort]: https://github.com/orlp/pdqsort + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort #[stable(feature = "sort_unstable", since = "1.20.0")] #[inline] pub fn sort_unstable_by<F>(&mut self, mut compare: F) where F: FnMut(&T, &T) -> Ordering, { - sort::quicksort(self, |a, b| compare(a, b) == Ordering::Less); + sort::unstable::sort(self, &mut |a, b| compare(a, b) == Ordering::Less); } - /// Sorts the slice with a key extraction function, but might not preserve the order of equal - /// elements. + /// Sorts the slice with a key extraction function, **without** preserving the initial order of + /// equal elements. /// - /// This sort is unstable (i.e., may reorder equal elements), in-place - /// (i.e., does not allocate), and *O*(*m* \* *n* \* log(*n*)) worst-case, where the key function is - /// *O*(*m*). + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. + /// + /// If `K: Ord` does not implement a total order the resulting order is unspecified. + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if `K: Ord` panics. /// /// # Current implementation /// - /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, - /// which combines the fast average case of randomized quicksort with the fast worst case of - /// heapsort, while achieving linear time on slices with certain patterns. It uses some - /// randomization to avoid degenerate cases, but with a fixed seed to always provide - /// deterministic behavior. + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is partially sorted. /// - /// Due to its key calling strategy, [`sort_unstable_by_key`](#method.sort_unstable_by_key) - /// is likely to be slower than [`sort_by_cached_key`](#method.sort_by_cached_key) in - /// cases where the key function is expensive. + /// If `K: Ord` does not implement a total order, the implementation may panic. /// /// # Examples /// @@ -3002,7 +3010,7 @@ impl<T> [T] { /// assert!(v == [1, 2, -3, 4, -5]); /// ``` /// - /// [pdqsort]: https://github.com/orlp/pdqsort + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort #[stable(feature = "sort_unstable", since = "1.20.0")] #[inline] pub fn sort_unstable_by_key<K, F>(&mut self, mut f: F) @@ -3010,27 +3018,32 @@ impl<T> [T] { F: FnMut(&T) -> K, K: Ord, { - sort::quicksort(self, |a, b| f(a).lt(&f(b))); + sort::unstable::sort(self, &mut |a, b| f(a).lt(&f(b))); } - /// Reorder the slice such that the element at `index` after the reordering is at its final sorted position. + /// Reorder the slice such that the element at `index` after the reordering is at its final + /// sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index`. Additionally, this reordering is - /// unstable (i.e. any number of equal elements may end up at position `index`), in-place - /// (i.e. does not allocate), and runs in *O*(*n*) time. - /// This function is also known as "kth element" in other libraries. + /// unstable (i.e. any number of equal elements may end up at position `index`), in-place (i.e. + /// does not allocate), and runs in *O*(*n*) time. This function is also known as "kth element" + /// in other libraries. /// - /// It returns a triplet of the following from the reordered slice: - /// the subslice prior to `index`, the element at `index`, and the subslice after `index`; - /// accordingly, the values in those two subslices will respectively all be less-than-or-equal-to - /// and greater-than-or-equal-to the value of the element at `index`. + /// It returns a triplet of the following from the reordered slice: the subslice prior to + /// `index`, the element at `index`, and the subslice after `index`; accordingly, the values in + /// those two subslices will respectively all be less-than-or-equal-to and + /// greater-than-or-equal-to the value of the element at `index`. /// /// # Current implementation /// - /// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also - /// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for - /// pivot selection, which guarantees linear runtime for all inputs. + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is nearly fully sorted, where `slice::sort` may be faster. /// /// [`sort_unstable`]: slice::sort_unstable /// @@ -3058,35 +3071,40 @@ impl<T> [T] { /// v == [-3, -5, 1, 4, 2] || /// v == [-5, -3, 1, 4, 2]); /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] #[inline] pub fn select_nth_unstable(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) where T: Ord, { - select::partition_at_index(self, index, T::lt) + sort::select::partition_at_index(self, index, T::lt) } - /// Reorder the slice with a comparator function such that the element at `index` after the reordering is at - /// its final sorted position. + /// Reorder the slice with a comparator function such that the element at `index` after the + /// reordering is at its final sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index` using the comparator function. /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at - /// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time. - /// This function is also known as "kth element" in other libraries. + /// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. /// - /// It returns a triplet of the following from - /// the slice reordered according to the provided comparator function: the subslice prior to - /// `index`, the element at `index`, and the subslice after `index`; accordingly, the values in - /// those two subslices will respectively all be less-than-or-equal-to and greater-than-or-equal-to - /// the value of the element at `index`. + /// It returns a triplet of the following from the slice reordered according to the provided + /// comparator function: the subslice prior to `index`, the element at `index`, and the subslice + /// after `index`; accordingly, the values in those two subslices will respectively all be + /// less-than-or-equal-to and greater-than-or-equal-to the value of the element at `index`. /// /// # Current implementation /// - /// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also - /// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for - /// pivot selection, which guarantees linear runtime for all inputs. + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is nearly fully sorted, where `slice::sort` may be faster. /// /// [`sort_unstable`]: slice::sort_unstable /// @@ -3114,6 +3132,8 @@ impl<T> [T] { /// v == [4, 2, 1, -5, -3] || /// v == [4, 2, 1, -3, -5]); /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] #[inline] pub fn select_nth_unstable_by<F>( @@ -3124,29 +3144,32 @@ impl<T> [T] { where F: FnMut(&T, &T) -> Ordering, { - select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less) + sort::select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less) } - /// Reorder the slice with a key extraction function such that the element at `index` after the reordering is - /// at its final sorted position. + /// Reorder the slice with a key extraction function such that the element at `index` after the + /// reordering is at its final sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index` using the key extraction function. /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at - /// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time. - /// This function is also known as "kth element" in other libraries. + /// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. /// - /// It returns a triplet of the following from - /// the slice reordered according to the provided key extraction function: the subslice prior to - /// `index`, the element at `index`, and the subslice after `index`; accordingly, the values in - /// those two subslices will respectively all be less-than-or-equal-to and greater-than-or-equal-to - /// the value of the element at `index`. + /// It returns a triplet of the following from the slice reordered according to the provided key + /// extraction function: the subslice prior to `index`, the element at `index`, and the subslice + /// after `index`; accordingly, the values in those two subslices will respectively all be + /// less-than-or-equal-to and greater-than-or-equal-to the value of the element at `index`. /// /// # Current implementation /// - /// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also - /// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for - /// pivot selection, which guarantees linear runtime for all inputs. + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is nearly fully sorted, where `slice::sort` may be faster. /// /// [`sort_unstable`]: slice::sort_unstable /// @@ -3174,6 +3197,8 @@ impl<T> [T] { /// v == [2, 1, -3, 4, -5] || /// v == [2, 1, -3, -5, 4]); /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] #[inline] pub fn select_nth_unstable_by_key<K, F>( @@ -3185,7 +3210,7 @@ impl<T> [T] { F: FnMut(&T) -> K, K: Ord, { - select::partition_at_index(self, index, |a: &T, b: &T| f(a).lt(&f(b))) + sort::select::partition_at_index(self, index, |a: &T, b: &T| f(a).lt(&f(b))) } /// Moves all consecutive repeated elements to the end of the slice according to the diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs deleted file mode 100644 index 993a608f42b..00000000000 --- a/library/core/src/slice/sort.rs +++ /dev/null @@ -1,1383 +0,0 @@ -//! Slice sorting -//! -//! This module contains a sorting algorithm based on Orson Peters' pattern-defeating quicksort, -//! published at: <https://github.com/orlp/pdqsort> -//! -//! Unstable sorting is compatible with core because it doesn't allocate memory, unlike our -//! stable sorting implementation. -//! -//! In addition it also contains the core logic of the stable sort used by `slice::sort` based on -//! TimSort. - -use crate::cmp; -use crate::mem::{self, MaybeUninit, SizedTypeProperties}; -use crate::ptr; - -// When dropped, copies from `src` into `dest`. -struct InsertionHole<T> { - src: *const T, - dest: *mut T, -} - -impl<T> Drop for InsertionHole<T> { - fn drop(&mut self) { - // SAFETY: This is a helper class. Please refer to its usage for correctness. Namely, one - // must be sure that `src` and `dst` does not overlap as required by - // `ptr::copy_nonoverlapping` and are both valid for writes. - unsafe { - ptr::copy_nonoverlapping(self.src, self.dest, 1); - } - } -} - -/// Inserts `v[v.len() - 1]` into pre-sorted sequence `v[..v.len() - 1]` so that whole `v[..]` -/// becomes sorted. -unsafe fn insert_tail<T, F>(v: &mut [T], is_less: &mut F) -where - F: FnMut(&T, &T) -> bool, -{ - debug_assert!(v.len() >= 2); - - let arr_ptr = v.as_mut_ptr(); - let i = v.len() - 1; - - // SAFETY: caller must ensure v is at least len 2. - unsafe { - // See insert_head which talks about why this approach is beneficial. - let i_ptr = arr_ptr.add(i); - - // It's important that we use i_ptr here. If this check is positive and we continue, - // We want to make sure that no other copy of the value was seen by is_less. - // Otherwise we would have to copy it back. - if is_less(&*i_ptr, &*i_ptr.sub(1)) { - // It's important, that we use tmp for comparison from now on. As it is the value that - // will be copied back. And notionally we could have created a divergence if we copy - // back the wrong value. - let tmp = mem::ManuallyDrop::new(ptr::read(i_ptr)); - // Intermediate state of the insertion process is always tracked by `hole`, which - // serves two purposes: - // 1. Protects integrity of `v` from panics in `is_less`. - // 2. Fills the remaining hole in `v` in the end. - // - // Panic safety: - // - // If `is_less` panics at any point during the process, `hole` will get dropped and - // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it - // initially held exactly once. - let mut hole = InsertionHole { src: &*tmp, dest: i_ptr.sub(1) }; - ptr::copy_nonoverlapping(hole.dest, i_ptr, 1); - - // SAFETY: We know i is at least 1. - for j in (0..(i - 1)).rev() { - let j_ptr = arr_ptr.add(j); - if !is_less(&*tmp, &*j_ptr) { - break; - } - - ptr::copy_nonoverlapping(j_ptr, hole.dest, 1); - hole.dest = j_ptr; - } - // `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`. - } - } -} - -/// Inserts `v[0]` into pre-sorted sequence `v[1..]` so that whole `v[..]` becomes sorted. -/// -/// This is the integral subroutine of insertion sort. -unsafe fn insert_head<T, F>(v: &mut [T], is_less: &mut F) -where - F: FnMut(&T, &T) -> bool, -{ - debug_assert!(v.len() >= 2); - - // SAFETY: caller must ensure v is at least len 2. - unsafe { - if is_less(v.get_unchecked(1), v.get_unchecked(0)) { - let arr_ptr = v.as_mut_ptr(); - - // There are three ways to implement insertion here: - // - // 1. Swap adjacent elements until the first one gets to its final destination. - // However, this way we copy data around more than is necessary. If elements are big - // structures (costly to copy), this method will be slow. - // - // 2. Iterate until the right place for the first element is found. Then shift the - // elements succeeding it to make room for it and finally place it into the - // remaining hole. This is a good method. - // - // 3. Copy the first element into a temporary variable. Iterate until the right place - // for it is found. As we go along, copy every traversed element into the slot - // preceding it. Finally, copy data from the temporary variable into the remaining - // hole. This method is very good. Benchmarks demonstrated slightly better - // performance than with the 2nd method. - // - // All methods were benchmarked, and the 3rd showed best results. So we chose that one. - let tmp = mem::ManuallyDrop::new(ptr::read(arr_ptr)); - - // Intermediate state of the insertion process is always tracked by `hole`, which - // serves two purposes: - // 1. Protects integrity of `v` from panics in `is_less`. - // 2. Fills the remaining hole in `v` in the end. - // - // Panic safety: - // - // If `is_less` panics at any point during the process, `hole` will get dropped and - // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it - // initially held exactly once. - let mut hole = InsertionHole { src: &*tmp, dest: arr_ptr.add(1) }; - ptr::copy_nonoverlapping(arr_ptr.add(1), arr_ptr.add(0), 1); - - for i in 2..v.len() { - if !is_less(&v.get_unchecked(i), &*tmp) { - break; - } - ptr::copy_nonoverlapping(arr_ptr.add(i), arr_ptr.add(i - 1), 1); - hole.dest = arr_ptr.add(i); - } - // `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`. - } - } -} - -/// Sort `v` assuming `v[..offset]` is already sorted. -/// -/// Never inline this function to avoid code bloat. It still optimizes nicely and has practically no -/// performance impact. Even improving performance in some cases. -#[inline(never)] -pub(super) fn insertion_sort_shift_left<T, F>(v: &mut [T], offset: usize, is_less: &mut F) -where - F: FnMut(&T, &T) -> bool, -{ - let len = v.len(); - - // Using assert here improves performance. - assert!(offset != 0 && offset <= len); - - // Shift each element of the unsorted region v[i..] as far left as is needed to make v sorted. - for i in offset..len { - // SAFETY: we tested that `offset` must be at least 1, so this loop is only entered if len - // >= 2. The range is exclusive and we know `i` must be at least 1 so this slice has at - // >least len 2. - unsafe { - insert_tail(&mut v[..=i], is_less); - } - } -} - -/// Sort `v` assuming `v[offset..]` is already sorted. -/// -/// Never inline this function to avoid code bloat. It still optimizes nicely and has practically no -/// performance impact. Even improving performance in some cases. -#[inline(never)] -fn insertion_sort_shift_right<T, F>(v: &mut [T], offset: usize, is_less: &mut F) -where - F: FnMut(&T, &T) -> bool, -{ - let len = v.len(); - - // Using assert here improves performance. - assert!(offset != 0 && offset <= len && len >= 2); - - // Shift each element of the unsorted region v[..i] as far left as is needed to make v sorted. - for i in (0..offset).rev() { - // SAFETY: we tested that `offset` must be at least 1, so this loop is only entered if len - // >= 2.We ensured that the slice length is always at least 2 long. We know that start_found - // will be at least one less than end, and the range is exclusive. Which gives us i always - // <= (end - 2). - unsafe { - insert_head(&mut v[i..len], is_less); - } - } -} - -/// Partially sorts a slice by shifting several out-of-order elements around. -/// -/// Returns `true` if the slice is sorted at the end. This function is *O*(*n*) worst-case. -#[cold] -fn partial_insertion_sort<T, F>(v: &mut [T], is_less: &mut F) -> bool -where - F: FnMut(&T, &T) -> bool, -{ - // Maximum number of adjacent out-of-order pairs that will get shifted. - const MAX_STEPS: usize = 5; - // If the slice is shorter than this, don't shift any elements. - const SHORTEST_SHIFTING: usize = 50; - - let len = v.len(); - let mut i = 1; - - for _ in 0..MAX_STEPS { - // SAFETY: We already explicitly did the bound checking with `i < len`. - // All our subsequent indexing is only in the range `0 <= index < len` - unsafe { - // Find the next pair of adjacent out-of-order elements. - while i < len && !is_less(v.get_unchecked(i), v.get_unchecked(i - 1)) { - i += 1; - } - } - - // Are we done? - if i == len { - return true; - } - - // Don't shift elements on short arrays, that has a performance cost. - if len < SHORTEST_SHIFTING { - return false; - } - - // Swap the found pair of elements. This puts them in correct order. - v.swap(i - 1, i); - - if i >= 2 { - // Shift the smaller element to the left. - insertion_sort_shift_left(&mut v[..i], i - 1, is_less); - - // Shift the greater element to the right. - insertion_sort_shift_right(&mut v[..i], 1, is_less); - } - } - - // Didn't manage to sort the slice in the limited number of steps. - false -} - -/// Sorts `v` using heapsort, which guarantees *O*(*n* \* log(*n*)) worst-case. -#[cold] -#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] -pub fn heapsort<T, F>(v: &mut [T], mut is_less: F) -where - F: FnMut(&T, &T) -> bool, -{ - // This binary heap respects the invariant `parent >= child`. - let mut sift_down = |v: &mut [T], mut node| { - loop { - // Children of `node`. - let mut child = 2 * node + 1; - if child >= v.len() { - break; - } - - // Choose the greater child. - if child + 1 < v.len() { - // We need a branch to be sure not to out-of-bounds index, - // but it's highly predictable. The comparison, however, - // is better done branchless, especially for primitives. - child += is_less(&v[child], &v[child + 1]) as usize; - } - - // Stop if the invariant holds at `node`. - if !is_less(&v[node], &v[child]) { - break; - } - - // Swap `node` with the greater child, move one step down, and continue sifting. - v.swap(node, child); - node = child; - } - }; - - // Build the heap in linear time. - for i in (0..v.len() / 2).rev() { - sift_down(v, i); - } - - // Pop maximal elements from the heap. - for i in (1..v.len()).rev() { - v.swap(0, i); - sift_down(&mut v[..i], 0); - } -} - -/// Partitions `v` into elements smaller than `pivot`, followed by elements greater than or equal -/// to `pivot`. -/// -/// Returns the number of elements smaller than `pivot`. -/// -/// Partitioning is performed block-by-block in order to minimize the cost of branching operations. -/// This idea is presented in the [BlockQuicksort][pdf] paper. -/// -/// [pdf]: https://drops.dagstuhl.de/opus/volltexte/2016/6389/pdf/LIPIcs-ESA-2016-38.pdf -fn partition_in_blocks<T, F>(v: &mut [T], pivot: &T, is_less: &mut F) -> usize -where - F: FnMut(&T, &T) -> bool, -{ - // Number of elements in a typical block. - const BLOCK: usize = 128; - - // The partitioning algorithm repeats the following steps until completion: - // - // 1. Trace a block from the left side to identify elements greater than or equal to the pivot. - // 2. Trace a block from the right side to identify elements smaller than the pivot. - // 3. Exchange the identified elements between the left and right side. - // - // We keep the following variables for a block of elements: - // - // 1. `block` - Number of elements in the block. - // 2. `start` - Start pointer into the `offsets` array. - // 3. `end` - End pointer into the `offsets` array. - // 4. `offsets` - Indices of out-of-order elements within the block. - - // The current block on the left side (from `l` to `l.add(block_l)`). - let mut l = v.as_mut_ptr(); - let mut block_l = BLOCK; - let mut start_l = ptr::null_mut(); - let mut end_l = ptr::null_mut(); - let mut offsets_l = [MaybeUninit::<u8>::uninit(); BLOCK]; - - // The current block on the right side (from `r.sub(block_r)` to `r`). - // SAFETY: The documentation for .add() specifically mention that `vec.as_ptr().add(vec.len())` is always safe - let mut r = unsafe { l.add(v.len()) }; - let mut block_r = BLOCK; - let mut start_r = ptr::null_mut(); - let mut end_r = ptr::null_mut(); - let mut offsets_r = [MaybeUninit::<u8>::uninit(); BLOCK]; - - // FIXME: When we get VLAs, try creating one array of length `min(v.len(), 2 * BLOCK)` rather - // than two fixed-size arrays of length `BLOCK`. VLAs might be more cache-efficient. - - // Returns the number of elements between pointers `l` (inclusive) and `r` (exclusive). - fn width<T>(l: *mut T, r: *mut T) -> usize { - assert!(mem::size_of::<T>() > 0); - // FIXME: this should *likely* use `offset_from`, but more - // investigation is needed (including running tests in miri). - (r.addr() - l.addr()) / mem::size_of::<T>() - } - - loop { - // We are done with partitioning block-by-block when `l` and `r` get very close. Then we do - // some patch-up work in order to partition the remaining elements in between. - let is_done = width(l, r) <= 2 * BLOCK; - - if is_done { - // Number of remaining elements (still not compared to the pivot). - let mut rem = width(l, r); - if start_l < end_l || start_r < end_r { - rem -= BLOCK; - } - - // Adjust block sizes so that the left and right block don't overlap, but get perfectly - // aligned to cover the whole remaining gap. - if start_l < end_l { - block_r = rem; - } else if start_r < end_r { - block_l = rem; - } else { - // There were the same number of elements to switch on both blocks during the last - // iteration, so there are no remaining elements on either block. Cover the remaining - // items with roughly equally-sized blocks. - block_l = rem / 2; - block_r = rem - block_l; - } - debug_assert!(block_l <= BLOCK && block_r <= BLOCK); - debug_assert!(width(l, r) == block_l + block_r); - } - - if start_l == end_l { - // Trace `block_l` elements from the left side. - start_l = MaybeUninit::slice_as_mut_ptr(&mut offsets_l); - end_l = start_l; - let mut elem = l; - - for i in 0..block_l { - // SAFETY: The unsafety operations below involve the usage of the `offset`. - // According to the conditions required by the function, we satisfy them because: - // 1. `offsets_l` is stack-allocated, and thus considered separate allocated object. - // 2. The function `is_less` returns a `bool`. - // Casting a `bool` will never overflow `isize`. - // 3. We have guaranteed that `block_l` will be `<= BLOCK`. - // Plus, `end_l` was initially set to the begin pointer of `offsets_` which was declared on the stack. - // Thus, we know that even in the worst case (all invocations of `is_less` returns false) we will only be at most 1 byte pass the end. - // Another unsafety operation here is dereferencing `elem`. - // However, `elem` was initially the begin pointer to the slice which is always valid. - unsafe { - // Branchless comparison. - *end_l = i as u8; - end_l = end_l.add(!is_less(&*elem, pivot) as usize); - elem = elem.add(1); - } - } - } - - if start_r == end_r { - // Trace `block_r` elements from the right side. - start_r = MaybeUninit::slice_as_mut_ptr(&mut offsets_r); - end_r = start_r; - let mut elem = r; - - for i in 0..block_r { - // SAFETY: The unsafety operations below involve the usage of the `offset`. - // According to the conditions required by the function, we satisfy them because: - // 1. `offsets_r` is stack-allocated, and thus considered separate allocated object. - // 2. The function `is_less` returns a `bool`. - // Casting a `bool` will never overflow `isize`. - // 3. We have guaranteed that `block_r` will be `<= BLOCK`. - // Plus, `end_r` was initially set to the begin pointer of `offsets_` which was declared on the stack. - // Thus, we know that even in the worst case (all invocations of `is_less` returns true) we will only be at most 1 byte pass the end. - // Another unsafety operation here is dereferencing `elem`. - // However, `elem` was initially `1 * sizeof(T)` past the end and we decrement it by `1 * sizeof(T)` before accessing it. - // Plus, `block_r` was asserted to be less than `BLOCK` and `elem` will therefore at most be pointing to the beginning of the slice. - unsafe { - // Branchless comparison. - elem = elem.sub(1); - *end_r = i as u8; - end_r = end_r.add(is_less(&*elem, pivot) as usize); - } - } - } - - // Number of out-of-order elements to swap between the left and right side. - let count = cmp::min(width(start_l, end_l), width(start_r, end_r)); - - if count > 0 { - macro_rules! left { - () => { - l.add(usize::from(*start_l)) - }; - } - macro_rules! right { - () => { - r.sub(usize::from(*start_r) + 1) - }; - } - - // Instead of swapping one pair at the time, it is more efficient to perform a cyclic - // permutation. This is not strictly equivalent to swapping, but produces a similar - // result using fewer memory operations. - - // SAFETY: The use of `ptr::read` is valid because there is at least one element in - // both `offsets_l` and `offsets_r`, so `left!` is a valid pointer to read from. - // - // The uses of `left!` involve calls to `offset` on `l`, which points to the - // beginning of `v`. All the offsets pointed-to by `start_l` are at most `block_l`, so - // these `offset` calls are safe as all reads are within the block. The same argument - // applies for the uses of `right!`. - // - // The calls to `start_l.offset` are valid because there are at most `count-1` of them, - // plus the final one at the end of the unsafe block, where `count` is the minimum number - // of collected offsets in `offsets_l` and `offsets_r`, so there is no risk of there not - // being enough elements. The same reasoning applies to the calls to `start_r.offset`. - // - // The calls to `copy_nonoverlapping` are safe because `left!` and `right!` are guaranteed - // not to overlap, and are valid because of the reasoning above. - unsafe { - let tmp = ptr::read(left!()); - ptr::copy_nonoverlapping(right!(), left!(), 1); - - for _ in 1..count { - start_l = start_l.add(1); - ptr::copy_nonoverlapping(left!(), right!(), 1); - start_r = start_r.add(1); - ptr::copy_nonoverlapping(right!(), left!(), 1); - } - - ptr::copy_nonoverlapping(&tmp, right!(), 1); - mem::forget(tmp); - start_l = start_l.add(1); - start_r = start_r.add(1); - } - } - - if start_l == end_l { - // All out-of-order elements in the left block were moved. Move to the next block. - - // block-width-guarantee - // SAFETY: if `!is_done` then the slice width is guaranteed to be at least `2*BLOCK` wide. There - // are at most `BLOCK` elements in `offsets_l` because of its size, so the `offset` operation is - // safe. Otherwise, the debug assertions in the `is_done` case guarantee that - // `width(l, r) == block_l + block_r`, namely, that the block sizes have been adjusted to account - // for the smaller number of remaining elements. - l = unsafe { l.add(block_l) }; - } - - if start_r == end_r { - // All out-of-order elements in the right block were moved. Move to the previous block. - - // SAFETY: Same argument as [block-width-guarantee]. Either this is a full block `2*BLOCK`-wide, - // or `block_r` has been adjusted for the last handful of elements. - r = unsafe { r.sub(block_r) }; - } - - if is_done { - break; - } - } - - // All that remains now is at most one block (either the left or the right) with out-of-order - // elements that need to be moved. Such remaining elements can be simply shifted to the end - // within their block. - - if start_l < end_l { - // The left block remains. - // Move its remaining out-of-order elements to the far right. - debug_assert_eq!(width(l, r), block_l); - while start_l < end_l { - // remaining-elements-safety - // SAFETY: while the loop condition holds there are still elements in `offsets_l`, so it - // is safe to point `end_l` to the previous element. - // - // The `ptr::swap` is safe if both its arguments are valid for reads and writes: - // - Per the debug assert above, the distance between `l` and `r` is `block_l` - // elements, so there can be at most `block_l` remaining offsets between `start_l` - // and `end_l`. This means `r` will be moved at most `block_l` steps back, which - // makes the `r.offset` calls valid (at that point `l == r`). - // - `offsets_l` contains valid offsets into `v` collected during the partitioning of - // the last block, so the `l.offset` calls are valid. - unsafe { - end_l = end_l.sub(1); - ptr::swap(l.add(usize::from(*end_l)), r.sub(1)); - r = r.sub(1); - } - } - width(v.as_mut_ptr(), r) - } else if start_r < end_r { - // The right block remains. - // Move its remaining out-of-order elements to the far left. - debug_assert_eq!(width(l, r), block_r); - while start_r < end_r { - // SAFETY: See the reasoning in [remaining-elements-safety]. - unsafe { - end_r = end_r.sub(1); - ptr::swap(l, r.sub(usize::from(*end_r) + 1)); - l = l.add(1); - } - } - width(v.as_mut_ptr(), l) - } else { - // Nothing else to do, we're done. - width(v.as_mut_ptr(), l) - } -} - -/// Partitions `v` into elements smaller than `v[pivot]`, followed by elements greater than or -/// equal to `v[pivot]`. -/// -/// Returns a tuple of: -/// -/// 1. Number of elements smaller than `v[pivot]`. -/// 2. True if `v` was already partitioned. -pub(super) fn partition<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool) -where - F: FnMut(&T, &T) -> bool, -{ - let (mid, was_partitioned) = { - // Place the pivot at the beginning of slice. - v.swap(0, pivot); - let (pivot, v) = v.split_at_mut(1); - let pivot = &mut pivot[0]; - - // Read the pivot into a stack-allocated variable for efficiency. If a following comparison - // operation panics, the pivot will be automatically written back into the slice. - - // SAFETY: `pivot` is a reference to the first element of `v`, so `ptr::read` is safe. - let tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); - let _pivot_guard = InsertionHole { src: &*tmp, dest: pivot }; - let pivot = &*tmp; - - // Find the first pair of out-of-order elements. - let mut l = 0; - let mut r = v.len(); - - // SAFETY: The unsafety below involves indexing an array. - // For the first one: We already do the bounds checking here with `l < r`. - // For the second one: We initially have `l == 0` and `r == v.len()` and we checked that `l < r` at every indexing operation. - // From here we know that `r` must be at least `r == l` which was shown to be valid from the first one. - unsafe { - // Find the first element greater than or equal to the pivot. - while l < r && is_less(v.get_unchecked(l), pivot) { - l += 1; - } - - // Find the last element smaller that the pivot. - while l < r && !is_less(v.get_unchecked(r - 1), pivot) { - r -= 1; - } - } - - (l + partition_in_blocks(&mut v[l..r], pivot, is_less), l >= r) - - // `_pivot_guard` goes out of scope and writes the pivot (which is a stack-allocated - // variable) back into the slice where it originally was. This step is critical in ensuring - // safety! - }; - - // Place the pivot between the two partitions. - v.swap(0, mid); - - (mid, was_partitioned) -} - -/// Partitions `v` into elements equal to `v[pivot]` followed by elements greater than `v[pivot]`. -/// -/// Returns the number of elements equal to the pivot. It is assumed that `v` does not contain -/// elements smaller than the pivot. -pub(super) fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize -where - F: FnMut(&T, &T) -> bool, -{ - // Place the pivot at the beginning of slice. - v.swap(0, pivot); - let (pivot, v) = v.split_at_mut(1); - let pivot = &mut pivot[0]; - - // Read the pivot into a stack-allocated variable for efficiency. If a following comparison - // operation panics, the pivot will be automatically written back into the slice. - // SAFETY: The pointer here is valid because it is obtained from a reference to a slice. - let tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); - let _pivot_guard = InsertionHole { src: &*tmp, dest: pivot }; - let pivot = &*tmp; - - let len = v.len(); - if len == 0 { - return 0; - } - - // Now partition the slice. - let mut l = 0; - let mut r = len; - loop { - // SAFETY: The unsafety below involves indexing an array. - // For the first one: We already do the bounds checking here with `l < r`. - // For the second one: We initially have `l == 0` and `r == v.len()` and we checked that `l < r` at every indexing operation. - // From here we know that `r` must be at least `r == l` which was shown to be valid from the first one. - unsafe { - // Find the first element greater than the pivot. - while l < r && !is_less(pivot, v.get_unchecked(l)) { - l += 1; - } - - // Find the last element equal to the pivot. - loop { - r -= 1; - if l >= r || !is_less(pivot, v.get_unchecked(r)) { - break; - } - } - - // Are we done? - if l >= r { - break; - } - - // Swap the found pair of out-of-order elements. - let ptr = v.as_mut_ptr(); - ptr::swap(ptr.add(l), ptr.add(r)); - l += 1; - } - } - - // We found `l` elements equal to the pivot. Add 1 to account for the pivot itself. - l + 1 - - // `_pivot_guard` goes out of scope and writes the pivot (which is a stack-allocated variable) - // back into the slice where it originally was. This step is critical in ensuring safety! -} - -/// Scatters some elements around in an attempt to break patterns that might cause imbalanced -/// partitions in quicksort. -#[cold] -pub(super) fn break_patterns<T>(v: &mut [T]) { - let len = v.len(); - if len >= 8 { - let mut seed = len; - let mut gen_usize = || { - // Pseudorandom number generator from the "Xorshift RNGs" paper by George Marsaglia. - if usize::BITS <= 32 { - let mut r = seed as u32; - r ^= r << 13; - r ^= r >> 17; - r ^= r << 5; - seed = r as usize; - seed - } else { - let mut r = seed as u64; - r ^= r << 13; - r ^= r >> 7; - r ^= r << 17; - seed = r as usize; - seed - } - }; - - // Take random numbers modulo this number. - // The number fits into `usize` because `len` is not greater than `isize::MAX`. - let modulus = len.next_power_of_two(); - - // Some pivot candidates will be in the nearby of this index. Let's randomize them. - let pos = len / 4 * 2; - - for i in 0..3 { - // Generate a random number modulo `len`. However, in order to avoid costly operations - // we first take it modulo a power of two, and then decrease by `len` until it fits - // into the range `[0, len - 1]`. - let mut other = gen_usize() & (modulus - 1); - - // `other` is guaranteed to be less than `2 * len`. - if other >= len { - other -= len; - } - - v.swap(pos - 1 + i, other); - } - } -} - -/// Chooses a pivot in `v` and returns the index and `true` if the slice is likely already sorted. -/// -/// Elements in `v` might be reordered in the process. -pub(super) fn choose_pivot<T, F>(v: &mut [T], is_less: &mut F) -> (usize, bool) -where - F: FnMut(&T, &T) -> bool, -{ - // Minimum length to choose the median-of-medians method. - // Shorter slices use the simple median-of-three method. - const SHORTEST_MEDIAN_OF_MEDIANS: usize = 50; - // Maximum number of swaps that can be performed in this function. - const MAX_SWAPS: usize = 4 * 3; - - let len = v.len(); - - // Three indices near which we are going to choose a pivot. - let mut a = len / 4 * 1; - let mut b = len / 4 * 2; - let mut c = len / 4 * 3; - - // Counts the total number of swaps we are about to perform while sorting indices. - let mut swaps = 0; - - if len >= 8 { - // Swaps indices so that `v[a] <= v[b]`. - // SAFETY: `len >= 8` so there are at least two elements in the neighborhoods of - // `a`, `b` and `c`. This means the three calls to `sort_adjacent` result in - // corresponding calls to `sort3` with valid 3-item neighborhoods around each - // pointer, which in turn means the calls to `sort2` are done with valid - // references. Thus the `v.get_unchecked` calls are safe, as is the `ptr::swap` - // call. - let mut sort2 = |a: &mut usize, b: &mut usize| unsafe { - if is_less(v.get_unchecked(*b), v.get_unchecked(*a)) { - ptr::swap(a, b); - swaps += 1; - } - }; - - // Swaps indices so that `v[a] <= v[b] <= v[c]`. - let mut sort3 = |a: &mut usize, b: &mut usize, c: &mut usize| { - sort2(a, b); - sort2(b, c); - sort2(a, b); - }; - - if len >= SHORTEST_MEDIAN_OF_MEDIANS { - // Finds the median of `v[a - 1], v[a], v[a + 1]` and stores the index into `a`. - let mut sort_adjacent = |a: &mut usize| { - let tmp = *a; - sort3(&mut (tmp - 1), a, &mut (tmp + 1)); - }; - - // Find medians in the neighborhoods of `a`, `b`, and `c`. - sort_adjacent(&mut a); - sort_adjacent(&mut b); - sort_adjacent(&mut c); - } - - // Find the median among `a`, `b`, and `c`. - sort3(&mut a, &mut b, &mut c); - } - - if swaps < MAX_SWAPS { - (b, swaps == 0) - } else { - // The maximum number of swaps was performed. Chances are the slice is descending or mostly - // descending, so reversing will probably help sort it faster. - v.reverse(); - (len - 1 - b, true) - } -} - -/// Sorts `v` recursively. -/// -/// If the slice had a predecessor in the original array, it is specified as `pred`. -/// -/// `limit` is the number of allowed imbalanced partitions before switching to `heapsort`. If zero, -/// this function will immediately switch to heapsort. -fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T>, mut limit: u32) -where - F: FnMut(&T, &T) -> bool, -{ - // Slices of up to this length get sorted using insertion sort. - const MAX_INSERTION: usize = 20; - - // True if the last partitioning was reasonably balanced. - let mut was_balanced = true; - // True if the last partitioning didn't shuffle elements (the slice was already partitioned). - let mut was_partitioned = true; - - loop { - let len = v.len(); - - // Very short slices get sorted using insertion sort. - if len <= MAX_INSERTION { - if len >= 2 { - insertion_sort_shift_left(v, 1, is_less); - } - return; - } - - // If too many bad pivot choices were made, simply fall back to heapsort in order to - // guarantee `O(n * log(n))` worst-case. - if limit == 0 { - heapsort(v, is_less); - return; - } - - // If the last partitioning was imbalanced, try breaking patterns in the slice by shuffling - // some elements around. Hopefully we'll choose a better pivot this time. - if !was_balanced { - break_patterns(v); - limit -= 1; - } - - // Choose a pivot and try guessing whether the slice is already sorted. - let (pivot, likely_sorted) = choose_pivot(v, is_less); - - // If the last partitioning was decently balanced and didn't shuffle elements, and if pivot - // selection predicts the slice is likely already sorted... - if was_balanced && was_partitioned && likely_sorted { - // Try identifying several out-of-order elements and shifting them to correct - // positions. If the slice ends up being completely sorted, we're done. - if partial_insertion_sort(v, is_less) { - return; - } - } - - // If the chosen pivot is equal to the predecessor, then it's the smallest element in the - // slice. Partition the slice into elements equal to and elements greater than the pivot. - // This case is usually hit when the slice contains many duplicate elements. - if let Some(p) = pred { - if !is_less(p, &v[pivot]) { - let mid = partition_equal(v, pivot, is_less); - - // Continue sorting elements greater than the pivot. - v = &mut v[mid..]; - continue; - } - } - - // Partition the slice. - let (mid, was_p) = partition(v, pivot, is_less); - was_balanced = cmp::min(mid, len - mid) >= len / 8; - was_partitioned = was_p; - - // Split the slice into `left`, `pivot`, and `right`. - let (left, right) = v.split_at_mut(mid); - let (pivot, right) = right.split_at_mut(1); - let pivot = &pivot[0]; - - // Recurse into the shorter side only in order to minimize the total number of recursive - // calls and consume less stack space. Then just continue with the longer side (this is - // akin to tail recursion). - if left.len() < right.len() { - recurse(left, is_less, pred, limit); - v = right; - pred = Some(pivot); - } else { - recurse(right, is_less, Some(pivot), limit); - v = left; - } - } -} - -/// Sorts `v` using pattern-defeating quicksort, which is *O*(*n* \* log(*n*)) worst-case. -pub fn quicksort<T, F>(v: &mut [T], mut is_less: F) -where - F: FnMut(&T, &T) -> bool, -{ - // Sorting has no meaningful behavior on zero-sized types. - if T::IS_ZST { - return; - } - - // Limit the number of imbalanced partitions to `floor(log2(len)) + 1`. - let limit = usize::BITS - v.len().leading_zeros(); - - recurse(v, &mut is_less, None, limit); -} - -/// Merges non-decreasing runs `v[..mid]` and `v[mid..]` using `buf` as temporary storage, and -/// stores the result into `v[..]`. -/// -/// # Safety -/// -/// The two slices must be non-empty and `mid` must be in bounds. Buffer `buf` must be long enough -/// to hold a copy of the shorter slice. Also, `T` must not be a zero-sized type. -unsafe fn merge<T, F>(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F) -where - F: FnMut(&T, &T) -> bool, -{ - let len = v.len(); - let v = v.as_mut_ptr(); - - // SAFETY: mid and len must be in-bounds of v. - let (v_mid, v_end) = unsafe { (v.add(mid), v.add(len)) }; - - // The merge process first copies the shorter run into `buf`. Then it traces the newly copied - // run and the longer run forwards (or backwards), comparing their next unconsumed elements and - // copying the lesser (or greater) one into `v`. - // - // As soon as the shorter run is fully consumed, the process is done. If the longer run gets - // consumed first, then we must copy whatever is left of the shorter run into the remaining - // hole in `v`. - // - // Intermediate state of the process is always tracked by `hole`, which serves two purposes: - // 1. Protects integrity of `v` from panics in `is_less`. - // 2. Fills the remaining hole in `v` if the longer run gets consumed first. - // - // Panic safety: - // - // If `is_less` panics at any point during the process, `hole` will get dropped and fill the - // hole in `v` with the unconsumed range in `buf`, thus ensuring that `v` still holds every - // object it initially held exactly once. - let mut hole; - - if mid <= len - mid { - // The left run is shorter. - - // SAFETY: buf must have enough capacity for `v[..mid]`. - unsafe { - ptr::copy_nonoverlapping(v, buf, mid); - hole = MergeHole { start: buf, end: buf.add(mid), dest: v }; - } - - // Initially, these pointers point to the beginnings of their arrays. - let left = &mut hole.start; - let mut right = v_mid; - let out = &mut hole.dest; - - while *left < hole.end && right < v_end { - // Consume the lesser side. - // If equal, prefer the left run to maintain stability. - - // SAFETY: left and right must be valid and part of v same for out. - unsafe { - let is_l = is_less(&*right, &**left); - let to_copy = if is_l { right } else { *left }; - ptr::copy_nonoverlapping(to_copy, *out, 1); - *out = out.add(1); - right = right.add(is_l as usize); - *left = left.add(!is_l as usize); - } - } - } else { - // The right run is shorter. - - // SAFETY: buf must have enough capacity for `v[mid..]`. - unsafe { - ptr::copy_nonoverlapping(v_mid, buf, len - mid); - hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid }; - } - - // Initially, these pointers point past the ends of their arrays. - let left = &mut hole.dest; - let right = &mut hole.end; - let mut out = v_end; - - while v < *left && buf < *right { - // Consume the greater side. - // If equal, prefer the right run to maintain stability. - - // SAFETY: left and right must be valid and part of v same for out. - unsafe { - let is_l = is_less(&*right.sub(1), &*left.sub(1)); - *left = left.sub(is_l as usize); - *right = right.sub(!is_l as usize); - let to_copy = if is_l { *left } else { *right }; - out = out.sub(1); - ptr::copy_nonoverlapping(to_copy, out, 1); - } - } - } - // Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of - // it will now be copied into the hole in `v`. - - // When dropped, copies the range `start..end` into `dest..`. - struct MergeHole<T> { - start: *mut T, - end: *mut T, - dest: *mut T, - } - - impl<T> Drop for MergeHole<T> { - fn drop(&mut self) { - // SAFETY: `T` is not a zero-sized type, and these are pointers into a slice's elements. - unsafe { - let len = self.end.sub_ptr(self.start); - ptr::copy_nonoverlapping(self.start, self.dest, len); - } - } - } -} - -/// This merge sort borrows some (but not all) ideas from TimSort, which used to be described in -/// detail [here](https://github.com/python/cpython/blob/main/Objects/listsort.txt). However Python -/// has switched to a Powersort based implementation. -/// -/// The algorithm identifies strictly descending and non-descending subsequences, which are called -/// natural runs. There is a stack of pending runs yet to be merged. Each newly found run is pushed -/// onto the stack, and then some pairs of adjacent runs are merged until these two invariants are -/// satisfied: -/// -/// 1. for every `i` in `1..runs.len()`: `runs[i - 1].len > runs[i].len` -/// 2. for every `i` in `2..runs.len()`: `runs[i - 2].len > runs[i - 1].len + runs[i].len` -/// -/// The invariants ensure that the total running time is *O*(*n* \* log(*n*)) worst-case. -pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>( - v: &mut [T], - is_less: &mut CmpF, - elem_alloc_fn: ElemAllocF, - elem_dealloc_fn: ElemDeallocF, - run_alloc_fn: RunAllocF, - run_dealloc_fn: RunDeallocF, -) where - CmpF: FnMut(&T, &T) -> bool, - ElemAllocF: Fn(usize) -> *mut T, - ElemDeallocF: Fn(*mut T, usize), - RunAllocF: Fn(usize) -> *mut TimSortRun, - RunDeallocF: Fn(*mut TimSortRun, usize), -{ - // Slices of up to this length get sorted using insertion sort. - const MAX_INSERTION: usize = 20; - - // The caller should have already checked that. - debug_assert!(!T::IS_ZST); - - let len = v.len(); - - // Short arrays get sorted in-place via insertion sort to avoid allocations. - if len <= MAX_INSERTION { - if len >= 2 { - insertion_sort_shift_left(v, 1, is_less); - } - return; - } - - // Allocate a buffer to use as scratch memory. We keep the length 0 so we can keep in it - // shallow copies of the contents of `v` without risking the dtors running on copies if - // `is_less` panics. When merging two sorted runs, this buffer holds a copy of the shorter run, - // which will always have length at most `len / 2`. - let buf = BufGuard::new(len / 2, elem_alloc_fn, elem_dealloc_fn); - let buf_ptr = buf.buf_ptr.as_ptr(); - - let mut runs = RunVec::new(run_alloc_fn, run_dealloc_fn); - - let mut end = 0; - let mut start = 0; - - // Scan forward. Memory pre-fetching prefers forward scanning vs backwards scanning, and the - // code-gen is usually better. For the most sensitive types such as integers, these are merged - // bidirectionally at once. So there is no benefit in scanning backwards. - while end < len { - let (streak_end, was_reversed) = find_streak(&v[start..], is_less); - end += streak_end; - if was_reversed { - v[start..end].reverse(); - } - - // Insert some more elements into the run if it's too short. Insertion sort is faster than - // merge sort on short sequences, so this significantly improves performance. - end = provide_sorted_batch(v, start, end, is_less); - - // Push this run onto the stack. - runs.push(TimSortRun { start, len: end - start }); - start = end; - - // Merge some pairs of adjacent runs to satisfy the invariants. - while let Some(r) = collapse(runs.as_slice(), len) { - let left = runs[r]; - let right = runs[r + 1]; - let merge_slice = &mut v[left.start..right.start + right.len]; - // SAFETY: `buf_ptr` must hold enough capacity for the shorter of the two sides, and - // neither side may be on length 0. - unsafe { - merge(merge_slice, left.len, buf_ptr, is_less); - } - runs[r + 1] = TimSortRun { start: left.start, len: left.len + right.len }; - runs.remove(r); - } - } - - // Finally, exactly one run must remain in the stack. - debug_assert!(runs.len() == 1 && runs[0].start == 0 && runs[0].len == len); - - // Examines the stack of runs and identifies the next pair of runs to merge. More specifically, - // if `Some(r)` is returned, that means `runs[r]` and `runs[r + 1]` must be merged next. If the - // algorithm should continue building a new run instead, `None` is returned. - // - // TimSort is infamous for its buggy implementations, as described here: - // http://envisage-project.eu/timsort-specification-and-verification/ - // - // The gist of the story is: we must enforce the invariants on the top four runs on the stack. - // Enforcing them on just top three is not sufficient to ensure that the invariants will still - // hold for *all* runs in the stack. - // - // This function correctly checks invariants for the top four runs. Additionally, if the top - // run starts at index 0, it will always demand a merge operation until the stack is fully - // collapsed, in order to complete the sort. - #[inline] - fn collapse(runs: &[TimSortRun], stop: usize) -> Option<usize> { - let n = runs.len(); - if n >= 2 - && (runs[n - 1].start + runs[n - 1].len == stop - || runs[n - 2].len <= runs[n - 1].len - || (n >= 3 && runs[n - 3].len <= runs[n - 2].len + runs[n - 1].len) - || (n >= 4 && runs[n - 4].len <= runs[n - 3].len + runs[n - 2].len)) - { - if n >= 3 && runs[n - 3].len < runs[n - 1].len { Some(n - 3) } else { Some(n - 2) } - } else { - None - } - } - - // Extremely basic versions of Vec. - // Their use is super limited and by having the code here, it allows reuse between the sort - // implementations. - struct BufGuard<T, ElemDeallocF> - where - ElemDeallocF: Fn(*mut T, usize), - { - buf_ptr: ptr::NonNull<T>, - capacity: usize, - elem_dealloc_fn: ElemDeallocF, - } - - impl<T, ElemDeallocF> BufGuard<T, ElemDeallocF> - where - ElemDeallocF: Fn(*mut T, usize), - { - fn new<ElemAllocF>( - len: usize, - elem_alloc_fn: ElemAllocF, - elem_dealloc_fn: ElemDeallocF, - ) -> Self - where - ElemAllocF: Fn(usize) -> *mut T, - { - Self { - buf_ptr: ptr::NonNull::new(elem_alloc_fn(len)).unwrap(), - capacity: len, - elem_dealloc_fn, - } - } - } - - impl<T, ElemDeallocF> Drop for BufGuard<T, ElemDeallocF> - where - ElemDeallocF: Fn(*mut T, usize), - { - fn drop(&mut self) { - (self.elem_dealloc_fn)(self.buf_ptr.as_ptr(), self.capacity); - } - } - - struct RunVec<RunAllocF, RunDeallocF> - where - RunAllocF: Fn(usize) -> *mut TimSortRun, - RunDeallocF: Fn(*mut TimSortRun, usize), - { - buf_ptr: ptr::NonNull<TimSortRun>, - capacity: usize, - len: usize, - run_alloc_fn: RunAllocF, - run_dealloc_fn: RunDeallocF, - } - - impl<RunAllocF, RunDeallocF> RunVec<RunAllocF, RunDeallocF> - where - RunAllocF: Fn(usize) -> *mut TimSortRun, - RunDeallocF: Fn(*mut TimSortRun, usize), - { - fn new(run_alloc_fn: RunAllocF, run_dealloc_fn: RunDeallocF) -> Self { - // Most slices can be sorted with at most 16 runs in-flight. - const START_RUN_CAPACITY: usize = 16; - - Self { - buf_ptr: ptr::NonNull::new(run_alloc_fn(START_RUN_CAPACITY)).unwrap(), - capacity: START_RUN_CAPACITY, - len: 0, - run_alloc_fn, - run_dealloc_fn, - } - } - - fn push(&mut self, val: TimSortRun) { - if self.len == self.capacity { - let old_capacity = self.capacity; - let old_buf_ptr = self.buf_ptr.as_ptr(); - - self.capacity = self.capacity * 2; - self.buf_ptr = ptr::NonNull::new((self.run_alloc_fn)(self.capacity)).unwrap(); - - // SAFETY: buf_ptr new and old were correctly allocated and old_buf_ptr has - // old_capacity valid elements. - unsafe { - ptr::copy_nonoverlapping(old_buf_ptr, self.buf_ptr.as_ptr(), old_capacity); - } - - (self.run_dealloc_fn)(old_buf_ptr, old_capacity); - } - - // SAFETY: The invariant was just checked. - unsafe { - self.buf_ptr.as_ptr().add(self.len).write(val); - } - self.len += 1; - } - - fn remove(&mut self, index: usize) { - if index >= self.len { - panic!("Index out of bounds"); - } - - // SAFETY: buf_ptr needs to be valid and len invariant upheld. - unsafe { - // the place we are taking from. - let ptr = self.buf_ptr.as_ptr().add(index); - - // Shift everything down to fill in that spot. - ptr::copy(ptr.add(1), ptr, self.len - index - 1); - } - self.len -= 1; - } - - fn as_slice(&self) -> &[TimSortRun] { - // SAFETY: Safe as long as buf_ptr is valid and len invariant was upheld. - unsafe { &*ptr::slice_from_raw_parts(self.buf_ptr.as_ptr(), self.len) } - } - - fn len(&self) -> usize { - self.len - } - } - - impl<RunAllocF, RunDeallocF> core::ops::Index<usize> for RunVec<RunAllocF, RunDeallocF> - where - RunAllocF: Fn(usize) -> *mut TimSortRun, - RunDeallocF: Fn(*mut TimSortRun, usize), - { - type Output = TimSortRun; - - fn index(&self, index: usize) -> &Self::Output { - if index < self.len { - // SAFETY: buf_ptr and len invariant must be upheld. - unsafe { - return &*(self.buf_ptr.as_ptr().add(index)); - } - } - - panic!("Index out of bounds"); - } - } - - impl<RunAllocF, RunDeallocF> core::ops::IndexMut<usize> for RunVec<RunAllocF, RunDeallocF> - where - RunAllocF: Fn(usize) -> *mut TimSortRun, - RunDeallocF: Fn(*mut TimSortRun, usize), - { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - if index < self.len { - // SAFETY: buf_ptr and len invariant must be upheld. - unsafe { - return &mut *(self.buf_ptr.as_ptr().add(index)); - } - } - - panic!("Index out of bounds"); - } - } - - impl<RunAllocF, RunDeallocF> Drop for RunVec<RunAllocF, RunDeallocF> - where - RunAllocF: Fn(usize) -> *mut TimSortRun, - RunDeallocF: Fn(*mut TimSortRun, usize), - { - fn drop(&mut self) { - // As long as TimSortRun is Copy we don't need to drop them individually but just the - // whole allocation. - (self.run_dealloc_fn)(self.buf_ptr.as_ptr(), self.capacity); - } - } -} - -/// Internal type used by merge_sort. -#[derive(Clone, Copy, Debug)] -pub struct TimSortRun { - len: usize, - start: usize, -} - -/// Takes a range as denoted by start and end, that is already sorted and extends it to the right if -/// necessary with sorts optimized for smaller ranges such as insertion sort. -fn provide_sorted_batch<T, F>(v: &mut [T], start: usize, mut end: usize, is_less: &mut F) -> usize -where - F: FnMut(&T, &T) -> bool, -{ - let len = v.len(); - assert!(end >= start && end <= len); - - // This value is a balance between least comparisons and best performance, as - // influenced by for example cache locality. - const MIN_INSERTION_RUN: usize = 10; - - // Insert some more elements into the run if it's too short. Insertion sort is faster than - // merge sort on short sequences, so this significantly improves performance. - let start_end_diff = end - start; - - if start_end_diff < MIN_INSERTION_RUN && end < len { - // v[start_found..end] are elements that are already sorted in the input. We want to extend - // the sorted region to the left, so we push up MIN_INSERTION_RUN - 1 to the right. Which is - // more efficient that trying to push those already sorted elements to the left. - end = cmp::min(start + MIN_INSERTION_RUN, len); - let presorted_start = cmp::max(start_end_diff, 1); - - insertion_sort_shift_left(&mut v[start..end], presorted_start, is_less); - } - - end -} - -/// Finds a streak of presorted elements starting at the beginning of the slice. Returns the first -/// value that is not part of said streak, and a bool denoting whether the streak was reversed. -/// Streaks can be increasing or decreasing. -fn find_streak<T, F>(v: &[T], is_less: &mut F) -> (usize, bool) -where - F: FnMut(&T, &T) -> bool, -{ - let len = v.len(); - - if len < 2 { - return (len, false); - } - - let mut end = 2; - - // SAFETY: See below specific. - unsafe { - // SAFETY: We checked that len >= 2, so 0 and 1 are valid indices. - let assume_reverse = is_less(v.get_unchecked(1), v.get_unchecked(0)); - - // SAFETY: We know end >= 2 and check end < len. - // From that follows that accessing v at end and end - 1 is safe. - if assume_reverse { - while end < len && is_less(v.get_unchecked(end), v.get_unchecked(end - 1)) { - end += 1; - } - - (end, true) - } else { - while end < len && !is_less(v.get_unchecked(end), v.get_unchecked(end - 1)) { - end += 1; - } - (end, false) - } - } -} diff --git a/library/core/src/slice/sort/mod.rs b/library/core/src/slice/sort/mod.rs new file mode 100644 index 00000000000..79852708b81 --- /dev/null +++ b/library/core/src/slice/sort/mod.rs @@ -0,0 +1,8 @@ +//! This module and the contained sub-modules contains the code for efficient and robust sort +//! implementations, as well as the domain adjacent implementation of `select_nth_unstable`. + +pub mod stable; +pub mod unstable; + +pub(crate) mod select; +pub(crate) mod shared; diff --git a/library/core/src/slice/select.rs b/library/core/src/slice/sort/select.rs index ffc193578e0..6212def3041 100644 --- a/library/core/src/slice/select.rs +++ b/library/core/src/slice/sort/select.rs @@ -1,45 +1,78 @@ -//! Slice selection -//! //! This module contains the implementation for `slice::select_nth_unstable`. -//! It uses an introselect algorithm based on Orson Peters' pattern-defeating quicksort, -//! published at: <https://github.com/orlp/pdqsort> +//! It uses an introselect algorithm based on ipnsort by Lukas Bergdoll and Orson Peters, +//! published at: <https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort> //! //! The fallback algorithm used for introselect is Median of Medians using Tukey's Ninther //! for pivot selection. Using this as a fallback ensures O(n) worst case running time with //! better performance than one would get using heapsort as fallback. -use crate::cmp; use crate::mem::{self, SizedTypeProperties}; -use crate::slice::sort::{ - break_patterns, choose_pivot, insertion_sort_shift_left, partition, partition_equal, -}; -// For slices of up to this length it's probably faster to simply sort them. -// Defined at the module scope because it's used in multiple functions. -const MAX_INSERTION: usize = 10; +use crate::slice::sort::shared::pivot::choose_pivot; +use crate::slice::sort::shared::smallsort::insertion_sort_shift_left; +use crate::slice::sort::unstable::quicksort::partition; + +/// Reorder the slice such that the element at `index` is at its final sorted position. +pub(crate) fn partition_at_index<T, F>( + v: &mut [T], + index: usize, + mut is_less: F, +) -> (&mut [T], &mut T, &mut [T]) +where + F: FnMut(&T, &T) -> bool, +{ + let len = v.len(); + + // Puts a lower limit of 1 on `len`. + if index >= len { + panic!("partition_at_index index {} greater than length of slice {}", index, len); + } + + if T::IS_ZST { + // Sorting has no meaningful behavior on zero-sized types. Do nothing. + } else if index == len - 1 { + // Find max element and place it in the last position of the array. We're free to use + // `unwrap()` here because we checked that `v` is not empty. + let max_idx = max_index(v, &mut is_less).unwrap(); + v.swap(max_idx, index); + } else if index == 0 { + // Find min element and place it in the first position of the array. We're free to use + // `unwrap()` here because we checked that `v` is not empty. + let min_idx = min_index(v, &mut is_less).unwrap(); + v.swap(min_idx, index); + } else { + partition_at_index_loop(v, index, None, &mut is_less); + } + + let (left, right) = v.split_at_mut(index); + let (pivot, right) = right.split_at_mut(1); + let pivot = &mut pivot[0]; + (left, pivot, right) +} + +// For small sub-slices it's faster to use a dedicated small-sort, but because it is only called at +// most once, it doesn't make sense to use something more sophisticated than insertion-sort. +const INSERTION_SORT_THRESHOLD: usize = 16; fn partition_at_index_loop<'a, T, F>( mut v: &'a mut [T], mut index: usize, + mut ancestor_pivot: Option<&'a T>, is_less: &mut F, - mut pred: Option<&'a T>, ) where F: FnMut(&T, &T) -> bool, { - // Limit the amount of iterations and fall back to fast deterministic selection - // to ensure O(n) worst case running time. This limit needs to be constant, because - // using `ilog2(len)` like in `sort` would result in O(n log n) time complexity. - // The exact value of the limit is chosen somewhat arbitrarily, but for most inputs bad pivot - // selections should be relatively rare, so the limit usually shouldn't be reached - // anyways. + // Limit the amount of iterations and fall back to fast deterministic selection to ensure O(n) + // worst case running time. This limit needs to be constant, because using `ilog2(len)` like in + // `sort` would result in O(n log n) time complexity. The exact value of the limit is chosen + // somewhat arbitrarily, but for most inputs bad pivot selections should be relatively rare, so + // the limit is reached for sub-slices len / (2^limit or less). Which makes the remaining work + // with the fallback minimal in relative terms. let mut limit = 16; - // True if the last partitioning was reasonably balanced. - let mut was_balanced = true; - loop { - if v.len() <= MAX_INSERTION { - if v.len() > 1 { + if v.len() <= INSERTION_SORT_THRESHOLD { + if v.len() >= 2 { insertion_sort_shift_left(v, 1, is_less); } return; @@ -50,38 +83,38 @@ fn partition_at_index_loop<'a, T, F>( return; } - // If the last partitioning was imbalanced, try breaking patterns in the slice by shuffling - // some elements around. Hopefully we'll choose a better pivot this time. - if !was_balanced { - break_patterns(v); - limit -= 1; - } + limit -= 1; // Choose a pivot - let (pivot, _) = choose_pivot(v, is_less); + let pivot_pos = choose_pivot(v, is_less); // If the chosen pivot is equal to the predecessor, then it's the smallest element in the // slice. Partition the slice into elements equal to and elements greater than the pivot. // This case is usually hit when the slice contains many duplicate elements. - if let Some(p) = pred { - if !is_less(p, &v[pivot]) { - let mid = partition_equal(v, pivot, is_less); + if let Some(p) = ancestor_pivot { + // SAFETY: choose_pivot promises to return a valid pivot position. + let pivot = unsafe { v.get_unchecked(pivot_pos) }; + + if !is_less(p, pivot) { + let num_lt = partition(v, pivot_pos, &mut |a, b| !is_less(b, a)); + + // Continue sorting elements greater than the pivot. We know that `mid` contains + // the pivot. So we can continue after `mid`. + let mid = num_lt + 1; // If we've passed our index, then we're good. if mid > index { return; } - // Otherwise, continue sorting elements greater than the pivot. v = &mut v[mid..]; index = index - mid; - pred = None; + ancestor_pivot = None; continue; } } - let (mid, _) = partition(v, pivot, is_less); - was_balanced = cmp::min(mid, v.len() - mid) >= v.len() / 8; + let mid = partition(v, pivot_pos, is_less); // Split the slice into `left`, `pivot`, and `right`. let (left, right) = v.split_at_mut(mid); @@ -91,7 +124,7 @@ fn partition_at_index_loop<'a, T, F>( if mid < index { v = right; index = index - mid - 1; - pred = Some(pivot); + ancestor_pivot = Some(pivot); } else if mid > index { v = left; } else { @@ -122,41 +155,6 @@ fn max_index<T, F: FnMut(&T, &T) -> bool>(slice: &[T], is_less: &mut F) -> Optio .map(|(i, _)| i) } -/// Reorder the slice such that the element at `index` is at its final sorted position. -pub fn partition_at_index<T, F>( - v: &mut [T], - index: usize, - mut is_less: F, -) -> (&mut [T], &mut T, &mut [T]) -where - F: FnMut(&T, &T) -> bool, -{ - if index >= v.len() { - panic!("partition_at_index index {} greater than length of slice {}", index, v.len()); - } - - if T::IS_ZST { - // Sorting has no meaningful behavior on zero-sized types. Do nothing. - } else if index == v.len() - 1 { - // Find max element and place it in the last position of the array. We're free to use - // `unwrap()` here because we know v must not be empty. - let max_idx = max_index(v, &mut is_less).unwrap(); - v.swap(max_idx, index); - } else if index == 0 { - // Find min element and place it in the first position of the array. We're free to use - // `unwrap()` here because we know v must not be empty. - let min_idx = min_index(v, &mut is_less).unwrap(); - v.swap(min_idx, index); - } else { - partition_at_index_loop(v, index, &mut is_less, None); - } - - let (left, right) = v.split_at_mut(index); - let (pivot, right) = right.split_at_mut(1); - let pivot = &mut pivot[0]; - (left, pivot, right) -} - /// Selection algorithm to select the k-th element from the slice in guaranteed O(n) time. /// This is essentially a quickselect that uses Tukey's Ninther for pivot selection fn median_of_medians<T, F: FnMut(&T, &T) -> bool>(mut v: &mut [T], is_less: &mut F, mut k: usize) { @@ -168,8 +166,8 @@ fn median_of_medians<T, F: FnMut(&T, &T) -> bool>(mut v: &mut [T], is_less: &mut // We now know that `k < v.len() <= isize::MAX` loop { - if v.len() <= MAX_INSERTION { - if v.len() > 1 { + if v.len() <= INSERTION_SORT_THRESHOLD { + if v.len() >= 2 { insertion_sort_shift_left(v, 1, is_less); } return; @@ -232,7 +230,8 @@ fn median_of_ninthers<T, F: FnMut(&T, &T) -> bool>(v: &mut [T], is_less: &mut F) } median_of_medians(&mut v[lo..lo + frac], is_less, pivot); - partition(v, lo + pivot, is_less).0 + + partition(v, lo + pivot, is_less) } /// Moves around the 9 elements at the indices a..i, such that diff --git a/library/core/src/slice/sort/shared/mod.rs b/library/core/src/slice/sort/shared/mod.rs new file mode 100644 index 00000000000..ad1171bfc6a --- /dev/null +++ b/library/core/src/slice/sort/shared/mod.rs @@ -0,0 +1,45 @@ +use crate::marker::Freeze; + +pub(crate) mod pivot; +pub(crate) mod smallsort; + +/// SAFETY: this is safety relevant, how does this interact with the soundness holes in +/// specialization? +#[rustc_unsafe_specialization_marker] +pub(crate) trait FreezeMarker {} + +impl<T: Freeze> FreezeMarker for T {} + +/// Finds a run of sorted elements starting at the beginning of the slice. +/// +/// Returns the length of the run, and a bool that is false when the run +/// is ascending, and true if the run strictly descending. +#[inline(always)] +pub(crate) fn find_existing_run<T, F: FnMut(&T, &T) -> bool>( + v: &[T], + is_less: &mut F, +) -> (usize, bool) { + let len = v.len(); + if len < 2 { + return (len, false); + } + + // SAFETY: We checked that len >= 2, so 0 and 1 are valid indices. + // This also means that run_len < len implies run_len and run_len - 1 + // are valid indices as well. + unsafe { + let mut run_len = 2; + let strictly_descending = is_less(v.get_unchecked(1), v.get_unchecked(0)); + if strictly_descending { + while run_len < len && is_less(v.get_unchecked(run_len), v.get_unchecked(run_len - 1)) { + run_len += 1; + } + } else { + while run_len < len && !is_less(v.get_unchecked(run_len), v.get_unchecked(run_len - 1)) + { + run_len += 1; + } + } + (run_len, strictly_descending) + } +} diff --git a/library/core/src/slice/sort/shared/pivot.rs b/library/core/src/slice/sort/shared/pivot.rs new file mode 100644 index 00000000000..255a1eb6c88 --- /dev/null +++ b/library/core/src/slice/sort/shared/pivot.rs @@ -0,0 +1,88 @@ +//! This module contains the logic for pivot selection. + +use crate::intrinsics; + +// Recursively select a pseudomedian if above this threshold. +const PSEUDO_MEDIAN_REC_THRESHOLD: usize = 64; + +/// Selects a pivot from `v`. Algorithm taken from glidesort by Orson Peters. +/// +/// This chooses a pivot by sampling an adaptive amount of points, approximating +/// the quality of a median of sqrt(n) elements. +pub fn choose_pivot<T, F: FnMut(&T, &T) -> bool>(v: &[T], is_less: &mut F) -> usize { + // We use unsafe code and raw pointers here because we're dealing with + // heavy recursion. Passing safe slices around would involve a lot of + // branches and function call overhead. + + let len = v.len(); + if len < 8 { + intrinsics::abort(); + } + + // SAFETY: a, b, c point to initialized regions of len_div_8 elements, + // satisfying median3 and median3_rec's preconditions as v_base points + // to an initialized region of n = len elements. + unsafe { + let v_base = v.as_ptr(); + let len_div_8 = len / 8; + + let a = v_base; // [0, floor(n/8)) + let b = v_base.add(len_div_8 * 4); // [4*floor(n/8), 5*floor(n/8)) + let c = v_base.add(len_div_8 * 7); // [7*floor(n/8), 8*floor(n/8)) + + if len < PSEUDO_MEDIAN_REC_THRESHOLD { + median3(&*a, &*b, &*c, is_less).sub_ptr(v_base) + } else { + median3_rec(a, b, c, len_div_8, is_less).sub_ptr(v_base) + } + } +} + +/// Calculates an approximate median of 3 elements from sections a, b, c, or +/// recursively from an approximation of each, if they're large enough. By +/// dividing the size of each section by 8 when recursing we have logarithmic +/// recursion depth and overall sample from f(n) = 3*f(n/8) -> f(n) = +/// O(n^(log(3)/log(8))) ~= O(n^0.528) elements. +/// +/// SAFETY: a, b, c must point to the start of initialized regions of memory of +/// at least n elements. +unsafe fn median3_rec<T, F: FnMut(&T, &T) -> bool>( + mut a: *const T, + mut b: *const T, + mut c: *const T, + n: usize, + is_less: &mut F, +) -> *const T { + // SAFETY: a, b, c still point to initialized regions of n / 8 elements, + // by the exact same logic as in choose_pivot. + unsafe { + if n * 8 >= PSEUDO_MEDIAN_REC_THRESHOLD { + let n8 = n / 8; + a = median3_rec(a, a.add(n8 * 4), a.add(n8 * 7), n8, is_less); + b = median3_rec(b, b.add(n8 * 4), b.add(n8 * 7), n8, is_less); + c = median3_rec(c, c.add(n8 * 4), c.add(n8 * 7), n8, is_less); + } + median3(&*a, &*b, &*c, is_less) + } +} + +/// Calculates the median of 3 elements. +/// +/// SAFETY: a, b, c must be valid initialized elements. +#[inline(always)] +fn median3<T, F: FnMut(&T, &T) -> bool>(a: &T, b: &T, c: &T, is_less: &mut F) -> *const T { + // Compiler tends to make this branchless when sensible, and avoids the + // third comparison when not. + let x = is_less(a, b); + let y = is_less(a, c); + if x == y { + // If x=y=0 then b, c <= a. In this case we want to return max(b, c). + // If x=y=1 then a < b, c. In this case we want to return min(b, c). + // By toggling the outcome of b < c using XOR x we get this behavior. + let z = is_less(b, c); + if z ^ x { c } else { b } + } else { + // Either c <= a < b or b <= a < c, thus a is our median. + a + } +} diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs new file mode 100644 index 00000000000..5111ed8756b --- /dev/null +++ b/library/core/src/slice/sort/shared/smallsort.rs @@ -0,0 +1,855 @@ +//! This module contains a variety of sort implementations that are optimized for small lengths. + +use crate::intrinsics; +use crate::mem::{self, ManuallyDrop, MaybeUninit}; +use crate::ptr; +use crate::slice; + +use crate::slice::sort::shared::FreezeMarker; + +// It's important to differentiate between SMALL_SORT_THRESHOLD performance for +// small slices and small-sort performance sorting small sub-slices as part of +// the main quicksort loop. For the former, testing showed that the +// representative benchmarks for real-world performance are cold CPU state and +// not single-size hot benchmarks. For the latter the CPU will call them many +// times, so hot benchmarks are fine and more realistic. And it's worth it to +// optimize sorting small sub-slices with more sophisticated solutions than +// insertion sort. + +/// Using a trait allows us to specialize on `Freeze` which in turn allows us to make safe +/// abstractions. +pub(crate) trait StableSmallSortTypeImpl: Sized { + /// For which input length <= return value of this function, is it valid to call `small_sort`. + fn small_sort_threshold() -> usize; + + /// Sorts `v` using strategies optimized for small sizes. + fn small_sort<F: FnMut(&Self, &Self) -> bool>( + v: &mut [Self], + scratch: &mut [MaybeUninit<Self>], + is_less: &mut F, + ); +} + +impl<T> StableSmallSortTypeImpl for T { + #[inline(always)] + default fn small_sort_threshold() -> usize { + // Optimal number of comparisons, and good perf. + SMALL_SORT_FALLBACK_THRESHOLD + } + + #[inline(always)] + default fn small_sort<F: FnMut(&T, &T) -> bool>( + v: &mut [T], + _scratch: &mut [MaybeUninit<T>], + is_less: &mut F, + ) { + if v.len() >= 2 { + insertion_sort_shift_left(v, 1, is_less); + } + } +} + +impl<T: FreezeMarker> StableSmallSortTypeImpl for T { + #[inline(always)] + fn small_sort_threshold() -> usize { + SMALL_SORT_GENERAL_THRESHOLD + } + + #[inline(always)] + fn small_sort<F: FnMut(&T, &T) -> bool>( + v: &mut [T], + scratch: &mut [MaybeUninit<T>], + is_less: &mut F, + ) { + small_sort_general_with_scratch(v, scratch, is_less); + } +} + +/// Using a trait allows us to specialize on `Freeze` which in turn allows us to make safe +/// abstractions. +pub(crate) trait UnstableSmallSortTypeImpl: Sized { + /// For which input length <= return value of this function, is it valid to call `small_sort`. + fn small_sort_threshold() -> usize; + + /// Sorts `v` using strategies optimized for small sizes. + fn small_sort<F: FnMut(&Self, &Self) -> bool>(v: &mut [Self], is_less: &mut F); +} + +impl<T> UnstableSmallSortTypeImpl for T { + #[inline(always)] + default fn small_sort_threshold() -> usize { + SMALL_SORT_FALLBACK_THRESHOLD + } + + #[inline(always)] + default fn small_sort<F>(v: &mut [T], is_less: &mut F) + where + F: FnMut(&T, &T) -> bool, + { + small_sort_fallback(v, is_less); + } +} + +impl<T: FreezeMarker> UnstableSmallSortTypeImpl for T { + #[inline(always)] + fn small_sort_threshold() -> usize { + <T as UnstableSmallSortFreezeTypeImpl>::small_sort_threshold() + } + + #[inline(always)] + fn small_sort<F>(v: &mut [T], is_less: &mut F) + where + F: FnMut(&T, &T) -> bool, + { + <T as UnstableSmallSortFreezeTypeImpl>::small_sort(v, is_less); + } +} + +/// FIXME(effects) use original ipnsort approach with choose_unstable_small_sort, +/// as found here <https://github.com/Voultapher/sort-research-rs/blob/438fad5d0495f65d4b72aa87f0b62fc96611dff3/ipnsort/src/smallsort.rs#L83C10-L83C36>. +pub(crate) trait UnstableSmallSortFreezeTypeImpl: Sized + FreezeMarker { + fn small_sort_threshold() -> usize; + + fn small_sort<F: FnMut(&Self, &Self) -> bool>(v: &mut [Self], is_less: &mut F); +} + +impl<T: FreezeMarker> UnstableSmallSortFreezeTypeImpl for T { + #[inline(always)] + default fn small_sort_threshold() -> usize { + if (mem::size_of::<T>() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { + SMALL_SORT_GENERAL_THRESHOLD + } else { + SMALL_SORT_FALLBACK_THRESHOLD + } + } + + #[inline(always)] + default fn small_sort<F>(v: &mut [T], is_less: &mut F) + where + F: FnMut(&T, &T) -> bool, + { + if (mem::size_of::<T>() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { + small_sort_general(v, is_less); + } else { + small_sort_fallback(v, is_less); + } + } +} + +/// SAFETY: Only used for run-time optimization heuristic. +#[rustc_unsafe_specialization_marker] +trait CopyMarker {} + +impl<T: Copy> CopyMarker for T {} + +impl<T: FreezeMarker + CopyMarker> UnstableSmallSortFreezeTypeImpl for T { + #[inline(always)] + fn small_sort_threshold() -> usize { + if has_efficient_in_place_swap::<T>() + && (mem::size_of::<T>() * SMALL_SORT_NETWORK_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE + { + SMALL_SORT_NETWORK_THRESHOLD + } else if (mem::size_of::<T>() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { + SMALL_SORT_GENERAL_THRESHOLD + } else { + SMALL_SORT_FALLBACK_THRESHOLD + } + } + + #[inline(always)] + fn small_sort<F>(v: &mut [T], is_less: &mut F) + where + F: FnMut(&T, &T) -> bool, + { + if has_efficient_in_place_swap::<T>() + && (mem::size_of::<T>() * SMALL_SORT_NETWORK_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE + { + small_sort_network(v, is_less); + } else if (mem::size_of::<T>() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { + small_sort_general(v, is_less); + } else { + small_sort_fallback(v, is_less); + } + } +} + +/// Optimal number of comparisons, and good perf. +const SMALL_SORT_FALLBACK_THRESHOLD: usize = 16; + +/// From a comparison perspective 20 was ~2% more efficient for fully random input, but for +/// wall-clock performance choosing 32 yielded better performance overall. +/// +/// SAFETY: If you change this value, you have to adjust [`small_sort_general`] ! +const SMALL_SORT_GENERAL_THRESHOLD: usize = 32; + +/// [`small_sort_general`] uses [`sort8_stable`] as primitive and does a kind of ping-pong merge, +/// where the output of the first two [`sort8_stable`] calls is stored at the end of the scratch +/// buffer. This simplifies panic handling and avoids additional copies. This affects the required +/// scratch buffer size. +/// +/// SAFETY: If you change this value, you have to adjust [`small_sort_general`] ! +pub(crate) const SMALL_SORT_GENERAL_SCRATCH_LEN: usize = SMALL_SORT_GENERAL_THRESHOLD + 16; + +/// SAFETY: If you change this value, you have to adjust [`small_sort_network`] ! +const SMALL_SORT_NETWORK_THRESHOLD: usize = 32; +const SMALL_SORT_NETWORK_SCRATCH_LEN: usize = SMALL_SORT_NETWORK_THRESHOLD; + +/// Using a stack array, could cause a stack overflow if the type `T` is very large. To be +/// conservative we limit the usage of small-sorts that require a stack array to types that fit +/// within this limit. +const MAX_STACK_ARRAY_SIZE: usize = 4096; + +fn small_sort_fallback<T, F: FnMut(&T, &T) -> bool>(v: &mut [T], is_less: &mut F) { + if v.len() >= 2 { + insertion_sort_shift_left(v, 1, is_less); + } +} + +fn small_sort_general<T: FreezeMarker, F: FnMut(&T, &T) -> bool>(v: &mut [T], is_less: &mut F) { + let mut stack_array = MaybeUninit::<[T; SMALL_SORT_GENERAL_SCRATCH_LEN]>::uninit(); + + // SAFETY: The memory is backed by `stack_array`, and the operation is safe as long as the len + // is the same. + let scratch = unsafe { + slice::from_raw_parts_mut( + stack_array.as_mut_ptr() as *mut MaybeUninit<T>, + SMALL_SORT_GENERAL_SCRATCH_LEN, + ) + }; + + small_sort_general_with_scratch(v, scratch, is_less); +} + +fn small_sort_general_with_scratch<T: FreezeMarker, F: FnMut(&T, &T) -> bool>( + v: &mut [T], + scratch: &mut [MaybeUninit<T>], + is_less: &mut F, +) { + let len = v.len(); + if len < 2 { + return; + } + + if scratch.len() < len + 16 { + intrinsics::abort(); + } + + let v_base = v.as_mut_ptr(); + let len_div_2 = len / 2; + + // SAFETY: See individual comments. + unsafe { + let scratch_base = scratch.as_mut_ptr() as *mut T; + + let presorted_len = if const { mem::size_of::<T>() <= 16 } && len >= 16 { + // SAFETY: scratch_base is valid and has enough space. + sort8_stable(v_base, scratch_base, scratch_base.add(len), is_less); + sort8_stable( + v_base.add(len_div_2), + scratch_base.add(len_div_2), + scratch_base.add(len + 8), + is_less, + ); + + 8 + } else if len >= 8 { + // SAFETY: scratch_base is valid and has enough space. + sort4_stable(v_base, scratch_base, is_less); + sort4_stable(v_base.add(len_div_2), scratch_base.add(len_div_2), is_less); + + 4 + } else { + ptr::copy_nonoverlapping(v_base, scratch_base, 1); + ptr::copy_nonoverlapping(v_base.add(len_div_2), scratch_base.add(len_div_2), 1); + + 1 + }; + + for offset in [0, len_div_2] { + // SAFETY: at this point dst is initialized with presorted_len elements. + // We extend this to desired_len, src is valid for desired_len elements. + let src = v_base.add(offset); + let dst = scratch_base.add(offset); + let desired_len = if offset == 0 { len_div_2 } else { len - len_div_2 }; + + for i in presorted_len..desired_len { + ptr::copy_nonoverlapping(src.add(i), dst.add(i), 1); + insert_tail(dst, dst.add(i), is_less); + } + } + + // SAFETY: see comment in `CopyOnDrop::drop`. + let drop_guard = CopyOnDrop { src: scratch_base, dst: v_base, len }; + + // SAFETY: at this point scratch_base is fully initialized, allowing us + // to use it as the source of our merge back into the original array. + // If a panic occurs we ensure the original array is restored to a valid + // permutation of the input through drop_guard. This technique is similar + // to ping-pong merging. + bidirectional_merge( + &*ptr::slice_from_raw_parts(drop_guard.src, drop_guard.len), + drop_guard.dst, + is_less, + ); + mem::forget(drop_guard); + } +} + +struct CopyOnDrop<T> { + src: *const T, + dst: *mut T, + len: usize, +} + +impl<T> Drop for CopyOnDrop<T> { + fn drop(&mut self) { + // SAFETY: `src` must contain `len` initialized elements, and dst must + // be valid to write `len` elements. + unsafe { + ptr::copy_nonoverlapping(self.src, self.dst, self.len); + } + } +} + +fn small_sort_network<T, F>(v: &mut [T], is_less: &mut F) +where + T: FreezeMarker, + F: FnMut(&T, &T) -> bool, +{ + // This implementation is tuned to be efficient for integer types. + + let len = v.len(); + if len < 2 { + return; + } + + if len > SMALL_SORT_NETWORK_SCRATCH_LEN { + intrinsics::abort(); + } + + let mut stack_array = MaybeUninit::<[T; SMALL_SORT_NETWORK_SCRATCH_LEN]>::uninit(); + + let len_div_2 = len / 2; + let no_merge = len < 18; + + let v_base = v.as_mut_ptr(); + let initial_region_len = if no_merge { len } else { len_div_2 }; + // SAFETY: Both possible values of `initial_region_len` are in-bounds. + let mut region = unsafe { &mut *ptr::slice_from_raw_parts_mut(v_base, initial_region_len) }; + + // Avoid compiler unrolling, we *really* don't want that to happen here for binary-size reasons. + loop { + let presorted_len = if region.len() >= 13 { + sort13_optimal(region, is_less); + 13 + } else if region.len() >= 9 { + sort9_optimal(region, is_less); + 9 + } else { + 1 + }; + + insertion_sort_shift_left(region, presorted_len, is_less); + + if no_merge { + return; + } + + if region.as_ptr() != v_base { + break; + } + + // SAFETY: The right side of `v` based on `len_div_2` is guaranteed in-bounds. + unsafe { + region = &mut *ptr::slice_from_raw_parts_mut(v_base.add(len_div_2), len - len_div_2) + }; + } + + // SAFETY: We checked that T is Freeze and thus observation safe. + // Should is_less panic v was not modified in parity_merge and retains it's original input. + // scratch and v must not alias and scratch has v.len() space. + unsafe { + let scratch_base = stack_array.as_mut_ptr() as *mut T; + bidirectional_merge( + &mut *ptr::slice_from_raw_parts_mut(v_base, len), + scratch_base, + is_less, + ); + ptr::copy_nonoverlapping(scratch_base, v_base, len); + } +} + +/// Swap two values in the slice pointed to by `v_base` at the position `a_pos` and `b_pos` if the +/// value at position `b_pos` is less than the one at position `a_pos`. +pub unsafe fn swap_if_less<T, F>(v_base: *mut T, a_pos: usize, b_pos: usize, is_less: &mut F) +where + F: FnMut(&T, &T) -> bool, +{ + // SAFETY: the caller must guarantee that `a` and `b` each added to `v_base` yield valid + // pointers into `v_base`, and are properly aligned, and part of the same allocation. + unsafe { + let v_a = v_base.add(a_pos); + let v_b = v_base.add(b_pos); + + // PANIC SAFETY: if is_less panics, no scratch memory was created and the slice should still be + // in a well defined state, without duplicates. + + // Important to only swap if it is more and not if it is equal. is_less should return false for + // equal, so we don't swap. + let should_swap = is_less(&*v_b, &*v_a); + + // This is a branchless version of swap if. + // The equivalent code with a branch would be: + // + // if should_swap { + // ptr::swap(left, right, 1); + // } + + // The goal is to generate cmov instructions here. + let left_swap = if should_swap { v_b } else { v_a }; + let right_swap = if should_swap { v_a } else { v_b }; + + let right_swap_tmp = ManuallyDrop::new(ptr::read(right_swap)); + ptr::copy(left_swap, v_a, 1); + ptr::copy_nonoverlapping(&*right_swap_tmp, v_b, 1); + } +} + +/// Sorts the first 9 elements of `v` with a fast fixed function. +/// +/// Should `is_less` generate substantial amounts of code the compiler can choose to not inline +/// `swap_if_less`. If the code of a sort impl changes so as to call this function in multiple +/// places, `#[inline(never)]` is recommended to keep binary-size in check. The current design of +/// `small_sort_network` makes sure to only call this once. +fn sort9_optimal<T, F>(v: &mut [T], is_less: &mut F) +where + F: FnMut(&T, &T) -> bool, +{ + if v.len() < 9 { + intrinsics::abort(); + } + + let v_base = v.as_mut_ptr(); + + // Optimal sorting network see: + // https://bertdobbelaere.github.io/sorting_networks.html. + + // SAFETY: We checked the len. + unsafe { + swap_if_less(v_base, 0, 3, is_less); + swap_if_less(v_base, 1, 7, is_less); + swap_if_less(v_base, 2, 5, is_less); + swap_if_less(v_base, 4, 8, is_less); + swap_if_less(v_base, 0, 7, is_less); + swap_if_less(v_base, 2, 4, is_less); + swap_if_less(v_base, 3, 8, is_less); + swap_if_less(v_base, 5, 6, is_less); + swap_if_less(v_base, 0, 2, is_less); + swap_if_less(v_base, 1, 3, is_less); + swap_if_less(v_base, 4, 5, is_less); + swap_if_less(v_base, 7, 8, is_less); + swap_if_less(v_base, 1, 4, is_less); + swap_if_less(v_base, 3, 6, is_less); + swap_if_less(v_base, 5, 7, is_less); + swap_if_less(v_base, 0, 1, is_less); + swap_if_less(v_base, 2, 4, is_less); + swap_if_less(v_base, 3, 5, is_less); + swap_if_less(v_base, 6, 8, is_less); + swap_if_less(v_base, 2, 3, is_less); + swap_if_less(v_base, 4, 5, is_less); + swap_if_less(v_base, 6, 7, is_less); + swap_if_less(v_base, 1, 2, is_less); + swap_if_less(v_base, 3, 4, is_less); + swap_if_less(v_base, 5, 6, is_less); + } +} + +/// Sorts the first 13 elements of `v` with a fast fixed function. +/// +/// Should `is_less` generate substantial amounts of code the compiler can choose to not inline +/// `swap_if_less`. If the code of a sort impl changes so as to call this function in multiple +/// places, `#[inline(never)]` is recommended to keep binary-size in check. The current design of +/// `small_sort_network` makes sure to only call this once. +fn sort13_optimal<T, F>(v: &mut [T], is_less: &mut F) +where + F: FnMut(&T, &T) -> bool, +{ + if v.len() < 13 { + intrinsics::abort(); + } + + let v_base = v.as_mut_ptr(); + + // Optimal sorting network see: + // https://bertdobbelaere.github.io/sorting_networks.html. + + // SAFETY: We checked the len. + unsafe { + swap_if_less(v_base, 0, 12, is_less); + swap_if_less(v_base, 1, 10, is_less); + swap_if_less(v_base, 2, 9, is_less); + swap_if_less(v_base, 3, 7, is_less); + swap_if_less(v_base, 5, 11, is_less); + swap_if_less(v_base, 6, 8, is_less); + swap_if_less(v_base, 1, 6, is_less); + swap_if_less(v_base, 2, 3, is_less); + swap_if_less(v_base, 4, 11, is_less); + swap_if_less(v_base, 7, 9, is_less); + swap_if_less(v_base, 8, 10, is_less); + swap_if_less(v_base, 0, 4, is_less); + swap_if_less(v_base, 1, 2, is_less); + swap_if_less(v_base, 3, 6, is_less); + swap_if_less(v_base, 7, 8, is_less); + swap_if_less(v_base, 9, 10, is_less); + swap_if_less(v_base, 11, 12, is_less); + swap_if_less(v_base, 4, 6, is_less); + swap_if_less(v_base, 5, 9, is_less); + swap_if_less(v_base, 8, 11, is_less); + swap_if_less(v_base, 10, 12, is_less); + swap_if_less(v_base, 0, 5, is_less); + swap_if_less(v_base, 3, 8, is_less); + swap_if_less(v_base, 4, 7, is_less); + swap_if_less(v_base, 6, 11, is_less); + swap_if_less(v_base, 9, 10, is_less); + swap_if_less(v_base, 0, 1, is_less); + swap_if_less(v_base, 2, 5, is_less); + swap_if_less(v_base, 6, 9, is_less); + swap_if_less(v_base, 7, 8, is_less); + swap_if_less(v_base, 10, 11, is_less); + swap_if_less(v_base, 1, 3, is_less); + swap_if_less(v_base, 2, 4, is_less); + swap_if_less(v_base, 5, 6, is_less); + swap_if_less(v_base, 9, 10, is_less); + swap_if_less(v_base, 1, 2, is_less); + swap_if_less(v_base, 3, 4, is_less); + swap_if_less(v_base, 5, 7, is_less); + swap_if_less(v_base, 6, 8, is_less); + swap_if_less(v_base, 2, 3, is_less); + swap_if_less(v_base, 4, 5, is_less); + swap_if_less(v_base, 6, 7, is_less); + swap_if_less(v_base, 8, 9, is_less); + swap_if_less(v_base, 3, 4, is_less); + swap_if_less(v_base, 5, 6, is_less); + } +} + +/// Sorts range [begin, tail] assuming [begin, tail) is already sorted. +/// +/// # Safety +/// begin < tail and p must be valid and initialized for all begin <= p <= tail. +unsafe fn insert_tail<T, F: FnMut(&T, &T) -> bool>(begin: *mut T, tail: *mut T, is_less: &mut F) { + // SAFETY: see individual comments. + unsafe { + // SAFETY: in-bounds as tail > begin. + let mut sift = tail.sub(1); + if !is_less(&*tail, &*sift) { + return; + } + + // SAFETY: after this read tail is never read from again, as we only ever + // read from sift, sift < tail and we only ever decrease sift. Thus this is + // effectively a move, not a copy. Should a panic occur, or we have found + // the correct insertion position, gap_guard ensures the element is moved + // back into the array. + let tmp = ManuallyDrop::new(tail.read()); + let mut gap_guard = CopyOnDrop { src: &*tmp, dst: tail, len: 1 }; + + loop { + // SAFETY: we move sift into the gap (which is valid), and point the + // gap guard destination at sift, ensuring that if a panic occurs the + // gap is once again filled. + ptr::copy_nonoverlapping(sift, gap_guard.dst, 1); + gap_guard.dst = sift; + + if sift == begin { + break; + } + + // SAFETY: we checked that sift != begin, thus this is in-bounds. + sift = sift.sub(1); + if !is_less(&tmp, &*sift) { + break; + } + } + } +} + +/// Sort `v` assuming `v[..offset]` is already sorted. +pub fn insertion_sort_shift_left<T, F: FnMut(&T, &T) -> bool>( + v: &mut [T], + offset: usize, + is_less: &mut F, +) { + let len = v.len(); + if offset == 0 || offset > len { + intrinsics::abort(); + } + + // SAFETY: see individual comments. + unsafe { + // We write this basic loop directly using pointers, as when we use a + // for loop LLVM likes to unroll this loop which we do not want. + // SAFETY: v_end is the one-past-end pointer, and we checked that + // offset <= len, thus tail is also in-bounds. + let v_base = v.as_mut_ptr(); + let v_end = v_base.add(len); + let mut tail = v_base.add(offset); + while tail != v_end { + // SAFETY: v_base and tail are both valid pointers to elements, and + // v_base < tail since we checked offset != 0. + insert_tail(v_base, tail, is_less); + + // SAFETY: we checked that tail is not yet the one-past-end pointer. + tail = tail.add(1); + } + } +} + +/// SAFETY: The caller MUST guarantee that `v_base` is valid for 4 reads and +/// `dst` is valid for 4 writes. The result will be stored in `dst[0..4]`. +pub unsafe fn sort4_stable<T, F: FnMut(&T, &T) -> bool>( + v_base: *const T, + dst: *mut T, + is_less: &mut F, +) { + // By limiting select to picking pointers, we are guaranteed good cmov code-gen + // regardless of type T's size. Further this only does 5 instead of 6 + // comparisons compared to a stable transposition 4 element sorting-network, + // and always copies each element exactly once. + + // SAFETY: all pointers have offset at most 3 from v_base and dst, and are + // thus in-bounds by the precondition. + unsafe { + // Stably create two pairs a <= b and c <= d. + let c1 = is_less(&*v_base.add(1), &*v_base); + let c2 = is_less(&*v_base.add(3), &*v_base.add(2)); + let a = v_base.add(c1 as usize); + let b = v_base.add(!c1 as usize); + let c = v_base.add(2 + c2 as usize); + let d = v_base.add(2 + (!c2 as usize)); + + // Compare (a, c) and (b, d) to identify max/min. We're left with two + // unknown elements, but because we are a stable sort we must know which + // one is leftmost and which one is rightmost. + // c3, c4 | min max unknown_left unknown_right + // 0, 0 | a d b c + // 0, 1 | a b c d + // 1, 0 | c d a b + // 1, 1 | c b a d + let c3 = is_less(&*c, &*a); + let c4 = is_less(&*d, &*b); + let min = select(c3, c, a); + let max = select(c4, b, d); + let unknown_left = select(c3, a, select(c4, c, b)); + let unknown_right = select(c4, d, select(c3, b, c)); + + // Sort the last two unknown elements. + let c5 = is_less(&*unknown_right, &*unknown_left); + let lo = select(c5, unknown_right, unknown_left); + let hi = select(c5, unknown_left, unknown_right); + + ptr::copy_nonoverlapping(min, dst, 1); + ptr::copy_nonoverlapping(lo, dst.add(1), 1); + ptr::copy_nonoverlapping(hi, dst.add(2), 1); + ptr::copy_nonoverlapping(max, dst.add(3), 1); + } + + #[inline(always)] + fn select<T>(cond: bool, if_true: *const T, if_false: *const T) -> *const T { + if cond { if_true } else { if_false } + } +} + +/// SAFETY: The caller MUST guarantee that `v_base` is valid for 8 reads and +/// writes, `scratch_base` and `dst` MUST be valid for 8 writes. The result will +/// be stored in `dst[0..8]`. +unsafe fn sort8_stable<T: FreezeMarker, F: FnMut(&T, &T) -> bool>( + v_base: *mut T, + dst: *mut T, + scratch_base: *mut T, + is_less: &mut F, +) { + // SAFETY: these pointers are all in-bounds by the precondition of our function. + unsafe { + sort4_stable(v_base, scratch_base, is_less); + sort4_stable(v_base.add(4), scratch_base.add(4), is_less); + } + + // SAFETY: scratch_base[0..8] is now initialized, allowing us to merge back + // into dst. + unsafe { + bidirectional_merge(&*ptr::slice_from_raw_parts(scratch_base, 8), dst, is_less); + } +} + +#[inline(always)] +unsafe fn merge_up<T, F: FnMut(&T, &T) -> bool>( + mut left_src: *const T, + mut right_src: *const T, + mut dst: *mut T, + is_less: &mut F, +) -> (*const T, *const T, *mut T) { + // This is a branchless merge utility function. + // The equivalent code with a branch would be: + // + // if !is_less(&*right_src, &*left_src) { + // ptr::copy_nonoverlapping(left_src, dst, 1); + // left_src = left_src.add(1); + // } else { + // ptr::copy_nonoverlapping(right_src, dst, 1); + // right_src = right_src.add(1); + // } + // dst = dst.add(1); + + // SAFETY: The caller must guarantee that `left_src`, `right_src` are valid + // to read and `dst` is valid to write, while not aliasing. + unsafe { + let is_l = !is_less(&*right_src, &*left_src); + let src = if is_l { left_src } else { right_src }; + ptr::copy_nonoverlapping(src, dst, 1); + right_src = right_src.add(!is_l as usize); + left_src = left_src.add(is_l as usize); + dst = dst.add(1); + } + + (left_src, right_src, dst) +} + +#[inline(always)] +unsafe fn merge_down<T, F: FnMut(&T, &T) -> bool>( + mut left_src: *const T, + mut right_src: *const T, + mut dst: *mut T, + is_less: &mut F, +) -> (*const T, *const T, *mut T) { + // This is a branchless merge utility function. + // The equivalent code with a branch would be: + // + // if !is_less(&*right_src, &*left_src) { + // ptr::copy_nonoverlapping(right_src, dst, 1); + // right_src = right_src.wrapping_sub(1); + // } else { + // ptr::copy_nonoverlapping(left_src, dst, 1); + // left_src = left_src.wrapping_sub(1); + // } + // dst = dst.sub(1); + + // SAFETY: The caller must guarantee that `left_src`, `right_src` are valid + // to read and `dst` is valid to write, while not aliasing. + unsafe { + let is_l = !is_less(&*right_src, &*left_src); + let src = if is_l { right_src } else { left_src }; + ptr::copy_nonoverlapping(src, dst, 1); + right_src = right_src.wrapping_sub(is_l as usize); + left_src = left_src.wrapping_sub(!is_l as usize); + dst = dst.sub(1); + } + + (left_src, right_src, dst) +} + +/// Merge v assuming v[..len / 2] and v[len / 2..] are sorted. +/// +/// Original idea for bi-directional merging by Igor van den Hoven (quadsort), +/// adapted to only use merge up and down. In contrast to the original +/// parity_merge function, it performs 2 writes instead of 4 per iteration. +/// +/// # Safety +/// The caller must guarantee that `dst` is valid for v.len() writes. +/// Also `v.as_ptr()` and `dst` must not alias and v.len() must be >= 2. +/// +/// Note that T must be Freeze, the comparison function is evaluated on outdated +/// temporary 'copies' that may not end up in the final array. +unsafe fn bidirectional_merge<T: FreezeMarker, F: FnMut(&T, &T) -> bool>( + v: &[T], + dst: *mut T, + is_less: &mut F, +) { + // It helps to visualize the merge: + // + // Initial: + // + // |dst (in dst) + // |left |right + // v v + // [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx] + // ^ ^ + // |left_rev |right_rev + // |dst_rev (in dst) + // + // After: + // + // |dst (in dst) + // |left | |right + // v v v + // [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx] + // ^ ^ ^ + // |left_rev | |right_rev + // |dst_rev (in dst) + // + // In each iteration one of left or right moves up one position, and one of + // left_rev or right_rev moves down one position, whereas dst always moves + // up one position and dst_rev always moves down one position. Assuming + // the input was sorted and the comparison function is correctly implemented + // at the end we will have left == left_rev + 1, and right == right_rev + 1, + // fully consuming the input having written it to dst. + + let len = v.len(); + let src = v.as_ptr(); + + let len_div_2 = len / 2; + + // SAFETY: The caller has to ensure that len >= 2. + unsafe { + intrinsics::assume(len_div_2 != 0); // This can avoid useless code-gen. + } + + // SAFETY: no matter what the result of the user-provided comparison function + // is, all 4 read pointers will always be in-bounds. Writing `dst` and `dst_rev` + // will always be in bounds if the caller guarantees that `dst` is valid for + // `v.len()` writes. + unsafe { + let mut left = src; + let mut right = src.add(len_div_2); + let mut dst = dst; + + let mut left_rev = src.add(len_div_2 - 1); + let mut right_rev = src.add(len - 1); + let mut dst_rev = dst.add(len - 1); + + for _ in 0..len_div_2 { + (left, right, dst) = merge_up(left, right, dst, is_less); + (left_rev, right_rev, dst_rev) = merge_down(left_rev, right_rev, dst_rev, is_less); + } + + let left_end = left_rev.wrapping_add(1); + let right_end = right_rev.wrapping_add(1); + + // Odd length, so one element is left unconsumed in the input. + if len % 2 != 0 { + let left_nonempty = left < left_end; + let last_src = if left_nonempty { left } else { right }; + ptr::copy_nonoverlapping(last_src, dst, 1); + left = left.add(left_nonempty as usize); + right = right.add((!left_nonempty) as usize); + } + + // We now should have consumed the full input exactly once. This can + // only fail if the comparison operator fails to be Ord, in which case + // we will panic and never access the inconsistent state in dst. + if left != left_end || right != right_end { + panic_on_ord_violation(); + } + } +} + +#[inline(never)] +fn panic_on_ord_violation() -> ! { + panic!("Ord violation"); +} + +#[must_use] +pub(crate) const fn has_efficient_in_place_swap<T>() -> bool { + // Heuristic that holds true on all tested 64-bit capable architectures. + mem::size_of::<T>() <= 8 // mem::size_of::<u64>() +} diff --git a/library/core/src/slice/sort/stable/drift.rs b/library/core/src/slice/sort/stable/drift.rs new file mode 100644 index 00000000000..4008639095b --- /dev/null +++ b/library/core/src/slice/sort/stable/drift.rs @@ -0,0 +1,300 @@ +//! This module contains the hybrid top-level loop combining bottom-up Mergesort with top-down +//! Quicksort. + +use crate::cmp; +use crate::intrinsics; +use crate::mem::MaybeUninit; + +use crate::slice::sort::shared::find_existing_run; +use crate::slice::sort::shared::smallsort::StableSmallSortTypeImpl; +use crate::slice::sort::stable::merge::merge; +use crate::slice::sort::stable::quicksort::quicksort; + +/// Sorts `v` based on comparison function `is_less`. If `eager_sort` is true, +/// it will only do small-sorts and physical merges, ensuring O(N * log(N)) +/// worst-case complexity. `scratch.len()` must be at least `max(v.len() / 2, +/// MIN_SMALL_SORT_SCRATCH_LEN)` otherwise the implementation may abort. +/// Fully ascending and descending inputs will be sorted with exactly N - 1 +/// comparisons. +/// +/// This is the main loop for driftsort, which uses powersort's heuristic to +/// determine in which order to merge runs, see below for details. +pub fn sort<T, F: FnMut(&T, &T) -> bool>( + v: &mut [T], + scratch: &mut [MaybeUninit<T>], + eager_sort: bool, + is_less: &mut F, +) { + let len = v.len(); + if len < 2 { + return; // Removing this length check *increases* code size. + } + let scale_factor = merge_tree_scale_factor(len); + + // It's important to have a relatively high entry barrier for pre-sorted + // runs, as the presence of a single such run will force on average several + // merge operations and shrink the maximum quicksort size a lot. For that + // reason we use sqrt(len) as our pre-sorted run threshold. + const MIN_SQRT_RUN_LEN: usize = 64; + let min_good_run_len = if len <= (MIN_SQRT_RUN_LEN * MIN_SQRT_RUN_LEN) { + // For small input length `MIN_SQRT_RUN_LEN` would break pattern + // detection of full or nearly sorted inputs. + cmp::min(len - len / 2, MIN_SQRT_RUN_LEN) + } else { + sqrt_approx(len) + }; + + // (stack_len, runs, desired_depths) together form a stack maintaining run + // information for the powersort heuristic. desired_depths[i] is the desired + // depth of the merge node that merges runs[i] with the run that comes after + // it. + let mut stack_len = 0; + let mut run_storage = MaybeUninit::<[DriftsortRun; 66]>::uninit(); + let runs: *mut DriftsortRun = run_storage.as_mut_ptr().cast(); + let mut desired_depth_storage = MaybeUninit::<[u8; 66]>::uninit(); + let desired_depths: *mut u8 = desired_depth_storage.as_mut_ptr().cast(); + + let mut scan_idx = 0; + let mut prev_run = DriftsortRun::new_sorted(0); // Initial dummy run. + loop { + // Compute the next run and the desired depth of the merge node between + // prev_run and next_run. On the last iteration we create a dummy run + // with root-level desired depth to fully collapse the merge tree. + let (next_run, desired_depth); + if scan_idx < len { + next_run = + create_run(&mut v[scan_idx..], scratch, min_good_run_len, eager_sort, is_less); + desired_depth = merge_tree_depth( + scan_idx - prev_run.len(), + scan_idx, + scan_idx + next_run.len(), + scale_factor, + ); + } else { + next_run = DriftsortRun::new_sorted(0); + desired_depth = 0; + }; + + // Process the merge nodes between earlier runs[i] that have a desire to + // be deeper in the merge tree than the merge node for the splitpoint + // between prev_run and next_run. + // + // SAFETY: first note that this is the only place we modify stack_len, + // runs or desired depths. We maintain the following invariants: + // 1. The first stack_len elements of runs/desired_depths are initialized. + // 2. For all valid i > 0, desired_depths[i] < desired_depths[i+1]. + // 3. The sum of all valid runs[i].len() plus prev_run.len() equals + // scan_idx. + unsafe { + while stack_len > 1 && *desired_depths.add(stack_len - 1) >= desired_depth { + // Desired depth greater than the upcoming desired depth, pop + // left neighbor run from stack and merge into prev_run. + let left = *runs.add(stack_len - 1); + let merged_len = left.len() + prev_run.len(); + let merge_start_idx = scan_idx - merged_len; + let merge_slice = v.get_unchecked_mut(merge_start_idx..scan_idx); + prev_run = logical_merge(merge_slice, scratch, left, prev_run, is_less); + stack_len -= 1; + } + + // We now know that desired_depths[stack_len - 1] < desired_depth, + // maintaining our invariant. This also guarantees we don't overflow + // the stack as merge_tree_depth(..) <= 64 and thus we can only have + // 64 distinct values on the stack before pushing, plus our initial + // dummy run, while our capacity is 66. + *runs.add(stack_len) = prev_run; + *desired_depths.add(stack_len) = desired_depth; + stack_len += 1; + } + + // Break before overriding the last run with our dummy run. + if scan_idx >= len { + break; + } + + scan_idx += next_run.len(); + prev_run = next_run; + } + + if !prev_run.sorted() { + stable_quicksort(v, scratch, is_less); + } +} + +// Nearly-Optimal Mergesorts: Fast, Practical Sorting Methods That Optimally +// Adapt to Existing Runs by J. Ian Munro and Sebastian Wild. +// +// This method forms a binary merge tree, where each internal node corresponds +// to a splitting point between the adjacent runs that have to be merged. If we +// visualize our array as the number line from 0 to 1, we want to find the +// dyadic fraction with smallest denominator that lies between the midpoints of +// our to-be-merged slices. The exponent in the dyadic fraction indicates the +// desired depth in the binary merge tree this internal node wishes to have. +// This does not always correspond to the actual depth due to the inherent +// imbalance in runs, but we follow it as closely as possible. +// +// As an optimization we rescale the number line from [0, 1) to [0, 2^62). Then +// finding the simplest dyadic fraction between midpoints corresponds to finding +// the most significant bit difference of the midpoints. We save scale_factor = +// ceil(2^62 / n) to perform this rescaling using a multiplication, avoiding +// having to repeatedly do integer divides. This rescaling isn't exact when n is +// not a power of two since we use integers and not reals, but the result is +// very close, and in fact when n < 2^30 the resulting tree is equivalent as the +// approximation errors stay entirely in the lower order bits. +// +// Thus for the splitting point between two adjacent slices [a, b) and [b, c) +// the desired depth of the corresponding merge node is CLZ((a+b)*f ^ (b+c)*f), +// where CLZ counts the number of leading zeros in an integer and f is our scale +// factor. Note that we omitted the division by two in the midpoint +// calculations, as this simply shifts the bits by one position (and thus always +// adds one to the result), and we only care about the relative depths. +// +// Finally, if we try to upper bound x = (a+b)*f giving x = (n-1 + n) * ceil(2^62 / n) then +// x < (2^62 / n + 1) * 2n +// x < 2^63 + 2n +// So as long as n < 2^62 we find that x < 2^64, meaning our operations do not +// overflow. +#[inline(always)] +fn merge_tree_scale_factor(n: usize) -> u64 { + if usize::BITS > u64::BITS { + panic!("Platform not supported"); + } + + ((1 << 62) + n as u64 - 1) / n as u64 +} + +// Note: merge_tree_depth output is < 64 when left < right as f*x and f*y must +// differ in some bit, and is <= 64 always. +#[inline(always)] +fn merge_tree_depth(left: usize, mid: usize, right: usize, scale_factor: u64) -> u8 { + let x = left as u64 + mid as u64; + let y = mid as u64 + right as u64; + ((scale_factor * x) ^ (scale_factor * y)).leading_zeros() as u8 +} + +fn sqrt_approx(n: usize) -> usize { + // Note that sqrt(n) = n^(1/2), and that 2^log2(n) = n. We combine these + // two facts to approximate sqrt(n) as 2^(log2(n) / 2). Because our integer + // log floors we want to add 0.5 to compensate for this on average, so our + // initial approximation is 2^((1 + floor(log2(n))) / 2). + // + // We then apply an iteration of Newton's method to improve our + // approximation, which for sqrt(n) is a1 = (a0 + n / a0) / 2. + // + // Finally we note that the exponentiation / division can be done directly + // with shifts. We OR with 1 to avoid zero-checks in the integer log. + let ilog = (n | 1).ilog2(); + let shift = (1 + ilog) / 2; + ((1 << shift) + (n >> shift)) / 2 +} + +// Lazy logical runs as in Glidesort. +#[inline(always)] +fn logical_merge<T, F: FnMut(&T, &T) -> bool>( + v: &mut [T], + scratch: &mut [MaybeUninit<T>], + left: DriftsortRun, + right: DriftsortRun, + is_less: &mut F, +) -> DriftsortRun { + // If one or both of the runs are sorted do a physical merge, using + // quicksort to sort the unsorted run if present. We also *need* to + // physically merge if the combined runs would not fit in the scratch space + // anymore (as this would mean we are no longer able to to quicksort them). + let len = v.len(); + let can_fit_in_scratch = len <= scratch.len(); + if !can_fit_in_scratch || left.sorted() || right.sorted() { + if !left.sorted() { + stable_quicksort(&mut v[..left.len()], scratch, is_less); + } + if !right.sorted() { + stable_quicksort(&mut v[left.len()..], scratch, is_less); + } + merge(v, scratch, left.len(), is_less); + + DriftsortRun::new_sorted(len) + } else { + DriftsortRun::new_unsorted(len) + } +} + +/// Creates a new logical run. +/// +/// A logical run can either be sorted or unsorted. If there is a pre-existing +/// run that clears the `min_good_run_len` threshold it is returned as a sorted +/// run. If not, the result depends on the value of `eager_sort`. If it is true, +/// then a sorted run of length `T::SMALL_SORT_THRESHOLD` is returned, and if it +/// is false an unsorted run of length `min_good_run_len` is returned. +fn create_run<T, F: FnMut(&T, &T) -> bool>( + v: &mut [T], + scratch: &mut [MaybeUninit<T>], + min_good_run_len: usize, + eager_sort: bool, + is_less: &mut F, +) -> DriftsortRun { + let len = v.len(); + if len >= min_good_run_len { + let (run_len, was_reversed) = find_existing_run(v, is_less); + + // SAFETY: find_existing_run promises to return a valid run_len. + unsafe { intrinsics::assume(run_len <= len) }; + + if run_len >= min_good_run_len { + if was_reversed { + v[..run_len].reverse(); + } + + return DriftsortRun::new_sorted(run_len); + } + } + + if eager_sort { + // We call quicksort with a len that will immediately call small-sort. + // By not calling the small-sort directly here it can always be inlined into + // the quicksort itself, making the recursive base case faster and is generally + // more binary-size efficient. + let eager_run_len = cmp::min(T::small_sort_threshold(), len); + quicksort(&mut v[..eager_run_len], scratch, 0, None, is_less); + DriftsortRun::new_sorted(eager_run_len) + } else { + DriftsortRun::new_unsorted(cmp::min(min_good_run_len, len)) + } +} + +fn stable_quicksort<T, F: FnMut(&T, &T) -> bool>( + v: &mut [T], + scratch: &mut [MaybeUninit<T>], + is_less: &mut F, +) { + // Limit the number of imbalanced partitions to `2 * floor(log2(len))`. + // The binary OR by one is used to eliminate the zero-check in the logarithm. + let limit = 2 * (v.len() | 1).ilog2(); + quicksort(v, scratch, limit, None, is_less); +} + +/// Compactly stores the length of a run, and whether or not it is sorted. This +/// can always fit in a usize because the maximum slice length is isize::MAX. +#[derive(Copy, Clone)] +struct DriftsortRun(usize); + +impl DriftsortRun { + #[inline(always)] + fn new_sorted(length: usize) -> Self { + Self((length << 1) | 1) + } + + #[inline(always)] + fn new_unsorted(length: usize) -> Self { + Self(length << 1) + } + + #[inline(always)] + fn sorted(self) -> bool { + self.0 & 1 == 1 + } + + #[inline(always)] + fn len(self) -> usize { + self.0 >> 1 + } +} diff --git a/library/core/src/slice/sort/stable/merge.rs b/library/core/src/slice/sort/stable/merge.rs new file mode 100644 index 00000000000..6739e114b13 --- /dev/null +++ b/library/core/src/slice/sort/stable/merge.rs @@ -0,0 +1,151 @@ +//! This module contains logic for performing a merge of two sorted sub-slices. + +use crate::cmp; +use crate::mem::MaybeUninit; +use crate::ptr; + +/// Merges non-decreasing runs `v[..mid]` and `v[mid..]` using `scratch` as +/// temporary storage, and stores the result into `v[..]`. +pub fn merge<T, F: FnMut(&T, &T) -> bool>( + v: &mut [T], + scratch: &mut [MaybeUninit<T>], + mid: usize, + is_less: &mut F, +) { + let len = v.len(); + + if mid == 0 || mid >= len || scratch.len() < cmp::min(mid, len - mid) { + return; + } + + // SAFETY: We checked that the two slices are non-empty and `mid` is in-bounds. + // We checked that the buffer `scratch` has enough capacity to hold a copy of + // the shorter slice. `merge_up` and `merge_down` are written in such a way that + // they uphold the contract described in `MergeState::drop`. + unsafe { + // The merge process first copies the shorter run into `buf`. Then it traces + // the newly copied run and the longer run forwards (or backwards), comparing + // their next unconsumed elements and copying the lesser (or greater) one into `v`. + // + // As soon as the shorter run is fully consumed, the process is done. If the + // longer run gets consumed first, then we must copy whatever is left of the + // shorter run into the remaining gap in `v`. + // + // Intermediate state of the process is always tracked by `gap`, which serves + // two purposes: + // 1. Protects integrity of `v` from panics in `is_less`. + // 2. Fills the remaining gap in `v` if the longer run gets consumed first. + + let buf = MaybeUninit::slice_as_mut_ptr(scratch); + + let v_base = v.as_mut_ptr(); + let v_mid = v_base.add(mid); + let v_end = v_base.add(len); + + let left_len = mid; + let right_len = len - mid; + + let left_is_shorter = left_len <= right_len; + let save_base = if left_is_shorter { v_base } else { v_mid }; + let save_len = if left_is_shorter { left_len } else { right_len }; + + ptr::copy_nonoverlapping(save_base, buf, save_len); + + let mut merge_state = MergeState { start: buf, end: buf.add(save_len), dst: save_base }; + + if left_is_shorter { + merge_state.merge_up(v_mid, v_end, is_less); + } else { + merge_state.merge_down(v_base, buf, v_end, is_less); + } + // Finally, `merge_state` gets dropped. If the shorter run was not fully + // consumed, whatever remains of it will now be copied into the hole in `v`. + } +} + +// When dropped, copies the range `start..end` into `dst..`. +struct MergeState<T> { + start: *mut T, + end: *mut T, + dst: *mut T, +} + +impl<T> MergeState<T> { + /// # Safety + /// The caller MUST guarantee that `self` is initialized in a way where `start -> end` is + /// the longer sub-slice and so that `dst` can be written to at least the shorter sub-slice + /// length times. In addition `start -> end` and `right -> right_end` MUST be valid to be + /// read. This function MUST only be called once. + unsafe fn merge_up<F: FnMut(&T, &T) -> bool>( + &mut self, + mut right: *const T, + right_end: *const T, + is_less: &mut F, + ) { + // SAFETY: See function safety comment. + unsafe { + let left = &mut self.start; + let out = &mut self.dst; + + while *left != self.end && right as *const T != right_end { + let consume_left = !is_less(&*right, &**left); + + let src = if consume_left { *left } else { right }; + ptr::copy_nonoverlapping(src, *out, 1); + + *left = left.add(consume_left as usize); + right = right.add(!consume_left as usize); + + *out = out.add(1); + } + } + } + + /// # Safety + /// The caller MUST guarantee that `self` is initialized in a way where `left_end <- dst` is + /// the shorter sub-slice and so that `out` can be written to at least the shorter sub-slice + /// length times. In addition `left_end <- dst` and `right_end <- end` MUST be valid to be + /// read. This function MUST only be called once. + unsafe fn merge_down<F: FnMut(&T, &T) -> bool>( + &mut self, + left_end: *const T, + right_end: *const T, + mut out: *mut T, + is_less: &mut F, + ) { + // SAFETY: See function safety comment. + unsafe { + loop { + let left = self.dst.sub(1); + let right = self.end.sub(1); + out = out.sub(1); + + let consume_left = is_less(&*right, &*left); + + let src = if consume_left { left } else { right }; + ptr::copy_nonoverlapping(src, out, 1); + + self.dst = left.add(!consume_left as usize); + self.end = right.add(consume_left as usize); + + if self.dst as *const T == left_end || self.end as *const T == right_end { + break; + } + } + } + } +} + +impl<T> Drop for MergeState<T> { + fn drop(&mut self) { + // SAFETY: The user of MergeState MUST ensure, that at any point this drop + // impl MAY run, for example when the user provided `is_less` panics, that + // copying the contiguous region between `start` and `end` to `dst` will + // leave the input slice `v` with each original element and all possible + // modifications observed. + unsafe { + let len = self.end.sub_ptr(self.start); + ptr::copy_nonoverlapping(self.start, self.dst, len); + } + } +} diff --git a/library/core/src/slice/sort/stable/mod.rs b/library/core/src/slice/sort/stable/mod.rs new file mode 100644 index 00000000000..3d3fe2e70b7 --- /dev/null +++ b/library/core/src/slice/sort/stable/mod.rs @@ -0,0 +1,116 @@ +//! This module contains the entry points for `slice::sort`. + +use crate::cmp; +use crate::intrinsics; +use crate::mem::{self, MaybeUninit, SizedTypeProperties}; + +use crate::slice::sort::shared::smallsort::{ + insertion_sort_shift_left, StableSmallSortTypeImpl, SMALL_SORT_GENERAL_SCRATCH_LEN, +}; + +pub(crate) mod drift; +pub(crate) mod merge; +pub(crate) mod quicksort; + +/// Stable sort called driftsort by Orson Peters and Lukas Bergdoll. +/// Design document: +/// <https://github.com/Voultapher/sort-research-rs/blob/main/writeup/driftsort_introduction/text.md> +/// +/// Upholds all safety properties outlined here: +/// <https://github.com/Voultapher/sort-research-rs/blob/main/writeup/sort_safety/text.md> +#[inline(always)] +pub fn sort<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], is_less: &mut F) { + // Arrays of zero-sized types are always all-equal, and thus sorted. + if T::IS_ZST { + return; + } + + // Instrumenting the standard library showed that 90+% of the calls to sort + // by rustc are either of size 0 or 1. + let len = v.len(); + if intrinsics::likely(len < 2) { + return; + } + + // More advanced sorting methods than insertion sort are faster if called in + // a hot loop for small inputs, but for general-purpose code the small + // binary size of insertion sort is more important. The instruction cache in + // modern processors is very valuable, and for a single sort call in general + // purpose code any gains from an advanced method are cancelled by i-cache + // misses during the sort, and thrashing the i-cache for surrounding code. + const MAX_LEN_ALWAYS_INSERTION_SORT: usize = 20; + if intrinsics::likely(len <= MAX_LEN_ALWAYS_INSERTION_SORT) { + insertion_sort_shift_left(v, 1, is_less); + return; + } + + driftsort_main::<T, F, BufT>(v, is_less); +} + +/// See [`sort`] +/// +/// Deliberately don't inline the main sorting routine entrypoint to ensure the +/// inlined insertion sort i-cache footprint remains minimal. +#[inline(never)] +fn driftsort_main<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], is_less: &mut F) { + // By allocating n elements of memory we can ensure the entire input can + // be sorted using stable quicksort, which allows better performance on + // random and low-cardinality distributions. However, we still want to + // reduce our memory usage to n / 2 for large inputs. We do this by scaling + // our allocation as max(n / 2, min(n, 8MB)), ensuring we scale like n for + // small inputs and n / 2 for large inputs, without a sudden drop off. We + // also need to ensure our alloc >= MIN_SMALL_SORT_SCRATCH_LEN, as the + // small-sort always needs this much memory. + const MAX_FULL_ALLOC_BYTES: usize = 8_000_000; // 8MB + let max_full_alloc = MAX_FULL_ALLOC_BYTES / mem::size_of::<T>(); + let len = v.len(); + let alloc_len = + cmp::max(cmp::max(len / 2, cmp::min(len, max_full_alloc)), SMALL_SORT_GENERAL_SCRATCH_LEN); + + // For small inputs 4KiB of stack storage suffices, which allows us to avoid + // calling the (de-)allocator. Benchmarks showed this was quite beneficial. + let mut stack_buf = AlignedStorage::<T, 4096>::new(); + let stack_scratch = stack_buf.as_uninit_slice_mut(); + let mut heap_buf; + let scratch = if stack_scratch.len() >= alloc_len { + stack_scratch + } else { + heap_buf = BufT::with_capacity(alloc_len); + heap_buf.as_uninit_slice_mut() + }; + + // For small inputs using quicksort is not yet beneficial, and a single + // small-sort or two small-sorts plus a single merge outperforms it, so use + // eager mode. + let eager_sort = len <= T::small_sort_threshold() * 2; + crate::slice::sort::stable::drift::sort(v, scratch, eager_sort, is_less); +} + +#[doc(hidden)] +/// Abstracts owned memory buffer, so that sort code can live in core where no allocation is +/// possible. This trait can then be implemented in a place that has access to allocation. +pub trait BufGuard<T> { + /// Creates new buffer that holds at least `capacity` memory. + fn with_capacity(capacity: usize) -> Self; + /// Returns mutable access to uninitialized memory owned by the buffer. + fn as_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<T>]; +} + +#[repr(C)] +struct AlignedStorage<T, const N: usize> { + _align: [T; 0], + storage: [MaybeUninit<u8>; N], +} + +impl<T, const N: usize> AlignedStorage<T, N> { + fn new() -> Self { + Self { _align: [], storage: MaybeUninit::uninit_array() } + } + + fn as_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<T>] { + let len = N / mem::size_of::<T>(); + + // SAFETY: `_align` ensures we are correctly aligned. + unsafe { core::slice::from_raw_parts_mut(self.storage.as_mut_ptr().cast(), len) } + } +} diff --git a/library/core/src/slice/sort/stable/quicksort.rs b/library/core/src/slice/sort/stable/quicksort.rs new file mode 100644 index 00000000000..181fe603d23 --- /dev/null +++ b/library/core/src/slice/sort/stable/quicksort.rs @@ -0,0 +1,257 @@ +//! This module contains a stable quicksort and partition implementation. + +use crate::intrinsics; +use crate::mem::{self, ManuallyDrop, MaybeUninit}; +use crate::ptr; + +use crate::slice::sort::shared::pivot::choose_pivot; +use crate::slice::sort::shared::smallsort::StableSmallSortTypeImpl; +use crate::slice::sort::shared::FreezeMarker; + +/// Sorts `v` recursively using quicksort. +/// +/// `limit` when initialized with `c*log(v.len())` for some c ensures we do not +/// overflow the stack or go quadratic. +#[inline(never)] +pub fn quicksort<T, F: FnMut(&T, &T) -> bool>( + mut v: &mut [T], + scratch: &mut [MaybeUninit<T>], + mut limit: u32, + mut left_ancestor_pivot: Option<&T>, + is_less: &mut F, +) { + loop { + let len = v.len(); + + if len <= T::small_sort_threshold() { + T::small_sort(v, scratch, is_less); + return; + } + + if limit == 0 { + // We have had too many bad pivots, switch to O(n log n) fallback + // algorithm. In our case that is driftsort in eager mode. + crate::slice::sort::stable::drift::sort(v, scratch, true, is_less); + return; + } + limit -= 1; + + let pivot_pos = choose_pivot(v, is_less); + // SAFETY: choose_pivot promises to return a valid pivot index. + unsafe { + intrinsics::assume(pivot_pos < v.len()); + } + + // SAFETY: We only access the temporary copy for Freeze types, otherwise + // self-modifications via `is_less` would not be observed and this would + // be unsound. Our temporary copy does not escape this scope. + let pivot_copy = unsafe { ManuallyDrop::new(ptr::read(&v[pivot_pos])) }; + let pivot_ref = (!has_direct_interior_mutability::<T>()).then_some(&*pivot_copy); + + // We choose a pivot, and check if this pivot is equal to our left + // ancestor. If true, we do a partition putting equal elements on the + // left and do not recurse on it. This gives O(n log k) sorting for k + // distinct values, a strategy borrowed from pdqsort. For types with + // interior mutability we can't soundly create a temporary copy of the + // ancestor pivot, and use left_partition_len == 0 as our method for + // detecting when we re-use a pivot, which means we do at most three + // partition operations with pivot p instead of the optimal two. + let mut perform_equal_partition = false; + if let Some(la_pivot) = left_ancestor_pivot { + perform_equal_partition = !is_less(la_pivot, &v[pivot_pos]); + } + + let mut left_partition_len = 0; + if !perform_equal_partition { + left_partition_len = stable_partition(v, scratch, pivot_pos, false, is_less); + perform_equal_partition = left_partition_len == 0; + } + + if perform_equal_partition { + let mid_eq = stable_partition(v, scratch, pivot_pos, true, &mut |a, b| !is_less(b, a)); + v = &mut v[mid_eq..]; + left_ancestor_pivot = None; + continue; + } + + // Process left side with the next loop iter, right side with recursion. + let (left, right) = v.split_at_mut(left_partition_len); + quicksort(right, scratch, limit, pivot_ref, is_less); + v = left; + } +} + +/// Partitions `v` using pivot `p = v[pivot_pos]` and returns the number of +/// elements less than `p`. The relative order of elements that compare < p and +/// those that compare >= p is preserved - it is a stable partition. +/// +/// If `is_less` is not a strict total order or panics, `scratch.len() < v.len()`, +/// or `pivot_pos >= v.len()`, the result and `v`'s state is sound but unspecified. +fn stable_partition<T, F: FnMut(&T, &T) -> bool>( + v: &mut [T], + scratch: &mut [MaybeUninit<T>], + pivot_pos: usize, + pivot_goes_left: bool, + is_less: &mut F, +) -> usize { + let len = v.len(); + + if intrinsics::unlikely(scratch.len() < len || pivot_pos >= len) { + core::intrinsics::abort() + } + + let v_base = v.as_ptr(); + let scratch_base = MaybeUninit::slice_as_mut_ptr(scratch); + + // The core idea is to write the values that compare as less-than to the left + // side of `scratch`, while the values that compared as greater or equal than + // `v[pivot_pos]` go to the right side of `scratch` in reverse. See + // PartitionState for details. + + // SAFETY: see individual comments. + unsafe { + // SAFETY: we made sure the scratch has length >= len and that pivot_pos + // is in-bounds. v and scratch are disjoint slices. + let pivot = v_base.add(pivot_pos); + let mut state = PartitionState::new(v_base, scratch_base, len); + + let mut pivot_in_scratch = ptr::null_mut(); + let mut loop_end_pos = pivot_pos; + + // SAFETY: this loop is equivalent to calling state.partition_one + // exactly len times. + loop { + // Ideally the outer loop won't be unrolled, to save binary size, + // but we do want the inner loop to be unrolled for small types, as + // this gave significant performance boosts in benchmarks. Unrolling + // through for _ in 0..UNROLL_LEN { .. } instead of manually improves + // compile times but has a ~10-20% performance penalty on opt-level=s. + if const { mem::size_of::<T>() <= 16 } { + const UNROLL_LEN: usize = 4; + let unroll_end = v_base.add(loop_end_pos.saturating_sub(UNROLL_LEN - 1)); + while state.scan < unroll_end { + state.partition_one(is_less(&*state.scan, &*pivot)); + state.partition_one(is_less(&*state.scan, &*pivot)); + state.partition_one(is_less(&*state.scan, &*pivot)); + state.partition_one(is_less(&*state.scan, &*pivot)); + } + } + + let loop_end = v_base.add(loop_end_pos); + while state.scan < loop_end { + state.partition_one(is_less(&*state.scan, &*pivot)); + } + + if loop_end_pos == len { + break; + } + + // We avoid comparing pivot with itself, as this could create deadlocks for + // certain comparison operators. We also store its location later for later. + pivot_in_scratch = state.partition_one(pivot_goes_left); + + loop_end_pos = len; + } + + // `pivot` must be copied into its correct position again, because a + // comparison operator might have modified it. + if has_direct_interior_mutability::<T>() { + ptr::copy_nonoverlapping(pivot, pivot_in_scratch, 1); + } + + // SAFETY: partition_one being called exactly len times guarantees that scratch + // is initialized with a permuted copy of `v`, and that num_left <= v.len(). + // Copying scratch[0..num_left] and scratch[num_left..v.len()] back is thus + // sound, as the values in scratch will never be read again, meaning our copies + // semantically act as moves, permuting `v`. + + // Copy all the elements < p directly from swap to v. + let v_base = v.as_mut_ptr(); + ptr::copy_nonoverlapping(scratch_base, v_base, state.num_left); + + // Copy the elements >= p in reverse order. + for i in 0..len - state.num_left { + ptr::copy_nonoverlapping( + scratch_base.add(len - 1 - i), + v_base.add(state.num_left + i), + 1, + ); + } + + state.num_left + } +} + +struct PartitionState<T> { + // The start of the scratch auxiliary memory. + scratch_base: *mut T, + // The current element that is being looked at, scans left to right through slice. + scan: *const T, + // Counts the number of elements that went to the left side, also works around: + // https://github.com/rust-lang/rust/issues/117128 + num_left: usize, + // Reverse scratch output pointer. + scratch_rev: *mut T, +} + +impl<T> PartitionState<T> { + /// # Safety + /// scan and scratch must point to valid disjoint buffers of length len. The + /// scan buffer must be initialized. + unsafe fn new(scan: *const T, scratch: *mut T, len: usize) -> Self { + // SAFETY: See function safety comment. + unsafe { Self { scratch_base: scratch, scan, num_left: 0, scratch_rev: scratch.add(len) } } + } + + /// Depending on the value of `towards_left` this function will write a value + /// to the growing left or right side of the scratch memory. This forms the + /// branchless core of the partition. + /// + /// # Safety + /// This function may be called at most `len` times. If it is called exactly + /// `len` times the scratch buffer then contains a copy of each element from + /// the scan buffer exactly once - a permutation, and num_left <= len. + unsafe fn partition_one(&mut self, towards_left: bool) -> *mut T { + // SAFETY: see individual comments. + unsafe { + // SAFETY: in-bounds because this function is called at most len times, and thus + // right now is incremented at most len - 1 times. Similarly, num_left < len and + // num_right < len, where num_right == i - num_left at the start of the ith + // iteration (zero-indexed). + self.scratch_rev = self.scratch_rev.sub(1); + + // SAFETY: now we have scratch_rev == base + len - (i + 1). This means + // scratch_rev + num_left == base + len - 1 - num_right < base + len. + let dst_base = if towards_left { self.scratch_base } else { self.scratch_rev }; + let dst = dst_base.add(self.num_left); + ptr::copy_nonoverlapping(self.scan, dst, 1); + + self.num_left += towards_left as usize; + self.scan = self.scan.add(1); + dst + } + } +} + +trait IsFreeze { + fn is_freeze() -> bool; +} + +impl<T> IsFreeze for T { + default fn is_freeze() -> bool { + false + } +} +impl<T: FreezeMarker> IsFreeze for T { + fn is_freeze() -> bool { + true + } +} + +#[must_use] +fn has_direct_interior_mutability<T>() -> bool { + // If a type has interior mutability it may alter itself during comparison + // in a way that must be preserved after the sort operation concludes. + // Otherwise a type like Mutex<Option<Box<str>>> could lead to double free. + !T::is_freeze() +} diff --git a/library/core/src/slice/sort/unstable/heapsort.rs b/library/core/src/slice/sort/unstable/heapsort.rs new file mode 100644 index 00000000000..559605ef4b6 --- /dev/null +++ b/library/core/src/slice/sort/unstable/heapsort.rs @@ -0,0 +1,80 @@ +//! This module contains a branchless heapsort as fallback for unstable quicksort. + +use crate::intrinsics; +use crate::ptr; + +/// Sorts `v` using heapsort, which guarantees *O*(*n* \* log(*n*)) worst-case. +/// +/// Never inline this, it sits the main hot-loop in `recurse` and is meant as unlikely algorithmic +/// fallback. +/// +/// SAFETY: The caller has to guarantee that `v.len()` >= 2. +#[inline(never)] +pub(crate) unsafe fn heapsort<T, F>(v: &mut [T], is_less: &mut F) +where + F: FnMut(&T, &T) -> bool, +{ + // SAFETY: See function safety. + unsafe { + intrinsics::assume(v.len() >= 2); + + // Build the heap in linear time. + for i in (0..v.len() / 2).rev() { + sift_down(v, i, is_less); + } + + // Pop maximal elements from the heap. + for i in (1..v.len()).rev() { + v.swap(0, i); + sift_down(&mut v[..i], 0, is_less); + } + } +} + +// This binary heap respects the invariant `parent >= child`. +// +// SAFETY: The caller has to guarantee that node < `v.len()`. +#[inline(never)] +unsafe fn sift_down<T, F>(v: &mut [T], mut node: usize, is_less: &mut F) +where + F: FnMut(&T, &T) -> bool, +{ + // SAFETY: See function safety. + unsafe { + intrinsics::assume(node < v.len()); + } + + let len = v.len(); + + let v_base = v.as_mut_ptr(); + + loop { + // Children of `node`. + let mut child = 2 * node + 1; + if child >= len { + break; + } + + // SAFETY: The invariants and checks guarantee that both node and child are in-bounds. + unsafe { + // Choose the greater child. + if child + 1 < len { + // We need a branch to be sure not to out-of-bounds index, + // but it's highly predictable. The comparison, however, + // is better done branchless, especially for primitives. + child += is_less(&*v_base.add(child), &*v_base.add(child + 1)) as usize; + } + + // Stop if the invariant holds at `node`. + if !is_less(&*v_base.add(node), &*v_base.add(child)) { + break; + } + + // Swap `node` with the greater child, move one step down, and continue sifting. This + // could be ptr::swap_nonoverlapping but that adds a significant amount of binary-size. + ptr::swap(v_base.add(node), v_base.add(child)); + } + + node = child; + } +} diff --git a/library/core/src/slice/sort/unstable/mod.rs b/library/core/src/slice/sort/unstable/mod.rs new file mode 100644 index 00000000000..692c2d8f7c7 --- /dev/null +++ b/library/core/src/slice/sort/unstable/mod.rs @@ -0,0 +1,76 @@ +//! This module contains the entry points for `slice::sort_unstable`. + +use crate::intrinsics; +use crate::mem::SizedTypeProperties; + +use crate::slice::sort::shared::find_existing_run; +use crate::slice::sort::shared::smallsort::insertion_sort_shift_left; + +pub(crate) mod heapsort; +pub(crate) mod quicksort; + +/// Unstable sort called ipnsort by Lukas Bergdoll. +/// Design document: +/// <https://github.com/Voultapher/sort-research-rs/blob/main/writeup/ipnsort_introduction/text.md> +/// +/// Upholds all safety properties outlined here: +/// <https://github.com/Voultapher/sort-research-rs/blob/main/writeup/sort_safety/text.md> +#[inline(always)] +pub fn sort<T, F: FnMut(&T, &T) -> bool>(v: &mut [T], is_less: &mut F) { + // Arrays of zero-sized types are always all-equal, and thus sorted. + if T::IS_ZST { + return; + } + + // Instrumenting the standard library showed that 90+% of the calls to sort + // by rustc are either of size 0 or 1. + let len = v.len(); + if intrinsics::likely(len < 2) { + return; + } + + // More advanced sorting methods than insertion sort are faster if called in + // a hot loop for small inputs, but for general-purpose code the small + // binary size of insertion sort is more important. The instruction cache in + // modern processors is very valuable, and for a single sort call in general + // purpose code any gains from an advanced method are cancelled by i-cache + // misses during the sort, and thrashing the i-cache for surrounding code. + const MAX_LEN_ALWAYS_INSERTION_SORT: usize = 20; + if intrinsics::likely(len <= MAX_LEN_ALWAYS_INSERTION_SORT) { + insertion_sort_shift_left(v, 1, is_less); + return; + } + + ipnsort(v, is_less); +} + +/// See [`sort`] +/// +/// Deliberately don't inline the main sorting routine entrypoint to ensure the +/// inlined insertion sort i-cache footprint remains minimal. +#[inline(never)] +fn ipnsort<T, F>(v: &mut [T], is_less: &mut F) +where + F: FnMut(&T, &T) -> bool, +{ + let len = v.len(); + let (run_len, was_reversed) = find_existing_run(v, is_less); + + // SAFETY: find_existing_run promises to return a valid run_len. + unsafe { intrinsics::assume(run_len <= len) }; + + if run_len == len { + if was_reversed { + v.reverse(); + } + + // It would be possible to a do in-place merging here for a long existing streak. But that + // makes the implementation a lot bigger, users can use `slice::sort` for that use-case. + return; + } + + // Limit the number of imbalanced partitions to `2 * floor(log2(len))`. + // The binary OR by one is used to eliminate the zero-check in the logarithm. + let limit = 2 * (len | 1).ilog2(); + crate::slice::sort::unstable::quicksort::quicksort(v, None, limit, is_less); +} diff --git a/library/core/src/slice/sort/unstable/quicksort.rs b/library/core/src/slice/sort/unstable/quicksort.rs new file mode 100644 index 00000000000..533b5b0eec7 --- /dev/null +++ b/library/core/src/slice/sort/unstable/quicksort.rs @@ -0,0 +1,351 @@ +//! This module contains an unstable quicksort and two partition implementations. + +use crate::intrinsics; +use crate::mem::{self, ManuallyDrop}; +use crate::ptr; + +use crate::slice::sort::shared::pivot::choose_pivot; +use crate::slice::sort::shared::smallsort::UnstableSmallSortTypeImpl; + +/// Sorts `v` recursively. +/// +/// If the slice had a predecessor in the original array, it is specified as `ancestor_pivot`. +/// +/// `limit` is the number of allowed imbalanced partitions before switching to `heapsort`. If zero, +/// this function will immediately switch to heapsort. +pub(crate) fn quicksort<'a, T, F>( + mut v: &'a mut [T], + mut ancestor_pivot: Option<&'a T>, + mut limit: u32, + is_less: &mut F, +) where + F: FnMut(&T, &T) -> bool, +{ + loop { + if v.len() <= T::small_sort_threshold() { + T::small_sort(v, is_less); + return; + } + + // If too many bad pivot choices were made, simply fall back to heapsort in order to + // guarantee `O(N x log(N))` worst-case. + if limit == 0 { + // SAFETY: We assume the `small_sort` threshold is at least 1. + unsafe { + crate::slice::sort::unstable::heapsort::heapsort(v, is_less); + } + return; + } + + limit -= 1; + + // Choose a pivot and try guessing whether the slice is already sorted. + let pivot_pos = choose_pivot(v, is_less); + + // If the chosen pivot is equal to the predecessor, then it's the smallest element in the + // slice. Partition the slice into elements equal to and elements greater than the pivot. + // This case is usually hit when the slice contains many duplicate elements. + if let Some(p) = ancestor_pivot { + // SAFETY: We assume choose_pivot yields an in-bounds position. + if !is_less(p, unsafe { v.get_unchecked(pivot_pos) }) { + let num_lt = partition(v, pivot_pos, &mut |a, b| !is_less(b, a)); + + // Continue sorting elements greater than the pivot. We know that `num_lt` contains + // the pivot. So we can continue after `num_lt`. + v = &mut v[(num_lt + 1)..]; + ancestor_pivot = None; + continue; + } + } + + // Partition the slice. + let num_lt = partition(v, pivot_pos, is_less); + // SAFETY: partition ensures that `num_lt` will be in-bounds. + unsafe { intrinsics::assume(num_lt < v.len()) }; + + // Split the slice into `left`, `pivot`, and `right`. + let (left, right) = v.split_at_mut(num_lt); + let (pivot, right) = right.split_at_mut(1); + let pivot = &pivot[0]; + + // Recurse into the left side. We have a fixed recursion limit, testing shows no real + // benefit for recursing into the shorter side. + quicksort(left, ancestor_pivot, limit, is_less); + + // Continue with the right side. + v = right; + ancestor_pivot = Some(pivot); + } +} + +/// Takes the input slice `v` and re-arranges elements such that when the call returns normally +/// all elements that compare true for `is_less(elem, pivot)` where `pivot == v[pivot_pos]` are +/// on the left side of `v` followed by the other elements, notionally considered greater or +/// equal to `pivot`. +/// +/// Returns the number of elements that are compared true for `is_less(elem, pivot)`. +/// +/// If `is_less` does not implement a total order the resulting order and return value are +/// unspecified. All original elements will remain in `v` and any possible modifications via +/// interior mutability will be observable. Same is true if `is_less` panics or `v.len()` +/// exceeds `scratch.len()`. +pub(crate) fn partition<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize +where + F: FnMut(&T, &T) -> bool, +{ + let len = v.len(); + + // Allows for panic-free code-gen by proving this property to the compiler. + if len == 0 { + return 0; + } + + // Allows for panic-free code-gen by proving this property to the compiler. + if pivot >= len { + intrinsics::abort(); + } + + // Place the pivot at the beginning of slice. + v.swap(0, pivot); + let (pivot, v_without_pivot) = v.split_at_mut(1); + + // Assuming that Rust generates noalias LLVM IR we can be sure that a partition function + // signature of the form `(v: &mut [T], pivot: &T)` guarantees that pivot and v can't alias. + // Having this guarantee is crucial for optimizations. It's possible to copy the pivot value + // into a stack value, but this creates issues for types with interior mutability mandating + // a drop guard. + let pivot = &mut pivot[0]; + + // This construct is used to limit the LLVM IR generated, which saves large amounts of + // compile-time by only instantiating the code that is needed. Idea by Frank Steffahn. + let num_lt = (const { inst_partition::<T, F>() })(v_without_pivot, pivot, is_less); + + // Place the pivot between the two partitions. + v.swap(0, num_lt); + + num_lt +} + +const fn inst_partition<T, F: FnMut(&T, &T) -> bool>() -> fn(&mut [T], &T, &mut F) -> usize { + const MAX_BRANCHLESS_PARTITION_SIZE: usize = 96; + if mem::size_of::<T>() <= MAX_BRANCHLESS_PARTITION_SIZE { + // Specialize for types that are relatively cheap to copy, where branchless optimizations + // have large leverage e.g. `u64` and `String`. + partition_lomuto_branchless_cyclic::<T, F> + } else { + partition_hoare_branchy_cyclic::<T, F> + } +} + +/// See [`partition`]. +fn partition_hoare_branchy_cyclic<T, F>(v: &mut [T], pivot: &T, is_less: &mut F) -> usize +where + F: FnMut(&T, &T) -> bool, +{ + let len = v.len(); + + if len == 0 { + return 0; + } + + // Optimized for large types that are expensive to move. Not optimized for integers. Optimized + // for small code-gen, assuming that is_less is an expensive operation that generates + // substantial amounts of code or a call. And that copying elements will likely be a call to + // memcpy. Using 2 `ptr::copy_nonoverlapping` has the chance to be faster than + // `ptr::swap_nonoverlapping` because `memcpy` can use wide SIMD based on runtime feature + // detection. Benchmarks support this analysis. + + let mut gap_opt: Option<GapGuard<T>> = None; + + // SAFETY: The left-to-right scanning loop performs a bounds check, where we know that `left >= + // v_base && left < right && right <= v_base.add(len)`. The right-to-left scanning loop performs + // a bounds check ensuring that `right` is in-bounds. We checked that `len` is more than zero, + // which means that unconditional `right = right.sub(1)` is safe to do. The exit check makes + // sure that `left` and `right` never alias, making `ptr::copy_nonoverlapping` safe. The + // drop-guard `gap` ensures that should `is_less` panic we always overwrite the duplicate in the + // input. `gap.pos` stores the previous value of `right` and starts at `right` and so it too is + // in-bounds. We never pass the saved `gap.value` to `is_less` while it is inside the `GapGuard` + // thus any changes via interior mutability will be observed. + unsafe { + let v_base = v.as_mut_ptr(); + + let mut left = v_base; + let mut right = v_base.add(len); + + loop { + // Find the first element greater than the pivot. + while left < right && is_less(&*left, pivot) { + left = left.add(1); + } + + // Find the last element equal to the pivot. + loop { + right = right.sub(1); + if left >= right || is_less(&*right, pivot) { + break; + } + } + + if left >= right { + break; + } + + // Swap the found pair of out-of-order elements via cyclic permutation. + let is_first_swap_pair = gap_opt.is_none(); + + if is_first_swap_pair { + gap_opt = Some(GapGuard { pos: right, value: ManuallyDrop::new(ptr::read(left)) }); + } + + let gap = gap_opt.as_mut().unwrap_unchecked(); + + // Single place where we instantiate ptr::copy_nonoverlapping in the partition. + if !is_first_swap_pair { + ptr::copy_nonoverlapping(left, gap.pos, 1); + } + gap.pos = right; + ptr::copy_nonoverlapping(right, left, 1); + + left = left.add(1); + } + + left.sub_ptr(v_base) + + // `gap_opt` goes out of scope and overwrites the last wrong-side element on the right side + // with the first wrong-side element of the left side that was initially overwritten by the + // first wrong-side element on the right side element. + } +} + +struct PartitionState<T> { + // The current element that is being looked at, scans left to right through slice. + right: *mut T, + // Counts the number of elements that compared less-than, also works around: + // https://github.com/rust-lang/rust/issues/117128 + num_lt: usize, + // Gap guard that tracks the temporary duplicate in the input. + gap: GapGuardRaw<T>, +} + +fn partition_lomuto_branchless_cyclic<T, F>(v: &mut [T], pivot: &T, is_less: &mut F) -> usize +where + F: FnMut(&T, &T) -> bool, +{ + // Novel partition implementation by Lukas Bergdoll and Orson Peters. Branchless Lomuto + // partition paired with a cyclic permutation. + // https://github.com/Voultapher/sort-research-rs/blob/main/writeup/lomcyc_partition/text.md + + let len = v.len(); + let v_base = v.as_mut_ptr(); + + if len == 0 { + return 0; + } + + // SAFETY: We checked that `len` is more than zero, which means that reading `v_base` is safe to + // do. From there we have a bounded loop where `v_base.add(i)` is guaranteed in-bounds. `v` and + // `pivot` can't alias because of type system rules. The drop-guard `gap` ensures that should + // `is_less` panic we always overwrite the duplicate in the input. `gap.pos` stores the previous + // value of `right` and starts at `v_base` and so it too is in-bounds. Given `UNROLL_LEN == 2` + // after the main loop we either have A) the last element in `v` that has not yet been processed + // because `len % 2 != 0`, or B) all elements have been processed except the gap value that was + // saved at the beginning with `ptr::read(v_base)`. In the case A) the loop will iterate twice, + // first performing loop_body to take care of the last element that didn't fit into the unroll. + // After that the behavior is the same as for B) where we use the saved value as `right` to + // overwrite the duplicate. If this very last call to `is_less` panics the saved value will be + // copied back including all possible changes via interior mutability. If `is_less` does not + // panic and the code continues we overwrite the duplicate and do `right = right.add(1)`, this + // is safe to do with `&mut *gap.value` because `T` is the same as `[T; 1]` and generating a + // pointer one past the allocation is safe. + unsafe { + let mut loop_body = |state: &mut PartitionState<T>| { + let right_is_lt = is_less(&*state.right, pivot); + let left = v_base.add(state.num_lt); + + ptr::copy(left, state.gap.pos, 1); + ptr::copy_nonoverlapping(state.right, left, 1); + + state.gap.pos = state.right; + state.num_lt += right_is_lt as usize; + + state.right = state.right.add(1); + }; + + // Ideally we could just use GapGuard in PartitionState, but the reference that is + // materialized with `&mut state` when calling `loop_body` would create a mutable reference + // to the parent struct that contains the gap value, invalidating the reference pointer + // created from a reference to the gap value in the cleanup loop. This is only an issue + // under Stacked Borrows, Tree Borrows accepts the intuitive code using GapGuard as valid. + let mut gap_value = ManuallyDrop::new(ptr::read(v_base)); + + let mut state = PartitionState { + num_lt: 0, + right: v_base.add(1), + + gap: GapGuardRaw { pos: v_base, value: &mut *gap_value }, + }; + + // Manual unrolling that works well on x86, Arm and with opt-level=s without murdering + // compile-times. Leaving this to the compiler yields ok to bad results. + let unroll_len = const { if mem::size_of::<T>() <= 16 { 2 } else { 1 } }; + + let unroll_end = v_base.add(len - (unroll_len - 1)); + while state.right < unroll_end { + if unroll_len == 2 { + loop_body(&mut state); + loop_body(&mut state); + } else { + loop_body(&mut state); + } + } + + // Single instantiate `loop_body` for both the unroll cleanup and cyclic permutation + // cleanup. Optimizes binary-size and compile-time. + let end = v_base.add(len); + loop { + let is_done = state.right == end; + state.right = if is_done { state.gap.value } else { state.right }; + + loop_body(&mut state); + + if is_done { + mem::forget(state.gap); + break; + } + } + + state.num_lt + } +} + +struct GapGuard<T> { + pos: *mut T, + value: ManuallyDrop<T>, +} + +impl<T> Drop for GapGuard<T> { + fn drop(&mut self) { + // SAFETY: `self` MUST be constructed in a way that makes copying the gap value into + // `self.pos` sound. + unsafe { + ptr::copy_nonoverlapping(&*self.value, self.pos, 1); + } + } +} + +/// Ideally this wouldn't be needed and we could just use the regular GapGuard. +/// See comment in [`partition_lomuto_branchless_cyclic`]. +struct GapGuardRaw<T> { + pos: *mut T, + value: *mut T, +} + +impl<T> Drop for GapGuardRaw<T> { + fn drop(&mut self) { + // SAFETY: `self` MUST be constructed in a way that makes copying the gap value into + // `self.pos` sound. + unsafe { + ptr::copy_nonoverlapping(self.value, self.pos, 1); + } + } +} diff --git a/library/core/src/str/count.rs b/library/core/src/str/count.rs index d8667864fe5..b5d7aaf05d4 100644 --- a/library/core/src/str/count.rs +++ b/library/core/src/str/count.rs @@ -17,6 +17,7 @@ //! Note: Because the term "leading byte" can sometimes be ambiguous (for //! example, it could also refer to the first byte of a slice), we'll often use //! the term "non-continuation byte" to refer to these bytes in the code. + use core::intrinsics::unlikely; const USIZE_SIZE: usize = core::mem::size_of::<usize>(); diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 3d21b09fa8a..86a965f68e0 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -282,7 +282,7 @@ impl<'a> Context<'a> { pub const fn ext(&mut self) -> &mut dyn Any { // FIXME: this field makes Context extra-weird about unwind safety // can we justify AssertUnwindSafe if we stabilize this? do we care? - match &mut *self.ext { + match &mut self.ext.0 { ExtData::Some(data) => *data, ExtData::None(unit) => unit, } @@ -356,7 +356,7 @@ impl<'a> ContextBuilder<'a> { #[rustc_const_unstable(feature = "const_waker", issue = "102012")] #[unstable(feature = "context_ext", issue = "123392")] pub const fn from(cx: &'a mut Context<'_>) -> Self { - let ext = match &mut *cx.ext { + let ext = match &mut cx.ext.0 { ExtData::Some(ext) => ExtData::Some(*ext), ExtData::None(()) => ExtData::None(()), }; diff --git a/library/core/tests/clone.rs b/library/core/tests/clone.rs index 64193e11558..23efab2f1b5 100644 --- a/library/core/tests/clone.rs +++ b/library/core/tests/clone.rs @@ -1,3 +1,6 @@ +use core::clone::CloneToUninit; +use core::mem::MaybeUninit; + #[test] #[allow(suspicious_double_ref_op)] fn test_borrowed_clone() { @@ -14,3 +17,66 @@ fn test_clone_from() { b.clone_from(&a); assert_eq!(*b, 5); } + +#[test] +fn test_clone_to_uninit_slice_success() { + // Using `String`s to exercise allocation and Drop of the individual elements; + // if something is aliased or double-freed, at least Miri will catch that. + let a: [String; 3] = ["a", "b", "c"].map(String::from); + + let mut storage: MaybeUninit<[String; 3]> = MaybeUninit::uninit(); + let b: [String; 3] = unsafe { + a[..].clone_to_uninit(storage.as_mut_ptr() as *mut [String]); + storage.assume_init() + }; + + assert_eq!(a, b); +} + +#[test] +#[cfg(panic = "unwind")] +fn test_clone_to_uninit_slice_drops_on_panic() { + use core::sync::atomic::{AtomicUsize, Ordering::Relaxed}; + + /// A static counter is OK to use as long as _this one test_ isn't run several times in + /// multiple threads. + static COUNTER: AtomicUsize = AtomicUsize::new(0); + /// Counts how many instances are live, and panics if a fifth one is created + struct CountsDropsAndPanics {} + impl CountsDropsAndPanics { + fn new() -> Self { + COUNTER.fetch_add(1, Relaxed); + Self {} + } + } + impl Clone for CountsDropsAndPanics { + fn clone(&self) -> Self { + if COUNTER.load(Relaxed) == 4 { panic!("intentional panic") } else { Self::new() } + } + } + impl Drop for CountsDropsAndPanics { + fn drop(&mut self) { + COUNTER.fetch_sub(1, Relaxed); + } + } + + let a: [CountsDropsAndPanics; 3] = core::array::from_fn(|_| CountsDropsAndPanics::new()); + assert_eq!(COUNTER.load(Relaxed), 3); + + let panic_payload = std::panic::catch_unwind(|| { + let mut storage: MaybeUninit<[CountsDropsAndPanics; 3]> = MaybeUninit::uninit(); + // This should panic halfway through + unsafe { + a[..].clone_to_uninit(storage.as_mut_ptr() as *mut [CountsDropsAndPanics]); + } + }) + .unwrap_err(); + assert_eq!(panic_payload.downcast().unwrap(), Box::new("intentional panic")); + + // Check for lack of leak, which is what this test is looking for + assert_eq!(COUNTER.load(Relaxed), 3, "leaked during clone!"); + + // Might as well exercise the rest of the drops + drop(a); + assert_eq!(COUNTER.load(Relaxed), 0); +} diff --git a/library/core/tests/iter/adapters/map_windows.rs b/library/core/tests/iter/adapters/map_windows.rs index 7fb2408f8ac..6744eff3fa2 100644 --- a/library/core/tests/iter/adapters/map_windows.rs +++ b/library/core/tests/iter/adapters/map_windows.rs @@ -3,6 +3,7 @@ use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; #[cfg(not(panic = "abort"))] mod drop_checks { //! These tests mainly make sure the elements are correctly dropped. + use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst}; #[derive(Debug)] diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index f632883b563..3a2c98db0d5 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -8,6 +8,7 @@ #![feature(async_iterator)] #![feature(bigint_helper_methods)] #![feature(cell_update)] +#![feature(clone_to_uninit)] #![feature(const_align_offset)] #![feature(const_align_of_val_raw)] #![feature(const_black_box)] @@ -48,12 +49,12 @@ #![feature(is_sorted)] #![feature(layout_for_ptr)] #![feature(pattern)] -#![feature(sort_internals)] #![feature(slice_take)] #![feature(slice_from_ptr_range)] #![feature(slice_split_once)] #![feature(split_as_slice)] #![feature(maybe_uninit_fill)] +#![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_write_slice)] #![feature(maybe_uninit_uninit_array_transpose)] diff --git a/library/core/tests/net/parser.rs b/library/core/tests/net/parser.rs index 36b87d7c1f5..e03959ac77c 100644 --- a/library/core/tests/net/parser.rs +++ b/library/core/tests/net/parser.rs @@ -1,4 +1,5 @@ // FIXME: These tests are all excellent candidates for AFL fuzz testing + use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use core::str::FromStr; diff --git a/library/core/tests/num/ieee754.rs b/library/core/tests/num/ieee754.rs index 48ab75b6f17..b0f6a7545aa 100644 --- a/library/core/tests/num/ieee754.rs +++ b/library/core/tests/num/ieee754.rs @@ -27,6 +27,7 @@ //! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests. //! Please consider this carefully when adding, removing, or reorganizing these tests. They are //! here so that it is clear what tests are required by the standard and what can be changed. + use ::core::str::FromStr; // IEEE 754 for many tests is applied to specific bit patterns. diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs index a1edb1a5186..2320a7acc35 100644 --- a/library/core/tests/num/int_log.rs +++ b/library/core/tests/num/int_log.rs @@ -24,15 +24,15 @@ fn checked_ilog() { #[cfg(not(miri))] // Miri is too slow for i in i16::MIN..=0 { - assert_eq!(i.checked_ilog(4), None); + assert_eq!(i.checked_ilog(4), None, "checking {i}"); } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32)); + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32), "checking {i}"); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32)); + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32), "checking {i}"); } } @@ -49,30 +49,30 @@ fn checked_ilog2() { assert_eq!(0i16.checked_ilog2(), None); for i in 1..=u8::MAX { - assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { // Guard against Android's imprecise f32::ilog2 implementation. if i != 8192 && i != 32768 { - assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); } } for i in i8::MIN..=0 { - assert_eq!(i.checked_ilog2(), None); + assert_eq!(i.checked_ilog2(), None, "checking {i}"); } for i in 1..=i8::MAX { - assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); } #[cfg(not(miri))] // Miri is too slow for i in i16::MIN..=0 { - assert_eq!(i.checked_ilog2(), None); + assert_eq!(i.checked_ilog2(), None, "checking {i}"); } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { // Guard against Android's imprecise f32::ilog2 implementation. if i != 8192 { - assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); } } } @@ -95,19 +95,19 @@ fn checked_ilog10() { #[cfg(not(miri))] // Miri is too slow for i in i16::MIN..=0 { - assert_eq!(i.checked_ilog10(), None); + assert_eq!(i.checked_ilog10(), None, "checking {i}"); } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32)); + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32), "checking {i}"); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32)); + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32), "checking {i}"); } #[cfg(not(miri))] // Miri is too slow for i in 1..=100_000u32 { - assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32)); + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32), "checking {i}"); } } diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index b1b9492f182..336a79a02ce 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -574,4 +574,13 @@ fn as_slice() { assert_eq!(Some(43).as_mut_slice(), &[43]); assert_eq!(None::<i32>.as_slice(), &[]); assert_eq!(None::<i32>.as_mut_slice(), &[]); + + const A: &[u32] = Some(44).as_slice(); + const B: &[u32] = None.as_slice(); + const _: () = { + let [45] = Some(45).as_mut_slice() else { panic!() }; + let []: &[u32] = None.as_mut_slice() else { panic!() }; + }; + assert_eq!(A, &[44]); + assert_eq!(B, &[]); } diff --git a/library/core/tests/pin_macro.rs b/library/core/tests/pin_macro.rs index 79c8c166c58..57485ef3974 100644 --- a/library/core/tests/pin_macro.rs +++ b/library/core/tests/pin_macro.rs @@ -1,4 +1,5 @@ // edition:2021 + use core::{ marker::PhantomPinned, mem::{drop as stuff, transmute}, diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index c91ac2fbb43..4cbbabb672b 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1803,9 +1803,7 @@ fn brute_force_rotate_test_1() { #[test] #[cfg(not(target_arch = "wasm32"))] fn sort_unstable() { - use core::cmp::Ordering::{Equal, Greater, Less}; - use core::slice::heapsort; - use rand::{seq::SliceRandom, Rng}; + use rand::Rng; // Miri is too slow (but still need to `chain` to make the types match) let lens = if cfg!(miri) { (2..20).chain(0..0) } else { (2..25).chain(500..510) }; @@ -1839,31 +1837,10 @@ fn sort_unstable() { tmp.copy_from_slice(v); tmp.sort_unstable_by(|a, b| b.cmp(a)); assert!(tmp.windows(2).all(|w| w[0] >= w[1])); - - // Test heapsort using `<` operator. - tmp.copy_from_slice(v); - heapsort(tmp, |a, b| a < b); - assert!(tmp.windows(2).all(|w| w[0] <= w[1])); - - // Test heapsort using `>` operator. - tmp.copy_from_slice(v); - heapsort(tmp, |a, b| a > b); - assert!(tmp.windows(2).all(|w| w[0] >= w[1])); } } } - // Sort using a completely random comparison function. - // This will reorder the elements *somehow*, but won't panic. - for i in 0..v.len() { - v[i] = i as i32; - } - v.sort_unstable_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap()); - v.sort_unstable(); - for i in 0..v.len() { - assert_eq!(v[i], i as i32); - } - // Should not panic. [0i32; 0].sort_unstable(); [(); 10].sort_unstable(); diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 353de8c5c57..14ba4af2bb5 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -14,7 +14,7 @@ #![feature(std_internals)] #![feature(staged_api)] #![feature(rustc_attrs)] -#![feature(c_unwind)] +#![cfg_attr(bootstrap, feature(c_unwind))] #![allow(internal_features)] #[cfg(target_os = "android")] diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml index dce2da31644..f830808d196 100644 --- a/library/panic_unwind/Cargo.toml +++ b/library/panic_unwind/Cargo.toml @@ -16,7 +16,7 @@ alloc = { path = "../alloc" } core = { path = "../core" } unwind = { path = "../unwind" } compiler_builtins = "0.1.0" -cfg-if = "1.0" +cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2", default-features = false } diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index b0245de501e..4dc36120608 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -24,7 +24,7 @@ #![feature(rustc_attrs)] #![panic_runtime] #![feature(panic_runtime)] -#![feature(c_unwind)] +#![cfg_attr(bootstrap, feature(c_unwind))] // `real_imp` is unused with Miri, so silence warnings. #![cfg_attr(miri, allow(dead_code))] #![allow(internal_features)] diff --git a/library/panic_unwind/src/miri.rs b/library/panic_unwind/src/miri.rs index 4d21e846010..695adadd59b 100644 --- a/library/panic_unwind/src/miri.rs +++ b/library/panic_unwind/src/miri.rs @@ -1,4 +1,5 @@ //! Unwinding panics for Miri. + use alloc::boxed::Box; use core::any::Any; diff --git a/library/portable-simd/crates/core_simd/examples/dot_product.rs b/library/portable-simd/crates/core_simd/examples/dot_product.rs index f047010a65c..75d152ae7f0 100644 --- a/library/portable-simd/crates/core_simd/examples/dot_product.rs +++ b/library/portable-simd/crates/core_simd/examples/dot_product.rs @@ -1,6 +1,5 @@ -// Code taken from the `packed_simd` crate -// Run this code with `cargo test --example dot_product` -//use std::iter::zip; +//! Code taken from the `packed_simd` crate. +//! Run this code with `cargo test --example dot_product`. #![feature(array_chunks)] #![feature(slice_as_chunks)] diff --git a/library/portable-simd/crates/core_simd/src/ops/assign.rs b/library/portable-simd/crates/core_simd/src/ops/assign.rs index 0e87785025a..d21d867de26 100644 --- a/library/portable-simd/crates/core_simd/src/ops/assign.rs +++ b/library/portable-simd/crates/core_simd/src/ops/assign.rs @@ -1,4 +1,5 @@ //! Assignment operators + use super::*; use core::ops::{AddAssign, MulAssign}; // commutative binary op-assignment use core::ops::{BitAndAssign, BitOrAssign, BitXorAssign}; // commutative bit binary op-assignment diff --git a/library/portable-simd/crates/core_simd/src/ops/deref.rs b/library/portable-simd/crates/core_simd/src/ops/deref.rs index 89a60ba1141..0ff76cfba39 100644 --- a/library/portable-simd/crates/core_simd/src/ops/deref.rs +++ b/library/portable-simd/crates/core_simd/src/ops/deref.rs @@ -2,6 +2,7 @@ //! Ideally, Rust would take care of this itself, //! and method calls usually handle the LHS implicitly. //! But this is not the case with arithmetic ops. + use super::*; macro_rules! deref_lhs { diff --git a/library/proc_macro/src/bridge/buffer.rs b/library/proc_macro/src/bridge/buffer.rs index 48030f8d82d..149767bf705 100644 --- a/library/proc_macro/src/bridge/buffer.rs +++ b/library/proc_macro/src/bridge/buffer.rs @@ -119,7 +119,9 @@ impl Write for Buffer { } impl Drop for Buffer { - #[inline] + // HACK(nbdd0121): Hack to prevent LLVM < 17.0.4 from misoptimising, + // change to `#[inline]` if fixed. + #[inline(never)] fn drop(&mut self) { let b = self.take(); (b.drop)(b); diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index cf9a3446522..6413b3515ec 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2742,18 +2742,15 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder { /// # Examples /// /// ```no_run -/// #![feature(fs_try_exists)] /// use std::fs; /// -/// assert!(!fs::try_exists("does_not_exist.txt").expect("Can't check existence of file does_not_exist.txt")); -/// assert!(fs::try_exists("/root/secret_file.txt").is_err()); +/// assert!(!fs::exists("does_not_exist.txt").expect("Can't check existence of file does_not_exist.txt")); +/// assert!(fs::exists("/root/secret_file.txt").is_err()); /// ``` /// /// [`Path::exists`]: crate::path::Path::exists -// FIXME: stabilization should modify documentation of `exists()` to recommend this method -// instead. -#[unstable(feature = "fs_try_exists", issue = "83186")] +#[stable(feature = "fs_try_exists", since = "CURRENT_RUSTC_VERSION")] #[inline] -pub fn try_exists<P: AsRef<Path>>(path: P) -> io::Result<bool> { - fs_imp::try_exists(path.as_ref()) +pub fn exists<P: AsRef<Path>>(path: P) -> io::Result<bool> { + fs_imp::exists(path.as_ref()) } diff --git a/library/std/src/hash/random.rs b/library/std/src/hash/random.rs index a1ccbb25369..0adf91e14ac 100644 --- a/library/std/src/hash/random.rs +++ b/library/std/src/hash/random.rs @@ -6,6 +6,7 @@ //! outside this crate. //! //! [`collections`]: crate::collections + #[allow(deprecated)] use super::{BuildHasher, Hasher, SipHasher13}; use crate::cell::Cell; diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index e9e29d60ca2..796137c0123 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -1,13 +1,14 @@ -///! An encapsulation of `BufReader`'s buffer management logic. -/// -/// This module factors out the basic functionality of `BufReader` in order to protect two core -/// invariants: -/// * `filled` bytes of `buf` are always initialized -/// * `pos` is always <= `filled` -/// Since this module encapsulates the buffer management logic, we can ensure that the range -/// `pos..filled` is always a valid index into the initialized region of the buffer. This means -/// that user code which wants to do reads from a `BufReader` via `buffer` + `consume` can do so -/// without encountering any runtime bounds checks. +//! An encapsulation of `BufReader`'s buffer management logic. +//! +//! This module factors out the basic functionality of `BufReader` in order to protect two core +//! invariants: +//! * `filled` bytes of `buf` are always initialized +//! * `pos` is always <= `filled` +//! Since this module encapsulates the buffer management logic, we can ensure that the range +//! `pos..filled` is always a valid index into the initialized region of the buffer. This means +//! that user code which wants to do reads from a `BufReader` via `buffer` + `consume` can do so +//! without encountering any runtime bounds checks. + use crate::cmp; use crate::io::{self, BorrowedBuf, Read}; use crate::mem::MaybeUninit; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 1c226f9f08f..caa8c7375ec 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -273,18 +273,17 @@ // // Language features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(c_unwind))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(asm_experimental_arch)] -#![feature(c_unwind)] #![feature(cfg_sanitizer_cfi)] #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] #![feature(concat_idents)] #![feature(const_mut_refs)] -#![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index bcab15db35b..858776f1446 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -27,7 +27,7 @@ use crate::io::{self, ErrorKind}; pub use self::ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::socket_addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; -#[unstable(feature = "tcplistener_into_incoming", issue = "88339")] +#[unstable(feature = "tcplistener_into_incoming", issue = "88373")] pub use self::tcp::IntoIncoming; #[stable(feature = "rust1", since = "1.0.0")] pub use self::tcp::{Incoming, TcpListener, TcpStream}; diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 9667d5f920e..6336354239b 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -105,7 +105,7 @@ pub struct Incoming<'a> { /// /// [`accept`]: TcpListener::accept #[derive(Debug)] -#[unstable(feature = "tcplistener_into_incoming", issue = "88339")] +#[unstable(feature = "tcplistener_into_incoming", issue = "88373")] pub struct IntoIncoming { listener: TcpListener, } @@ -894,7 +894,7 @@ impl TcpListener { /// } /// ``` #[must_use = "`self` will be dropped if the result is not used"] - #[unstable(feature = "tcplistener_into_incoming", issue = "88339")] + #[unstable(feature = "tcplistener_into_incoming", issue = "88373")] pub fn into_incoming(self) -> IntoIncoming { IntoIncoming { listener: self } } @@ -1033,7 +1033,7 @@ impl<'a> Iterator for Incoming<'a> { #[stable(feature = "tcp_listener_incoming_fused_iterator", since = "1.64.0")] impl FusedIterator for Incoming<'_> {} -#[unstable(feature = "tcplistener_into_incoming", issue = "88339")] +#[unstable(feature = "tcplistener_into_incoming", issue = "88373")] impl Iterator for IntoIncoming { type Item = io::Result<TcpStream>; fn next(&mut self) -> Option<io::Result<TcpStream>> { @@ -1041,7 +1041,7 @@ impl Iterator for IntoIncoming { } } -#[unstable(feature = "tcplistener_into_incoming", issue = "88339")] +#[unstable(feature = "tcplistener_into_incoming", issue = "88373")] impl FusedIterator for IntoIncoming {} impl AsInner<net_imp::TcpListener> for TcpListener { diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs index 2ba67a6dd1a..91959094797 100644 --- a/library/std/src/os/linux/process.rs +++ b/library/std/src/os/linux/process.rs @@ -6,20 +6,20 @@ use crate::io::Result; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; -use crate::process; +use crate::process::{self, ExitStatus}; use crate::sealed::Sealed; #[cfg(not(doc))] -use crate::sys::fd::FileDesc; +use crate::sys::{fd::FileDesc, linux::pidfd::PidFd as InnerPidFd}; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; #[cfg(doc)] -struct FileDesc; +struct InnerPidFd; /// This type represents a file descriptor that refers to a process. /// /// A `PidFd` can be obtained by setting the corresponding option on [`Command`] /// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved -/// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`]. +/// from the [`Child`] by calling [`pidfd`] or [`into_pidfd`]. /// /// Example: /// ```no_run @@ -33,7 +33,7 @@ struct FileDesc; /// .expect("Failed to spawn child"); /// /// let pidfd = child -/// .take_pidfd() +/// .into_pidfd() /// .expect("Failed to retrieve pidfd"); /// /// // The file descriptor will be closed when `pidfd` is dropped. @@ -44,28 +44,63 @@ struct FileDesc; /// [`create_pidfd`]: CommandExt::create_pidfd /// [`Child`]: process::Child /// [`pidfd`]: fn@ChildExt::pidfd -/// [`take_pidfd`]: ChildExt::take_pidfd +/// [`into_pidfd`]: ChildExt::into_pidfd /// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html #[derive(Debug)] +#[repr(transparent)] pub struct PidFd { - inner: FileDesc, + inner: InnerPidFd, } -impl AsInner<FileDesc> for PidFd { +impl PidFd { + /// Forces the child process to exit. + /// + /// Unlike [`Child::kill`] it is possible to attempt to kill + /// reaped children since PidFd does not suffer from pid recycling + /// races. But doing so will return an Error. + /// + /// [`Child::kill`]: process::Child::kill + pub fn kill(&self) -> Result<()> { + self.inner.kill() + } + + /// Waits for the child to exit completely, returning the status that it exited with. + /// + /// Unlike [`Child::wait`] it does not ensure that the stdin handle is closed. + /// Additionally it will not return an `ExitStatus` if the child + /// has already been reaped. Instead an error will be returned. + /// + /// [`Child::wait`]: process::Child::wait + pub fn wait(&self) -> Result<ExitStatus> { + self.inner.wait().map(FromInner::from_inner) + } + + /// Attempts to collect the exit status of the child if it has already exited. + /// + /// Unlike [`Child::try_wait`] this method will return an Error + /// if the child has already been reaped. + /// + /// [`Child::try_wait`]: process::Child::try_wait + pub fn try_wait(&self) -> Result<Option<ExitStatus>> { + Ok(self.inner.try_wait()?.map(FromInner::from_inner)) + } +} + +impl AsInner<InnerPidFd> for PidFd { #[inline] - fn as_inner(&self) -> &FileDesc { + fn as_inner(&self) -> &InnerPidFd { &self.inner } } -impl FromInner<FileDesc> for PidFd { - fn from_inner(inner: FileDesc) -> PidFd { +impl FromInner<InnerPidFd> for PidFd { + fn from_inner(inner: InnerPidFd) -> PidFd { PidFd { inner } } } -impl IntoInner<FileDesc> for PidFd { - fn into_inner(self) -> FileDesc { +impl IntoInner<InnerPidFd> for PidFd { + fn into_inner(self) -> InnerPidFd { self.inner } } @@ -73,37 +108,37 @@ impl IntoInner<FileDesc> for PidFd { impl AsRawFd for PidFd { #[inline] fn as_raw_fd(&self) -> RawFd { - self.as_inner().as_raw_fd() + self.as_inner().as_inner().as_raw_fd() } } impl FromRawFd for PidFd { unsafe fn from_raw_fd(fd: RawFd) -> Self { - Self::from_inner(FileDesc::from_raw_fd(fd)) + Self::from_inner(InnerPidFd::from_raw_fd(fd)) } } impl IntoRawFd for PidFd { fn into_raw_fd(self) -> RawFd { - self.into_inner().into_raw_fd() + self.into_inner().into_inner().into_raw_fd() } } impl AsFd for PidFd { fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().as_fd() + self.as_inner().as_inner().as_fd() } } impl From<OwnedFd> for PidFd { fn from(fd: OwnedFd) -> Self { - Self::from_inner(FileDesc::from_inner(fd)) + Self::from_inner(InnerPidFd::from_inner(FileDesc::from_inner(fd))) } } impl From<PidFd> for OwnedFd { fn from(pid_fd: PidFd) -> Self { - pid_fd.into_inner().into_inner() + pid_fd.into_inner().into_inner().into_inner() } } @@ -124,18 +159,26 @@ pub trait ChildExt: Sealed { /// [`Child`]: process::Child fn pidfd(&self) -> Result<&PidFd>; - /// Takes ownership of the [`PidFd`] created for this [`Child`], if available. + /// Returns the [`PidFd`] created for this [`Child`], if available. + /// Otherwise self is returned. /// /// A pidfd will only be available if its creation was requested with /// [`create_pidfd`] when the corresponding [`Command`] was created. /// + /// Taking ownership of the PidFd consumes the Child to avoid pid reuse + /// races. Use [`pidfd`] and [`BorrowedFd::try_clone_to_owned`] if + /// you don't want to disassemble the Child yet. + /// /// Even if requested, a pidfd may not be available due to an older /// version of Linux being in use, or if some other error occurred. /// /// [`Command`]: process::Command /// [`create_pidfd`]: CommandExt::create_pidfd + /// [`pidfd`]: ChildExt::pidfd /// [`Child`]: process::Child - fn take_pidfd(&mut self) -> Result<PidFd>; + fn into_pidfd(self) -> crate::result::Result<PidFd, Self> + where + Self: Sized; } /// Os-specific extensions for [`Command`] @@ -146,7 +189,7 @@ pub trait CommandExt: Sealed { /// spawned by this [`Command`]. /// By default, no pidfd will be created. /// - /// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`]. + /// The pidfd can be retrieved from the child with [`pidfd`] or [`into_pidfd`]. /// /// A pidfd will only be created if it is possible to do so /// in a guaranteed race-free manner. Otherwise, [`pidfd`] will return an error. @@ -160,7 +203,7 @@ pub trait CommandExt: Sealed { /// [`Command`]: process::Command /// [`Child`]: process::Child /// [`pidfd`]: fn@ChildExt::pidfd - /// [`take_pidfd`]: ChildExt::take_pidfd + /// [`into_pidfd`]: ChildExt::into_pidfd fn create_pidfd(&mut self, val: bool) -> &mut process::Command; } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 7b8caaa2684..72073d13280 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2907,6 +2907,8 @@ impl Path { /// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios /// where those bugs are not an issue. /// + /// This is an alias for [`std::fs::exists`](crate::fs::exists). + /// /// # Examples /// /// ```no_run @@ -2919,7 +2921,7 @@ impl Path { #[stable(feature = "path_try_exists", since = "1.63.0")] #[inline] pub fn try_exists(&self) -> io::Result<bool> { - fs::try_exists(self) + fs::exists(self) } /// Returns `true` if the path exists on disk and is pointing at a regular file. diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index dfff4dd4fb0..96690f8c44e 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -1,5 +1,6 @@ -/// The underlying OsString/OsStr implementation on Windows is a -/// wrapper around the "WTF-8" encoding; see the `wtf8` module for more. +//! The underlying OsString/OsStr implementation on Windows is a +//! wrapper around the "WTF-8" encoding; see the `wtf8` module for more. + use crate::borrow::Cow; use crate::collections::TryReserveError; use crate::fmt; diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs index a98a1006ef4..e4e9eee044e 100644 --- a/library/std/src/sys/pal/hermit/fs.rs +++ b/library/std/src/sys/pal/hermit/fs.rs @@ -18,7 +18,7 @@ use crate::sys::time::SystemTime; use crate::sys::unsupported; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; -pub use crate::sys_common::fs::{copy, try_exists}; +pub use crate::sys_common::fs::{copy, exists}; #[derive(Debug)] pub struct File(FileDesc); diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs index 205226ce1da..a0c8217128f 100644 --- a/library/std/src/sys/pal/itron/thread.rs +++ b/library/std/src/sys/pal/itron/thread.rs @@ -1,5 +1,6 @@ //! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and //! `exd_tsk` are available. + use super::{ abi, error::{expect_success, expect_success_aborting, ItronError}, diff --git a/library/std/src/sys/pal/solid/abi/fs.rs b/library/std/src/sys/pal/solid/abi/fs.rs index 49526f4c9cd..75efaaac2a9 100644 --- a/library/std/src/sys/pal/solid/abi/fs.rs +++ b/library/std/src/sys/pal/solid/abi/fs.rs @@ -1,4 +1,5 @@ //! `solid_fs.h` + use crate::os::raw::{c_char, c_int, c_uchar}; pub use libc::{ ino_t, off_t, stat, time_t, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs index a6c1336109a..dc83e4f4b49 100644 --- a/library/std/src/sys/pal/solid/fs.rs +++ b/library/std/src/sys/pal/solid/fs.rs @@ -12,7 +12,7 @@ use crate::{ sys::unsupported, }; -pub use crate::sys_common::fs::try_exists; +pub use crate::sys_common::fs::exists; /// A file descriptor. #[derive(Clone, Copy)] diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 035c92bc84b..5c4ccd32850 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -97,7 +97,7 @@ use libc::{ ))] use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64}; -pub use crate::sys_common::fs::try_exists; +pub use crate::sys_common::fs::exists; pub struct File(FileDesc); diff --git a/library/std/src/sys/pal/unix/linux/mod.rs b/library/std/src/sys/pal/unix/linux/mod.rs new file mode 100644 index 00000000000..88aa1e3decc --- /dev/null +++ b/library/std/src/sys/pal/unix/linux/mod.rs @@ -0,0 +1 @@ +pub mod pidfd; diff --git a/library/std/src/sys/pal/unix/linux/pidfd.rs b/library/std/src/sys/pal/unix/linux/pidfd.rs new file mode 100644 index 00000000000..7474f80e94f --- /dev/null +++ b/library/std/src/sys/pal/unix/linux/pidfd.rs @@ -0,0 +1,76 @@ +use crate::io; +use crate::os::fd::{AsRawFd, FromRawFd, RawFd}; +use crate::sys::cvt; +use crate::sys::pal::unix::fd::FileDesc; +use crate::sys::process::ExitStatus; +use crate::sys_common::{AsInner, FromInner, IntoInner}; + +#[cfg(test)] +mod tests; + +#[derive(Debug)] +pub(crate) struct PidFd(FileDesc); + +impl PidFd { + pub fn kill(&self) -> io::Result<()> { + return cvt(unsafe { + libc::syscall( + libc::SYS_pidfd_send_signal, + self.0.as_raw_fd(), + libc::SIGKILL, + crate::ptr::null::<()>(), + 0, + ) + }) + .map(drop); + } + + pub fn wait(&self) -> io::Result<ExitStatus> { + let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; + cvt(unsafe { + libc::waitid(libc::P_PIDFD, self.0.as_raw_fd() as u32, &mut siginfo, libc::WEXITED) + })?; + return Ok(ExitStatus::from_waitid_siginfo(siginfo)); + } + + pub fn try_wait(&self) -> io::Result<Option<ExitStatus>> { + let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; + + cvt(unsafe { + libc::waitid( + libc::P_PIDFD, + self.0.as_raw_fd() as u32, + &mut siginfo, + libc::WEXITED | libc::WNOHANG, + ) + })?; + if unsafe { siginfo.si_pid() } == 0 { + return Ok(None); + } + return Ok(Some(ExitStatus::from_waitid_siginfo(siginfo))); + } +} + +impl AsInner<FileDesc> for PidFd { + fn as_inner(&self) -> &FileDesc { + &self.0 + } +} + +impl IntoInner<FileDesc> for PidFd { + fn into_inner(self) -> FileDesc { + self.0 + } +} + +impl FromInner<FileDesc> for PidFd { + fn from_inner(inner: FileDesc) -> Self { + Self(inner) + } +} + +impl FromRawFd for PidFd { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + Self(FileDesc::from_raw_fd(fd)) + } +} diff --git a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs new file mode 100644 index 00000000000..6d9532f2ef1 --- /dev/null +++ b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs @@ -0,0 +1,87 @@ +use crate::assert_matches::assert_matches; +use crate::os::fd::{AsRawFd, RawFd}; +use crate::os::linux::process::{ChildExt, CommandExt}; +use crate::os::unix::process::ExitStatusExt; +use crate::process::Command; + +#[test] +fn test_command_pidfd() { + let pidfd_open_available = probe_pidfd_support(); + + // always exercise creation attempts + let mut child = Command::new("false").create_pidfd(true).spawn().unwrap(); + + // but only check if we know that the kernel supports pidfds. + // We don't assert the precise value, since the standard library + // might have opened other file descriptors before our code runs. + if pidfd_open_available { + assert!(child.pidfd().is_ok()); + } + if let Ok(pidfd) = child.pidfd() { + let flags = super::cvt(unsafe { libc::fcntl(pidfd.as_raw_fd(), libc::F_GETFD) }).unwrap(); + assert!(flags & libc::FD_CLOEXEC != 0); + } + let status = child.wait().expect("error waiting on pidfd"); + assert_eq!(status.code(), Some(1)); + + let mut child = Command::new("sleep").arg("1000").create_pidfd(true).spawn().unwrap(); + assert_matches!(child.try_wait(), Ok(None)); + child.kill().expect("failed to kill child"); + let status = child.wait().expect("error waiting on pidfd"); + assert_eq!(status.signal(), Some(libc::SIGKILL)); + + let _ = Command::new("echo") + .create_pidfd(false) + .spawn() + .unwrap() + .pidfd() + .expect_err("pidfd should not have been created when create_pid(false) is set"); + + let _ = Command::new("echo") + .spawn() + .unwrap() + .pidfd() + .expect_err("pidfd should not have been created"); +} + +#[test] +fn test_pidfd() { + if !probe_pidfd_support() { + return; + } + + let child = Command::new("sleep") + .arg("1000") + .create_pidfd(true) + .spawn() + .expect("executing 'sleep' failed"); + + let fd = child.into_pidfd().unwrap(); + + assert_matches!(fd.try_wait(), Ok(None)); + fd.kill().expect("kill failed"); + fd.kill().expect("sending kill twice failed"); + let status = fd.wait().expect("1st wait failed"); + assert_eq!(status.signal(), Some(libc::SIGKILL)); + + // Trying to wait again for a reaped child is safe since there's no pid-recycling race. + // But doing so will return an error. + let res = fd.wait(); + assert_matches!(res, Err(e) if e.raw_os_error() == Some(libc::ECHILD)); + + // Ditto for additional attempts to kill an already-dead child. + let res = fd.kill(); + assert_matches!(res, Err(e) if e.raw_os_error() == Some(libc::ESRCH)); +} + +fn probe_pidfd_support() -> bool { + // pidfds require the pidfd_open syscall + let our_pid = crate::process::id(); + let pidfd = unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) }; + if pidfd >= 0 { + unsafe { libc::close(pidfd as RawFd) }; + true + } else { + false + } +} diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 735ed96bc7b..b370f06e92b 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -20,6 +20,8 @@ pub mod io; pub mod kernel_copy; #[cfg(target_os = "l4re")] mod l4re; +#[cfg(target_os = "linux")] +pub mod linux; #[cfg(not(target_os = "l4re"))] pub mod net; #[cfg(target_os = "l4re")] diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 72bda90a9ba..32382d9a50c 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -7,9 +7,7 @@ use crate::sys::cvt; use crate::sys::process::process_common::*; #[cfg(target_os = "linux")] -use crate::os::linux::process::PidFd; -#[cfg(target_os = "linux")] -use crate::os::unix::io::AsRawFd; +use crate::sys::pal::unix::linux::pidfd::PidFd; #[cfg(target_os = "vxworks")] use libc::RTP_ID as pid_t; @@ -815,16 +813,7 @@ impl Process { #[cfg(target_os = "linux")] if let Some(pid_fd) = self.pidfd.as_ref() { // pidfd_send_signal predates pidfd_open. so if we were able to get an fd then sending signals will work too - return cvt(unsafe { - libc::syscall( - libc::SYS_pidfd_send_signal, - pid_fd.as_raw_fd(), - libc::SIGKILL, - crate::ptr::null::<()>(), - 0, - ) - }) - .map(drop); + return pid_fd.kill(); } cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop) } @@ -836,12 +825,7 @@ impl Process { } #[cfg(target_os = "linux")] if let Some(pid_fd) = self.pidfd.as_ref() { - let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; - - cvt_r(|| unsafe { - libc::waitid(libc::P_PIDFD, pid_fd.as_raw_fd() as u32, &mut siginfo, libc::WEXITED) - })?; - let status = ExitStatus::from_waitid_siginfo(siginfo); + let status = pid_fd.wait()?; self.status = Some(status); return Ok(status); } @@ -857,22 +841,11 @@ impl Process { } #[cfg(target_os = "linux")] if let Some(pid_fd) = self.pidfd.as_ref() { - let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; - - cvt(unsafe { - libc::waitid( - libc::P_PIDFD, - pid_fd.as_raw_fd() as u32, - &mut siginfo, - libc::WEXITED | libc::WNOHANG, - ) - })?; - if unsafe { siginfo.si_pid() } == 0 { - return Ok(None); + let status = pid_fd.try_wait()?; + if let Some(status) = status { + self.status = Some(status) } - let status = ExitStatus::from_waitid_siginfo(siginfo); - self.status = Some(status); - return Ok(Some(status)); + return Ok(status); } let mut status = 0 as c_int; let pid = cvt(unsafe { libc::waitpid(self.pid, &mut status, libc::WNOHANG) })?; @@ -1105,20 +1078,33 @@ impl ExitStatusError { } #[cfg(target_os = "linux")] -#[unstable(feature = "linux_pidfd", issue = "82971")] -impl crate::os::linux::process::ChildExt for crate::process::Child { - fn pidfd(&self) -> io::Result<&PidFd> { - self.handle - .pidfd - .as_ref() - .ok_or_else(|| Error::new(ErrorKind::Uncategorized, "No pidfd was created.")) - } +mod linux_child_ext { + + use crate::io; + use crate::mem; + use crate::os::linux::process as os; + use crate::sys::pal::unix::linux::pidfd as imp; + use crate::sys::pal::unix::ErrorKind; + use crate::sys_common::FromInner; + + #[unstable(feature = "linux_pidfd", issue = "82971")] + impl crate::os::linux::process::ChildExt for crate::process::Child { + fn pidfd(&self) -> io::Result<&os::PidFd> { + self.handle + .pidfd + .as_ref() + // SAFETY: The os type is a transparent wrapper, therefore we can transmute references + .map(|fd| unsafe { mem::transmute::<&imp::PidFd, &os::PidFd>(fd) }) + .ok_or_else(|| io::Error::new(ErrorKind::Uncategorized, "No pidfd was created.")) + } - fn take_pidfd(&mut self) -> io::Result<PidFd> { - self.handle - .pidfd - .take() - .ok_or_else(|| Error::new(ErrorKind::Uncategorized, "No pidfd was created.")) + fn into_pidfd(mut self) -> Result<os::PidFd, Self> { + self.handle + .pidfd + .take() + .map(|fd| <os::PidFd as FromInner<imp::PidFd>>::from_inner(fd)) + .ok_or_else(|| self) + } } } diff --git a/library/std/src/sys/pal/unix/process/process_unix/tests.rs b/library/std/src/sys/pal/unix/process/process_unix/tests.rs index 0a6c6ec19fc..e5e1f956bc3 100644 --- a/library/std/src/sys/pal/unix/process/process_unix/tests.rs +++ b/library/std/src/sys/pal/unix/process/process_unix/tests.rs @@ -60,57 +60,3 @@ fn test_command_fork_no_unwind() { || signal == libc::SIGSEGV ); } - -#[test] -#[cfg(target_os = "linux")] // pidfds are a linux-specific concept -fn test_command_pidfd() { - use crate::assert_matches::assert_matches; - use crate::os::fd::{AsRawFd, RawFd}; - use crate::os::linux::process::{ChildExt, CommandExt}; - use crate::process::Command; - - // pidfds require the pidfd_open syscall - let our_pid = crate::process::id(); - let pidfd = unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) }; - let pidfd_open_available = if pidfd >= 0 { - unsafe { libc::close(pidfd as RawFd) }; - true - } else { - false - }; - - // always exercise creation attempts - let mut child = Command::new("false").create_pidfd(true).spawn().unwrap(); - - // but only check if we know that the kernel supports pidfds. - // We don't assert the precise value, since the standard library - // might have opened other file descriptors before our code runs. - if pidfd_open_available { - assert!(child.pidfd().is_ok()); - } - if let Ok(pidfd) = child.pidfd() { - let flags = super::cvt(unsafe { libc::fcntl(pidfd.as_raw_fd(), libc::F_GETFD) }).unwrap(); - assert!(flags & libc::FD_CLOEXEC != 0); - } - let status = child.wait().expect("error waiting on pidfd"); - assert_eq!(status.code(), Some(1)); - - let mut child = Command::new("sleep").arg("1000").create_pidfd(true).spawn().unwrap(); - assert_matches!(child.try_wait(), Ok(None)); - child.kill().expect("failed to kill child"); - let status = child.wait().expect("error waiting on pidfd"); - assert_eq!(status.signal(), Some(libc::SIGKILL)); - - let _ = Command::new("echo") - .create_pidfd(false) - .spawn() - .unwrap() - .pidfd() - .expect_err("pidfd should not have been created when create_pid(false) is set"); - - let _ = Command::new("echo") - .spawn() - .unwrap() - .pidfd() - .expect_err("pidfd should not have been created"); -} diff --git a/library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs b/library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs index e6dfadcf4a4..973188b1f2b 100644 --- a/library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs +++ b/library/std/src/sys/pal/unix/process/process_unsupported/wait_status.rs @@ -1,6 +1,7 @@ //! Emulated wait status for non-Unix #[cfg(unix) platforms //! //! Separate module to facilitate testing against a real Unix implementation. + use crate::ffi::c_int; use crate::fmt; use crate::num::NonZero; diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 1ab54ec57c3..619f4e4121e 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -475,9 +475,10 @@ mod cgroups { //! * cgroup v2 in non-standard mountpoints //! * paths containing control characters or spaces, since those would be escaped in procfs //! output and we don't unescape + use crate::borrow::Cow; use crate::ffi::OsString; - use crate::fs::{try_exists, File}; + use crate::fs::{exists, File}; use crate::io::Read; use crate::io::{BufRead, BufReader}; use crate::os::unix::ffi::OsStringExt; @@ -555,7 +556,7 @@ mod cgroups { path.push("cgroup.controllers"); // skip if we're not looking at cgroup2 - if matches!(try_exists(&path), Err(_) | Ok(false)) { + if matches!(exists(&path), Err(_) | Ok(false)) { return usize::MAX; }; @@ -612,7 +613,7 @@ mod cgroups { path.push(&group_path); // skip if we guessed the mount incorrectly - if matches!(try_exists(&path), Err(_) | Ok(false)) { + if matches!(exists(&path), Err(_) | Ok(false)) { continue; } diff --git a/library/std/src/sys/pal/unsupported/fs.rs b/library/std/src/sys/pal/unsupported/fs.rs index 6ac1b5d2bcf..474c9fe97d1 100644 --- a/library/std/src/sys/pal/unsupported/fs.rs +++ b/library/std/src/sys/pal/unsupported/fs.rs @@ -291,7 +291,7 @@ pub fn remove_dir_all(_path: &Path) -> io::Result<()> { unsupported() } -pub fn try_exists(_path: &Path) -> io::Result<bool> { +pub fn exists(_path: &Path) -> io::Result<bool> { unsupported() } diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index 529b82e0198..c58e6a08b37 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -17,7 +17,7 @@ use crate::sys::time::SystemTime; use crate::sys::unsupported; use crate::sys_common::{AsInner, FromInner, IntoInner}; -pub use crate::sys_common::fs::try_exists; +pub use crate::sys_common::fs::exists; pub struct File { fd: WasiFd, diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 629ff114b5a..cc68f5ef5f0 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1531,7 +1531,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { } // Try to see if a file exists but, unlike `exists`, report I/O errors. -pub fn try_exists(path: &Path) -> io::Result<bool> { +pub fn exists(path: &Path) -> io::Result<bool> { // Open the file to ensure any symlinks are followed to their target. let mut opts = OpenOptions::new(); // No read, write, etc access rights are needed. diff --git a/library/std/src/sys/sync/condvar/itron.rs b/library/std/src/sys/sync/condvar/itron.rs index 9b64d241efd..3a3039889e9 100644 --- a/library/std/src/sys/sync/condvar/itron.rs +++ b/library/std/src/sys/sync/condvar/itron.rs @@ -1,4 +1,5 @@ //! POSIX conditional variable implementation based on user-space wait queues. + use crate::sys::pal::itron::{ abi, error::expect_success_aborting, spin::SpinMutex, task, time::with_tmos_strong, }; diff --git a/library/std/src/sys/sync/mutex/itron.rs b/library/std/src/sys/sync/mutex/itron.rs index a134eb2d1be..4ba32a8fbcd 100644 --- a/library/std/src/sys/sync/mutex/itron.rs +++ b/library/std/src/sys/sync/mutex/itron.rs @@ -1,5 +1,6 @@ //! Mutex implementation backed by μITRON mutexes. Assumes `acre_mtx` and //! `TA_INHERIT` are available. + use crate::sys::pal::itron::{ abi, error::{expect_success, expect_success_aborting, fail, ItronError}, diff --git a/library/std/src/sys/sync/rwlock/solid.rs b/library/std/src/sys/sync/rwlock/solid.rs index 9bf6f5dbb73..7558eee8edd 100644 --- a/library/std/src/sys/sync/rwlock/solid.rs +++ b/library/std/src/sys/sync/rwlock/solid.rs @@ -1,4 +1,5 @@ //! A readers-writer lock implementation backed by the SOLID kernel extension. + use crate::sys::pal::{ abi, itron::{ diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys_common/fs.rs index 617ac52e51c..acb6713cf1b 100644 --- a/library/std/src/sys_common/fs.rs +++ b/library/std/src/sys_common/fs.rs @@ -42,7 +42,7 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { fs::remove_dir(path) } -pub fn try_exists(path: &Path) -> io::Result<bool> { +pub fn exists(path: &Path) -> io::Result<bool> { match fs::metadata(path) { Ok(_) => Ok(true), Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false), diff --git a/library/std/tests/create_dir_all_bare.rs b/library/std/tests/create_dir_all_bare.rs index fd2a7f906f8..79c3c8f528e 100644 --- a/library/std/tests/create_dir_all_bare.rs +++ b/library/std/tests/create_dir_all_bare.rs @@ -2,6 +2,7 @@ //! Note that this test changes the current directory so //! should not be in the same process as other tests. + use std::env; use std::fs; use std::path::{Path, PathBuf}; diff --git a/library/test/src/bench.rs b/library/test/src/bench.rs index 64ca13c0d4e..9f34f54c3d6 100644 --- a/library/test/src/bench.rs +++ b/library/test/src/bench.rs @@ -1,4 +1,5 @@ //! Benchmarking module. + use super::{ event::CompletedTest, options::BenchMode, diff --git a/library/test/src/helpers/concurrency.rs b/library/test/src/helpers/concurrency.rs index b395adcf885..1854c6a7652 100644 --- a/library/test/src/helpers/concurrency.rs +++ b/library/test/src/helpers/concurrency.rs @@ -1,5 +1,6 @@ //! Helper module which helps to determine amount of threads to be used //! during tests execution. + use std::{env, num::NonZero, thread}; pub fn get_concurrency() -> usize { diff --git a/library/test/src/helpers/metrics.rs b/library/test/src/helpers/metrics.rs index f77a23e6875..bc38969cefb 100644 --- a/library/test/src/helpers/metrics.rs +++ b/library/test/src/helpers/metrics.rs @@ -1,4 +1,5 @@ //! Benchmark metrics. + use std::collections::BTreeMap; #[derive(Clone, PartialEq, Debug, Copy)] diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 544d9fbf1ae..45a1c334a44 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -2,7 +2,7 @@ #![unstable(feature = "panic_unwind", issue = "32837")] #![feature(link_cfg)] #![feature(staged_api)] -#![feature(c_unwind)] +#![cfg_attr(bootstrap, feature(c_unwind))] #![feature(strict_provenance)] #![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))] #![cfg_attr(not(target_env = "msvc"), feature(libc))] diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 54136d2aebd..4fb64595504 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -665,6 +665,10 @@ impl Step for Std { } } +/// Tarball containing the compiler that gets downloaded and used by +/// `rust.download-rustc`. +/// +/// (Don't confuse this with [`RustDev`], without the `c`!) #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct RustcDev { pub compiler: Compiler, @@ -2225,6 +2229,11 @@ impl Step for LlvmBitcodeLinker { /// Tarball intended for internal consumption to ease rustc/std development. /// /// Should not be considered stable by end users. +/// +/// In practice, this is the tarball that gets downloaded and used by +/// `llvm.download-ci-llvm`. +/// +/// (Don't confuse this with [`RustcDev`], with a `c`!) #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct RustDev { pub target: TargetSelection, diff --git a/src/bootstrap/src/core/build_steps/mod.rs b/src/bootstrap/src/core/build_steps/mod.rs index 381ee7ef53b..004174e35e1 100644 --- a/src/bootstrap/src/core/build_steps/mod.rs +++ b/src/bootstrap/src/core/build_steps/mod.rs @@ -7,6 +7,7 @@ pub(crate) mod doc; pub(crate) mod format; pub(crate) mod install; pub(crate) mod llvm; +pub(crate) mod perf; pub(crate) mod run; pub(crate) mod setup; pub(crate) mod suggest; diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs new file mode 100644 index 00000000000..9d70ca6bd71 --- /dev/null +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -0,0 +1,45 @@ +use std::process::Command; + +use crate::core::build_steps::compile::{Std, Sysroot}; +use crate::core::build_steps::tool::RustcPerf; +use crate::core::builder::Builder; +use crate::core::config::DebuginfoLevel; + +/// Performs profiling using `rustc-perf` on a built version of the compiler. +pub fn perf(builder: &Builder<'_>) { + let collector = builder.ensure(RustcPerf { + compiler: builder.compiler(0, builder.config.build), + target: builder.config.build, + }); + + if builder.build.config.rust_debuginfo_level_rustc == DebuginfoLevel::None { + builder.info(r#"WARNING: You are compiling rustc without debuginfo, this will make profiling less useful. +Consider setting `rust.debuginfo-level = 1` in `config.toml`."#); + } + + let compiler = builder.compiler(builder.top_stage, builder.config.build); + builder.ensure(Std::new(compiler, builder.config.build)); + let sysroot = builder.ensure(Sysroot::new(compiler)); + let rustc = sysroot.join("bin/rustc"); + + let results_dir = builder.build.tempdir().join("rustc-perf"); + + let mut cmd = Command::new(collector); + let cmd = cmd + .arg("profile_local") + .arg("eprintln") + .arg("--out-dir") + .arg(&results_dir) + .arg("--include") + .arg("helloworld") + .arg(&rustc); + + builder.info(&format!("Running `rustc-perf` using `{}`", rustc.display())); + + // We need to set the working directory to `src/tools/perf`, so that it can find the directory + // with compile-time benchmarks. + let cmd = cmd.current_dir(builder.src.join("src/tools/rustc-perf")); + builder.build.run(cmd); + + builder.info(&format!("You can find the results at `{}`", results_dir.display())); +} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 445096e9786..8a2bc3b9d48 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -26,7 +26,7 @@ use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::flags::get_completion; use crate::core::config::flags::Subcommand; use crate::core::config::TargetSelection; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::{BootstrapCommand, OutputMode}; use crate::utils::helpers::{ self, add_link_lib_path, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var, linker_args, linker_flags, output, t, target_supports_cranelift_backend, up_to_date, @@ -156,7 +156,10 @@ You can skip linkcheck with --skip src/tools/linkchecker" let _guard = builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host); let _time = helpers::timeit(builder); - builder.run_delaying_failure(linkchecker.arg(builder.out.join(host.triple).join("doc"))); + builder.run_tracked( + BootstrapCommand::from(linkchecker.arg(builder.out.join(host.triple).join("doc"))) + .delay_failure(), + ); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -201,7 +204,7 @@ impl Step for HtmlCheck { if !check_if_tidy_is_installed() { eprintln!("not running HTML-check tool because `tidy` is missing"); eprintln!( - "Note that `tidy` is not the in-tree `src/tools/tidy` but needs to be installed" + "You need the HTML tidy tool https://www.html-tidy.org/, this tool is *not* part of the rust project and needs to be installed separately, for example via your package manager." ); panic!("Cannot run html-check tests"); } @@ -213,8 +216,11 @@ impl Step for HtmlCheck { builder, )); - builder.run_delaying_failure( - builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)), + builder.run_tracked( + BootstrapCommand::from( + builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)), + ) + .delay_failure(), ); } } @@ -261,7 +267,7 @@ impl Step for Cargotest { .env("RUSTC", builder.rustc(compiler)) .env("RUSTDOC", builder.rustdoc(compiler)); add_rustdoc_cargo_linker_args(cmd, builder, compiler.host, LldThreads::No); - builder.run_delaying_failure(cmd); + builder.run_tracked(BootstrapCommand::from(cmd).delay_failure()); } } @@ -813,7 +819,7 @@ impl Step for RustdocTheme { .env("RUSTC_BOOTSTRAP", "1"); cmd.args(linker_args(builder, self.compiler.host, LldThreads::No)); - builder.run_delaying_failure(&mut cmd); + builder.run_tracked(BootstrapCommand::from(&mut cmd).delay_failure()); } } @@ -1093,7 +1099,7 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to } builder.info("tidy check"); - builder.run_delaying_failure(&mut cmd); + builder.run_tracked(BootstrapCommand::from(&mut cmd).delay_failure()); builder.info("x.py completions check"); let [bash, zsh, fish, powershell] = ["x.py.sh", "x.py.zsh", "x.py.fish", "x.py.ps1"] @@ -2179,7 +2185,8 @@ impl BookTest { compiler.host, ); let _time = helpers::timeit(builder); - let toolstate = if builder.run_delaying_failure(&mut rustbook_cmd) { + let cmd = BootstrapCommand::from(&mut rustbook_cmd).delay_failure(); + let toolstate = if builder.run_tracked(cmd).is_success() { ToolState::TestPass } else { ToolState::TestFail @@ -2312,7 +2319,8 @@ impl Step for ErrorIndex { let guard = builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host); let _time = helpers::timeit(builder); - builder.run_quiet(&mut tool); + builder + .run_tracked(BootstrapCommand::from(&mut tool).output_mode(OutputMode::OnlyOnFailure)); drop(guard); // The tests themselves need to link to std, so make sure it is // available. @@ -2341,11 +2349,11 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> let test_args = builder.config.test_args().join(" "); cmd.arg("--test-args").arg(test_args); - if builder.config.verbose_tests { - builder.run_delaying_failure(&mut cmd) - } else { - builder.run_quiet_delaying_failure(&mut cmd) + let mut cmd = BootstrapCommand::from(&mut cmd).delay_failure(); + if !builder.config.verbose_tests { + cmd = cmd.quiet(); } + builder.run_tracked(cmd).is_success() } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -2370,7 +2378,8 @@ impl Step for RustcGuide { let src = builder.src.join(relative_path); let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); - let toolstate = if builder.run_delaying_failure(rustbook_cmd.arg("linkcheck").arg(&src)) { + let cmd = BootstrapCommand::from(rustbook_cmd.arg("linkcheck").arg(&src)).delay_failure(); + let toolstate = if builder.run_tracked(cmd).is_success() { ToolState::TestPass } else { ToolState::TestFail @@ -2984,7 +2993,7 @@ impl Step for Bootstrap { .current_dir(builder.src.join("src/bootstrap/")); // NOTE: we intentionally don't pass test_args here because the args for unittest and cargo test are mutually incompatible. // Use `python -m unittest` manually if you want to pass arguments. - builder.run_delaying_failure(&mut check_bootstrap); + builder.run_tracked(BootstrapCommand::from(&mut check_bootstrap).delay_failure()); let mut cmd = Command::new(&builder.initial_cargo); cmd.arg("test") @@ -3061,7 +3070,7 @@ impl Step for TierCheck { self.compiler.host, self.compiler.host, ); - builder.run_delaying_failure(&mut cargo.into()); + builder.run_tracked(BootstrapCommand::from(&mut cargo.into()).delay_failure()); } } @@ -3147,7 +3156,7 @@ impl Step for RustInstaller { cmd.env("CARGO", &builder.initial_cargo); cmd.env("RUSTC", &builder.initial_rustc); cmd.env("TMP_DIR", &tmpdir); - builder.run_delaying_failure(&mut cmd); + builder.run_tracked(BootstrapCommand::from(&mut cmd).delay_failure()); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 613484788b6..850c8bfe2f8 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -32,6 +32,8 @@ struct ToolBuild { extra_features: Vec<String>, /// Nightly-only features that are allowed (comma-separated list). allow_features: &'static str, + /// Additional arguments to pass to the `cargo` invocation. + cargo_args: Vec<String>, } impl Builder<'_> { @@ -100,6 +102,7 @@ impl Step for ToolBuild { if !self.allow_features.is_empty() { cargo.allow_features(self.allow_features); } + cargo.args(self.cargo_args); let _guard = builder.msg_tool( Kind::Build, self.mode, @@ -126,10 +129,7 @@ impl Step for ToolBuild { if tool == "tidy" { tool = "rust-tidy"; } - let cargo_out = builder.cargo_out(compiler, self.mode, target).join(exe(tool, target)); - let bin = builder.tools_dir(compiler).join(exe(tool, target)); - builder.copy_link(&cargo_out, &bin); - bin + copy_link_tool_bin(builder, self.compiler, self.target, self.mode, tool) } } } @@ -214,6 +214,21 @@ pub fn prepare_tool_cargo( cargo } +/// Links a built tool binary with the given `name` from the build directory to the +/// tools directory. +fn copy_link_tool_bin( + builder: &Builder<'_>, + compiler: Compiler, + target: TargetSelection, + mode: Mode, + name: &str, +) -> PathBuf { + let cargo_out = builder.cargo_out(compiler, mode, target).join(exe(name, target)); + let bin = builder.tools_dir(compiler).join(exe(name, target)); + builder.copy_link(&cargo_out, &bin); + bin +} + macro_rules! bootstrap_tool { ($( $name:ident, $path:expr, $tool_name:expr @@ -283,6 +298,7 @@ macro_rules! bootstrap_tool { }, extra_features: vec![], allow_features: concat!($($allow_features)*), + cargo_args: vec![] }) } } @@ -349,10 +365,60 @@ impl Step for OptimizedDist { source_type: SourceType::InTree, extra_features: Vec::new(), allow_features: "", + cargo_args: Vec::new(), }) } } +/// The [rustc-perf](https://github.com/rust-lang/rustc-perf) benchmark suite, which is added +/// as a submodule at `src/tools/rustc-perf`. +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct RustcPerf { + pub compiler: Compiler, + pub target: TargetSelection, +} + +impl Step for RustcPerf { + /// Path to the built `collector` binary. + type Output = PathBuf; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/rustc-perf") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(RustcPerf { + compiler: run.builder.compiler(0, run.builder.config.build), + target: run.target, + }); + } + + fn run(self, builder: &Builder<'_>) -> PathBuf { + // We need to ensure the rustc-perf submodule is initialized. + builder.update_submodule(Path::new("src/tools/rustc-perf")); + + let tool = ToolBuild { + compiler: self.compiler, + target: self.target, + tool: "collector", + mode: Mode::ToolBootstrap, + path: "src/tools/rustc-perf", + source_type: SourceType::Submodule, + extra_features: Vec::new(), + allow_features: "", + // Only build the collector package, which is used for benchmarking through + // a CLI. + cargo_args: vec!["-p".to_string(), "collector".to_string()], + }; + let collector_bin = builder.ensure(tool.clone()); + // We also need to symlink the `rustc-fake` binary to the corresponding directory, + // because `collector` expects it in the same directory. + copy_link_tool_bin(builder, tool.compiler, tool.target, tool.mode, "rustc-fake"); + + collector_bin + } +} + #[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] pub struct ErrorIndex { pub compiler: Compiler, @@ -403,6 +469,7 @@ impl Step for ErrorIndex { source_type: SourceType::InTree, extra_features: Vec::new(), allow_features: "", + cargo_args: Vec::new(), }) } } @@ -437,6 +504,7 @@ impl Step for RemoteTestServer { source_type: SourceType::InTree, extra_features: Vec::new(), allow_features: "", + cargo_args: Vec::new(), }) } } @@ -595,6 +663,7 @@ impl Step for Cargo { source_type: SourceType::Submodule, extra_features: Vec::new(), allow_features: "", + cargo_args: Vec::new(), }) } } @@ -622,6 +691,7 @@ impl Step for LldWrapper { source_type: SourceType::InTree, extra_features: Vec::new(), allow_features: "", + cargo_args: Vec::new(), }) } } @@ -670,6 +740,7 @@ impl Step for RustAnalyzer { extra_features: vec!["in-rust-tree".to_owned()], source_type: SourceType::InTree, allow_features: RustAnalyzer::ALLOW_FEATURES, + cargo_args: Vec::new(), }) } } @@ -717,6 +788,7 @@ impl Step for RustAnalyzerProcMacroSrv { extra_features: vec!["in-rust-tree".to_owned()], source_type: SourceType::InTree, allow_features: RustAnalyzer::ALLOW_FEATURES, + cargo_args: Vec::new(), }); // Copy `rust-analyzer-proc-macro-srv` to `<sysroot>/libexec/` @@ -923,6 +995,7 @@ macro_rules! tool_extended { extra_features: $sel.extra_features, source_type: SourceType::InTree, allow_features: concat!($($allow_features)*), + cargo_args: vec![] }); if (false $(|| !$add_bins_to_sysroot.is_empty())?) && $sel.compiler.stage > 0 { diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 3c4806a1311..2e9c04624c7 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -274,7 +274,7 @@ impl PathSet { /// This is used for `StepDescription::krate`, which passes all matching crates at once to /// `Step::make_run`, rather than calling it many times with a single crate. /// See `tests.rs` for examples. - fn intersection_removing_matches(&self, needles: &mut Vec<&Path>, module: Kind) -> PathSet { + fn intersection_removing_matches(&self, needles: &mut Vec<PathBuf>, module: Kind) -> PathSet { let mut check = |p| { for (i, n) in needles.iter().enumerate() { let matched = Self::check(p, n, module); @@ -346,7 +346,7 @@ const PATH_REMAP: &[(&str, &[&str])] = &[ ), ]; -fn remap_paths(paths: &mut Vec<&Path>) { +fn remap_paths(paths: &mut Vec<PathBuf>) { let mut remove = vec![]; let mut add = vec![]; for (i, path) in paths.iter().enumerate().filter_map(|(i, path)| path.to_str().map(|s| (i, s))) @@ -355,7 +355,7 @@ fn remap_paths(paths: &mut Vec<&Path>) { // Remove leading and trailing slashes so `tests/` and `tests` are equivalent if path.trim_matches(std::path::is_separator) == search { remove.push(i); - add.extend(replace.iter().map(Path::new)); + add.extend(replace.iter().map(PathBuf::from)); break; } } @@ -438,8 +438,25 @@ impl StepDescription { } } - // strip CurDir prefix if present - let mut paths: Vec<_> = paths.iter().map(|p| p.strip_prefix(".").unwrap_or(p)).collect(); + // Attempt to resolve paths to be relative to the builder source directory. + let mut paths: Vec<PathBuf> = paths + .iter() + .map(|p| { + // If the path does not exist, it may represent the name of a Step, such as `tidy` in `x test tidy` + if !p.exists() { + return p.clone(); + } + + // Make the path absolute, strip the prefix, and convert to a PathBuf. + match std::path::absolute(p) { + Ok(p) => p.strip_prefix(&builder.src).unwrap_or(&p).to_path_buf(), + Err(e) => { + eprintln!("ERROR: {:?}", e); + panic!("Due to the above error, failed to resolve path: {:?}", p); + } + } + }) + .collect(); remap_paths(&mut paths); @@ -629,7 +646,7 @@ impl<'a> ShouldRun<'a> { /// (for now, just `all_krates` and `paths`, but we may want to add an `aliases` function in the future?) fn pathset_for_paths_removing_matches( &self, - paths: &mut Vec<&Path>, + paths: &mut Vec<PathBuf>, kind: Kind, ) -> Vec<PathSet> { let mut sets = vec![]; @@ -666,6 +683,7 @@ pub enum Kind { Setup, Suggest, Vendor, + Perf, } impl Kind { @@ -687,6 +705,7 @@ impl Kind { Kind::Setup => "setup", Kind::Suggest => "suggest", Kind::Vendor => "vendor", + Kind::Perf => "perf", } } @@ -698,6 +717,7 @@ impl Kind { Kind::Run => "Running", Kind::Suggest => "Suggesting", Kind::Clippy => "Linting", + Kind::Perf => "Profiling & benchmarking", _ => { let title_letter = self.as_str()[0..1].to_ascii_uppercase(); return format!("{title_letter}{}ing", &self.as_str()[1..]); @@ -749,7 +769,8 @@ impl<'a> Builder<'a> { tool::RustdocGUITest, tool::OptimizedDist, tool::CoverageDump, - tool::LlvmBitcodeLinker + tool::LlvmBitcodeLinker, + tool::RustcPerf, ), Kind::Clippy => describe!( clippy::Std, @@ -945,7 +966,7 @@ impl<'a> Builder<'a> { Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), Kind::Vendor => describe!(vendor::Vendor), // special-cased in Build::build() - Kind::Format | Kind::Suggest => vec![], + Kind::Format | Kind::Suggest | Kind::Perf => vec![], } } @@ -1017,6 +1038,7 @@ impl<'a> Builder<'a> { path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)), ), Subcommand::Vendor { .. } => (Kind::Vendor, &paths[..]), + Subcommand::Perf { .. } => (Kind::Perf, &paths[..]), }; Self::new_internal(build, kind, paths.to_owned()) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 276fd0b11d6..aa119b8c699 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -122,11 +122,14 @@ fn test_intersection() { PathSet::Set(paths.into_iter().map(|p| TaskPath { path: p.into(), kind: None }).collect()) }; let library_set = set(&["library/core", "library/alloc", "library/std"]); - let mut command_paths = - vec![Path::new("library/core"), Path::new("library/alloc"), Path::new("library/stdarch")]; + let mut command_paths = vec![ + PathBuf::from("library/core"), + PathBuf::from("library/alloc"), + PathBuf::from("library/stdarch"), + ]; let subset = library_set.intersection_removing_matches(&mut command_paths, Kind::Build); assert_eq!(subset, set(&["library/core", "library/alloc"]),); - assert_eq!(command_paths, vec![Path::new("library/stdarch")]); + assert_eq!(command_paths, vec![PathBuf::from("library/stdarch")]); } #[test] diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 0438dee7241..948f97e746f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2043,6 +2043,7 @@ impl Config { Subcommand::Bench { .. } => flags.stage.or(bench_stage).unwrap_or(2), Subcommand::Dist { .. } => flags.stage.or(dist_stage).unwrap_or(2), Subcommand::Install { .. } => flags.stage.or(install_stage).unwrap_or(2), + Subcommand::Perf { .. } => flags.stage.unwrap_or(1), // These are all bootstrap tools, which don't depend on the compiler. // The stage we pass shouldn't matter, but use 0 just in case. Subcommand::Clean { .. } @@ -2080,7 +2081,8 @@ impl Config { | Subcommand::Setup { .. } | Subcommand::Format { .. } | Subcommand::Suggest { .. } - | Subcommand::Vendor { .. } => {} + | Subcommand::Vendor { .. } + | Subcommand::Perf { .. } => {} } } diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 83def0c6df0..eb5152a3831 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -469,6 +469,9 @@ Arguments: #[arg(long)] versioned_dirs: bool, }, + /// Perform profiling and benchmarking of the compiler using the + /// `rustc-perf` benchmark suite. + Perf {}, } impl Subcommand { @@ -490,6 +493,7 @@ impl Subcommand { Subcommand::Setup { .. } => Kind::Setup, Subcommand::Suggest { .. } => Kind::Suggest, Subcommand::Vendor { .. } => Kind::Vendor, + Subcommand::Perf { .. } => Kind::Perf, } } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 449d8c128ec..dfc30298c28 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -23,7 +23,7 @@ use std::fmt::Display; use std::fs::{self, File}; use std::io; use std::path::{Path, PathBuf}; -use std::process::{Command, Output, Stdio}; +use std::process::{Command, Stdio}; use std::str; use std::sync::OnceLock; @@ -41,7 +41,7 @@ use crate::core::builder::Kind; use crate::core::config::{flags, LldMode}; use crate::core::config::{DryRun, Target}; use crate::core::config::{LlvmLibunwind, TargetSelection}; -use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, OutputMode}; +use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode}; use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, symlink_dir}; mod core; @@ -585,8 +585,8 @@ impl Build { BootstrapCommand::from(submodule_git().args(["diff-index", "--quiet", "HEAD"])) .allow_failure() .output_mode(match self.is_verbose() { - true => OutputMode::PrintAll, - false => OutputMode::PrintOutput, + true => OutputMode::All, + false => OutputMode::OnlyOutput, }), ); if has_local_modifications { @@ -659,6 +659,9 @@ impl Build { Subcommand::Suggest { run } => { return core::build_steps::suggest::suggest(&builder::Builder::new(self), *run); } + Subcommand::Perf { .. } => { + return core::build_steps::perf::perf(&builder::Builder::new(self)); + } _ => (), } @@ -958,73 +961,36 @@ impl Build { }) } - /// Runs a command, printing out nice contextual information if it fails. - fn run(&self, cmd: &mut Command) { - self.run_cmd(BootstrapCommand::from(cmd).fail_fast().output_mode( - match self.is_verbose() { - true => OutputMode::PrintAll, - false => OutputMode::PrintOutput, - }, - )); - } - - /// Runs a command, printing out contextual info if it fails, and delaying errors until the build finishes. - pub(crate) fn run_delaying_failure(&self, cmd: &mut Command) -> bool { - self.run_cmd(BootstrapCommand::from(cmd).delay_failure().output_mode( - match self.is_verbose() { - true => OutputMode::PrintAll, - false => OutputMode::PrintOutput, - }, - )) - } - - /// Runs a command, printing out nice contextual information if it fails. - fn run_quiet(&self, cmd: &mut Command) { - self.run_cmd( - BootstrapCommand::from(cmd).fail_fast().output_mode(OutputMode::SuppressOnSuccess), - ); - } - - /// Runs a command, printing out nice contextual information if it fails. - /// Exits if the command failed to execute at all, otherwise returns its - /// `status.success()`. - fn run_quiet_delaying_failure(&self, cmd: &mut Command) -> bool { - self.run_cmd( - BootstrapCommand::from(cmd).delay_failure().output_mode(OutputMode::SuppressOnSuccess), - ) - } - - /// A centralized function for running commands that do not return output. - pub(crate) fn run_cmd<'a, C: Into<BootstrapCommand<'a>>>(&self, cmd: C) -> bool { + /// Execute a command and return its output. + fn run_tracked(&self, command: BootstrapCommand<'_>) -> CommandOutput { if self.config.dry_run() { - return true; + return CommandOutput::default(); } - let command = cmd.into(); self.verbose(|| println!("running: {command:?}")); - let (output, print_error) = match command.output_mode { - mode @ (OutputMode::PrintAll | OutputMode::PrintOutput) => ( - command.command.status().map(|status| Output { - status, - stdout: Vec::new(), - stderr: Vec::new(), - }), - matches!(mode, OutputMode::PrintAll), + let output_mode = command.output_mode.unwrap_or_else(|| match self.is_verbose() { + true => OutputMode::All, + false => OutputMode::OnlyOutput, + }); + let (output, print_error): (io::Result<CommandOutput>, bool) = match output_mode { + mode @ (OutputMode::All | OutputMode::OnlyOutput) => ( + command.command.status().map(|status| status.into()), + matches!(mode, OutputMode::All), ), - OutputMode::SuppressOnSuccess => (command.command.output(), true), + OutputMode::OnlyOnFailure => (command.command.output().map(|o| o.into()), true), }; let output = match output { Ok(output) => output, Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", command, e)), }; - let result = if !output.status.success() { + if !output.is_success() { if print_error { println!( "\n\nCommand did not execute successfully.\ - \nExpected success, got: {}", - output.status, + \nExpected success, got: {}", + output.status(), ); if !self.is_verbose() { @@ -1034,37 +1000,45 @@ impl Build { self.verbose(|| { println!( "\nSTDOUT ----\n{}\n\ - STDERR ----\n{}\n", - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) + STDERR ----\n{}\n", + output.stdout(), + output.stderr(), ) }); } - Err(()) - } else { - Ok(()) - }; - match result { - Ok(_) => true, - Err(_) => { - match command.failure_behavior { - BehaviorOnFailure::DelayFail => { - if self.fail_fast { - exit!(1); - } - - let mut failures = self.delayed_failures.borrow_mut(); - failures.push(format!("{command:?}")); - } - BehaviorOnFailure::Exit => { + match command.failure_behavior { + BehaviorOnFailure::DelayFail => { + if self.fail_fast { exit!(1); } - BehaviorOnFailure::Ignore => {} + + let mut failures = self.delayed_failures.borrow_mut(); + failures.push(format!("{command:?}")); + } + BehaviorOnFailure::Exit => { + exit!(1); } - false + BehaviorOnFailure::Ignore => {} } } + output + } + + /// Runs a command, printing out nice contextual information if it fails. + fn run(&self, cmd: &mut Command) { + self.run_cmd(BootstrapCommand::from(cmd).fail_fast().output_mode( + match self.is_verbose() { + true => OutputMode::All, + false => OutputMode::OnlyOutput, + }, + )); + } + + /// A centralized function for running commands that do not return output. + pub(crate) fn run_cmd<'a, C: Into<BootstrapCommand<'a>>>(&self, cmd: C) -> bool { + let command = cmd.into(); + self.run_tracked(command).is_success() } /// Check if verbosity is greater than the `level` diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 0aede2022ba..e8c588b75b3 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -1,4 +1,4 @@ -use std::process::Command; +use std::process::{Command, ExitStatus, Output}; /// What should be done when the command fails. #[derive(Debug, Copy, Clone)] @@ -16,11 +16,11 @@ pub enum BehaviorOnFailure { pub enum OutputMode { /// Print both the output (by inheriting stdout/stderr) and also the command itself, if it /// fails. - PrintAll, + All, /// Print the output (by inheriting stdout/stderr). - PrintOutput, + OnlyOutput, /// Suppress the output if the command succeeds, otherwise print the output. - SuppressOnSuccess, + OnlyOnFailure, } /// Wrapper around `std::process::Command`. @@ -28,7 +28,7 @@ pub enum OutputMode { pub struct BootstrapCommand<'a> { pub command: &'a mut Command, pub failure_behavior: BehaviorOnFailure, - pub output_mode: OutputMode, + pub output_mode: Option<OutputMode>, } impl<'a> BootstrapCommand<'a> { @@ -44,17 +44,62 @@ impl<'a> BootstrapCommand<'a> { Self { failure_behavior: BehaviorOnFailure::Ignore, ..self } } + /// Do not print the output of the command, unless it fails. + pub fn quiet(self) -> Self { + self.output_mode(OutputMode::OnlyOnFailure) + } + pub fn output_mode(self, output_mode: OutputMode) -> Self { - Self { output_mode, ..self } + Self { output_mode: Some(output_mode), ..self } } } impl<'a> From<&'a mut Command> for BootstrapCommand<'a> { fn from(command: &'a mut Command) -> Self { - Self { - command, - failure_behavior: BehaviorOnFailure::Exit, - output_mode: OutputMode::PrintAll, - } + Self { command, failure_behavior: BehaviorOnFailure::Exit, output_mode: None } + } +} + +/// Represents the output of an executed process. +#[allow(unused)] +pub struct CommandOutput(Output); + +impl CommandOutput { + pub fn is_success(&self) -> bool { + self.0.status.success() + } + + pub fn is_failure(&self) -> bool { + !self.is_success() + } + + pub fn status(&self) -> ExitStatus { + self.0.status + } + + pub fn stdout(&self) -> String { + String::from_utf8(self.0.stdout.clone()).expect("Cannot parse process stdout as UTF-8") + } + + pub fn stderr(&self) -> String { + String::from_utf8(self.0.stderr.clone()).expect("Cannot parse process stderr as UTF-8") + } +} + +impl Default for CommandOutput { + fn default() -> Self { + Self(Output { status: Default::default(), stdout: vec![], stderr: vec![] }) + } +} + +impl From<Output> for CommandOutput { + fn from(output: Output) -> Self { + Self(output) + } +} + +impl From<ExitStatus> for CommandOutput { + fn from(status: ExitStatus) -> Self { + Self(Output { status, stdout: vec![], stderr: vec![] }) } } diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 115ee69a589..6db25ff1a80 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -112,7 +112,7 @@ def atomic_link(link: Path, target: Path): os.remove(tmp_file) -@dataclass(kw_only=True) +@dataclass class TestEnvironment: rust_build_dir: Path sdk_dir: Path diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index e76ebb8f8aa..1a8ff931f01 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -47,7 +47,7 @@ - [\*-linux-ohos](platform-support/openharmony.md) - [\*-hurd-gnu](platform-support/hurd.md) - [aarch64-unknown-teeos](platform-support/aarch64-unknown-teeos.md) - - [\*-esp-espidf](platform-support/esp-idf.md) + - [\*-espidf](platform-support/esp-idf.md) - [\*-unknown-fuchsia](platform-support/fuchsia.md) - [\*-kmc-solid_\*](platform-support/kmc-solid.md) - [csky-unknown-linux-gnuabiv2\*](platform-support/csky-unknown-linux-gnuabiv2.md) @@ -60,6 +60,7 @@ - [mipsel-sony-psx](platform-support/mipsel-sony-psx.md) - [mipsisa\*r6\*-unknown-linux-gnu\*](platform-support/mips-release-6.md) - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md) + - [powerpc-unknown-openbsd](platform-support/powerpc-unknown-openbsd.md) - [powerpc64-ibm-aix](platform-support/aix.md) - [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md) - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) @@ -81,6 +82,7 @@ - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md) - [x86_64-unknown-linux-none.md](platform-support/x86_64-unknown-linux-none.md) - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md) + - [xtensa-\*-none-elf](platform-support/xtensa.md) - [Targets](targets/index.md) - [Built-in Targets](targets/built-in.md) - [Custom Targets](targets/custom.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 834e909c065..537c88cd22b 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -330,7 +330,7 @@ target | std | host | notes `powerpc-unknown-linux-gnuspe` | ✓ | | PowerPC SPE Linux `powerpc-unknown-linux-musl` | ? | | PowerPC Linux with musl 1.2.3 [`powerpc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD 32-bit powerpc systems -`powerpc-unknown-openbsd` | ? | | +[`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * | | `powerpc-wrs-vxworks-spe` | ? | | `powerpc-wrs-vxworks` | ? | | `powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2) @@ -384,8 +384,11 @@ target | std | host | notes `x86_64-wrs-vxworks` | ? | | [`x86_64h-apple-darwin`](platform-support/x86_64h-apple-darwin.md) | ✓ | ✓ | macOS with late-gen Intel (at least Haswell) [`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * | | 64-bit Linux with no libc -`xtensa-esp32-none-elf` | | | Xtensa ESP32 -`xtensa-esp32s2-none-elf` | | | Xtensa ESP32-S2 -`xtensa-esp32s3-none-elf` | | | Xtensa ESP32-S3 +[`xtensa-esp32-none-elf`](platform-support/xtensa.md) | * | | Xtensa ESP32 +[`xtensa-esp32-espidf`](platform-support/esp-idf.md) | ✓ | | Xtensa ESP32 +[`xtensa-esp32s2-none-elf`](platform-support/xtensa.md) | * | | Xtensa ESP32-S2 +[`xtensa-esp32s2-espidf`](platform-support/esp-idf.md) | ✓ | | Xtensa ESP32-S2 +[`xtensa-esp32s3-none-elf`](platform-support/xtensa.md) | * | | Xtensa ESP32-S3 +[`xtensa-esp32s3-espidf`](platform-support/esp-idf.md) | ✓ | | Xtensa ESP32-S3 [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets diff --git a/src/doc/rustc/src/platform-support/esp-idf.md b/src/doc/rustc/src/platform-support/esp-idf.md index 1f8d9859809..91d7d66627d 100644 --- a/src/doc/rustc/src/platform-support/esp-idf.md +++ b/src/doc/rustc/src/platform-support/esp-idf.md @@ -1,4 +1,4 @@ -# `*-esp-espidf` +# `*-espidf` **Tier: 3** @@ -8,18 +8,22 @@ Targets for the [ESP-IDF](https://github.com/espressif/esp-idf) development fram - Ivan Markov [@ivmarkov](https://github.com/ivmarkov) - Scott Mabin [@MabezDev](https://github.com/MabezDev) +- Sergio Gasquez [@SergioGasquez](https://github.com/SergioGasquez) ## Requirements The target names follow this format: `$ARCH-esp-espidf`, where `$ARCH` specifies the target processor architecture. The following targets are currently defined: -| Target name | Target CPU(s) | Minimum ESP-IDF version | -| ------------------------ | --------------------------------------------------------------- | ----------------------- | -| `riscv32imc-esp-espidf` | [ESP32-C2](https://www.espressif.com/en/products/socs/esp32-c2) | `v5.0` | -| `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` | +| Target name | Target CPU(s) | Minimum ESP-IDF version | +| ------------------------- | --------------------------------------------------------------- | ----------------------- | +| `riscv32imc-esp-espidf` | [ESP32-C2](https://www.espressif.com/en/products/socs/esp32-c2) | `v5.0` | +| `riscv32imc-esp-espidf` | [ESP32-C3](https://www.espressif.com/en/products/socs/esp32-c3) | `v4.4` | +| `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` | +| `xtensa-esp32-espidf` | [ESP32](https://www.espressif.com/en/products/socs/esp32) | `v4.4` | +| `xtensa-esp32s2-espidf` | [ESP32-S2](https://www.espressif.com/en/products/socs/esp32-s2) | `v4.4` | +| `xtensa-esp32s3-espidf` | [ESP32-S3](https://www.espressif.com/en/products/socs/esp32-s3) | `v4.4` | It is recommended to use the latest ESP-IDF stable release if possible. diff --git a/src/doc/rustc/src/platform-support/powerpc-unknown-openbsd.md b/src/doc/rustc/src/platform-support/powerpc-unknown-openbsd.md new file mode 100644 index 00000000000..b1600c71f1f --- /dev/null +++ b/src/doc/rustc/src/platform-support/powerpc-unknown-openbsd.md @@ -0,0 +1,3 @@ +## Designated maintainers + +`powerpc-unknown-openbsd` is not maintained by OpenBSD developers and there are currently no active rustc maintainers. diff --git a/src/doc/rustc/src/platform-support/xtensa.md b/src/doc/rustc/src/platform-support/xtensa.md index 7785977466e..332b8ee9c15 100644 --- a/src/doc/rustc/src/platform-support/xtensa.md +++ b/src/doc/rustc/src/platform-support/xtensa.md @@ -1,4 +1,4 @@ -# `xtensa-*` +# `xtensa-*-none-elf` **Tier: 3** @@ -20,6 +20,8 @@ The target names follow this format: `xtensa-$CPU`, where `$CPU` specifies the t | `xtensa-esp32s3-none-elf` | [ESP32-S3](https://www.espressif.com/en/products/socs/esp32-s3) | -## Building the target +Xtensa targets that support `std` are documented in the [ESP-IDF platform support document](esp-idf.md) + +## Building the targets The targets can be built by installing the [Xtensa enabled Rust channel](https://github.com/esp-rs/rust/). See instructions in the [RISC-V and Xtensa Targets section of the The Rust on ESP Book](https://docs.esp-rs.org/book/installation/riscv-and-xtensa.html). diff --git a/src/doc/unstable-book/src/language-features/c-unwind.md b/src/doc/unstable-book/src/language-features/c-unwind.md deleted file mode 100644 index fb32918d5e4..00000000000 --- a/src/doc/unstable-book/src/language-features/c-unwind.md +++ /dev/null @@ -1,26 +0,0 @@ -# `c_unwind` - -The tracking issue for this feature is: [#74990] - -[#74990]: https://github.com/rust-lang/rust/issues/74990 - ------------------------- - -Introduces new ABI strings: -- "C-unwind" -- "cdecl-unwind" -- "stdcall-unwind" -- "fastcall-unwind" -- "vectorcall-unwind" -- "thiscall-unwind" -- "aapcs-unwind" -- "win64-unwind" -- "sysv64-unwind" -- "system-unwind" - -These enable unwinding from other languages (such as C++) into Rust frames and -from Rust into other languages. - -See [RFC 2945] for more information. - -[RFC 2945]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md index 02a009d56d3..c262d3f6da1 100644 --- a/src/doc/unstable-book/src/language-features/intrinsics.md +++ b/src/doc/unstable-book/src/language-features/intrinsics.md @@ -18,7 +18,7 @@ All intrinsic fallback bodies are automatically made cross-crate inlineable (lik by the codegen backend, but not the MIR inliner. ```rust -#![feature(rustc_attrs, effects)] +#![feature(rustc_attrs)] #![allow(internal_features)] #[rustc_intrinsic] @@ -28,7 +28,7 @@ const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} Since these are just regular functions, it is perfectly ok to create the intrinsic twice: ```rust -#![feature(rustc_attrs, effects)] +#![feature(rustc_attrs)] #![allow(internal_features)] #[rustc_intrinsic] diff --git a/src/doc/unstable-book/src/library-features/sort-internals.md b/src/doc/unstable-book/src/library-features/sort-internals.md deleted file mode 100644 index 6f2385e5300..00000000000 --- a/src/doc/unstable-book/src/library-features/sort-internals.md +++ /dev/null @@ -1,5 +0,0 @@ -# `sort_internals` - -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 7343f3147ee..2072f76a481 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -48,6 +48,7 @@ complete -c x.py -n "__fish_use_subcommand" -f -a "run" -d 'Run tools contained complete -c x.py -n "__fish_use_subcommand" -f -a "setup" -d 'Set up the environment for development' complete -c x.py -n "__fish_use_subcommand" -f -a "suggest" -d 'Suggest a subset of tests to run, based on modified files' complete -c x.py -n "__fish_use_subcommand" -f -a "vendor" -d 'Vendor dependencies' +complete -c x.py -n "__fish_use_subcommand" -f -a "perf" -d 'Perform profiling and benchmarking of the compiler using the `rustc-perf` benchmark suite' complete -c x.py -n "__fish_seen_subcommand_from build" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_seen_subcommand_from build" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from build" -l build -d 'build target of the stage0 compiler' -r -f @@ -628,3 +629,37 @@ complete -c x.py -n "__fish_seen_subcommand_from vendor" -l llvm-profile-generat complete -c x.py -n "__fish_seen_subcommand_from vendor" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from vendor" -l skip-stage0-validation -d 'Skip stage0 compiler validation' complete -c x.py -n "__fish_seen_subcommand_from vendor" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from perf" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from perf" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from perf" -l skip -d 'build paths to skip' -r -F +complete -c x.py -n "__fish_seen_subcommand_from perf" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from perf" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from perf" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" +complete -c x.py -n "__fish_seen_subcommand_from perf" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from perf" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" +complete -c x.py -n "__fish_seen_subcommand_from perf" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from perf" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from perf" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from perf" -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 perf" -l set -d 'override options in config.toml' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from perf" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l enable-bolt-settings -d 'Enable BOLT link flags' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_seen_subcommand_from perf" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index d9adb1778f2..919382d441f 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -75,6 +75,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development') [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files') [CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies') + [CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using the `rustc-perf` benchmark suite') break } 'x.py;build' { @@ -769,6 +770,47 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break } + 'x.py;perf' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--skip', 'skip', [CompletionResultType]::ParameterName, 'build paths to skip') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [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('-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') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--dump-bootstrap-shims', 'dump-bootstrap-shims', [CompletionResultType]::ParameterName, 'Indicates whether to dump the work done from bootstrap shims') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--bypass-bootstrap-lock', 'bypass-bootstrap-lock', [CompletionResultType]::ParameterName, 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') + [CompletionResult]::new('--skip-stage0-validation', 'skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } }) $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 6cb9e95c8c1..a4234905476 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -45,6 +45,9 @@ _x.py() { bootstrap,miri) cmd="bootstrap__miri" ;; + bootstrap,perf) + cmd="bootstrap__perf" + ;; bootstrap,run) cmd="bootstrap__run" ;; @@ -67,7 +70,7 @@ _x.py() { case "${cmd}" in x.py) - opts="-v -i -j -h --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]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor" + opts="-v -i -j -h --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]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1414,6 +1417,116 @@ _x.py() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + x.py__perf) + opts="-v -i -j -h --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 + fi + case "${prev}" in + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --skip) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --reproducible-artifact) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; x.py__run) opts="-v -i -j -h --args --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 diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 24ddd1c4b7c..bbebf8b892d 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -789,6 +789,49 @@ _arguments "${_arguments_options[@]}" \ '*::paths -- paths for the subcommand:_files' \ && ret=0 ;; +(perf) +_arguments "${_arguments_options[@]}" \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--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:( )' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--dump-bootstrap-shims[Indicates whether to dump the work done from bootstrap shims]' \ +'--json-output[use message-format=json]' \ +'--bypass-bootstrap-lock[Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'--skip-stage0-validation[Skip stage0 compiler validation]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; esac ;; esac @@ -813,6 +856,7 @@ _x.py_commands() { 'setup:Set up the environment for development' \ 'suggest:Suggest a subset of tests to run, based on modified files' \ 'vendor:Vendor dependencies' \ +'perf:Perform profiling and benchmarking of the compiler using the \`rustc-perf\` benchmark suite' \ ) _describe -t commands 'x.py commands' commands "$@" } @@ -871,6 +915,11 @@ _x.py__miri_commands() { local commands; commands=() _describe -t commands 'x.py miri commands' commands "$@" } +(( $+functions[_x.py__perf_commands] )) || +_x.py__perf_commands() { + local commands; commands=() + _describe -t commands 'x.py perf commands' commands "$@" +} (( $+functions[_x.py__run_commands] )) || _x.py__run_commands() { local commands; commands=() diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index da41f974068..22565ea4028 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3077,9 +3077,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( let def_id = item.owner_id.to_def_id(); cx.with_param_env(def_id, |cx| { let kind = match item.kind { - // FIXME(missing_unsafe_on_extern) handle safety of foreign fns. - // Safety was added as part of the implementation of unsafe extern blocks PR #124482 - hir::ForeignItemKind::Fn(decl, names, generics, _) => { + hir::ForeignItemKind::Fn(decl, names, generics, safety) => { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args let generics = clean_generics(generics, cx); @@ -3087,13 +3085,12 @@ fn clean_maybe_renamed_foreign_item<'tcx>( let decl = clean_fn_decl_with_args(cx, decl, None, args); (generics, decl) }); - ForeignFunctionItem(Box::new(Function { decl, generics })) - } - // FIXME(missing_unsafe_on_extern) handle safety of foreign statics. - // Safety was added as part of the implementation of unsafe extern blocks PR #124482 - hir::ForeignItemKind::Static(ty, mutability, _) => { - ForeignStaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: None }) + ForeignFunctionItem(Box::new(Function { decl, generics }), safety) } + hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem( + Static { type_: clean_ty(ty, cx), mutability, expr: None }, + safety, + ), hir::ForeignItemKind::Type => ForeignTypeItem, }; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 69678b727c1..c4020f2a450 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -639,14 +639,14 @@ impl Item { hir::FnHeader { safety: sig.safety(), abi: sig.abi(), constness, asyncness } } let header = match *self.kind { - ItemKind::ForeignFunctionItem(_) => { + ItemKind::ForeignFunctionItem(_, safety) => { let def_id = self.def_id().unwrap(); let abi = tcx.fn_sig(def_id).skip_binder().abi(); hir::FnHeader { safety: if abi == Abi::RustIntrinsic { intrinsic_operation_unsafety(tcx, def_id.expect_local()) } else { - hir::Safety::Unsafe + safety }, abi, constness: if tcx.is_const_fn(def_id) @@ -842,9 +842,9 @@ pub(crate) enum ItemKind { StructFieldItem(Type), VariantItem(Variant), /// `fn`s from an extern block - ForeignFunctionItem(Box<Function>), + ForeignFunctionItem(Box<Function>, hir::Safety), /// `static`s from an extern block - ForeignStaticItem(Static), + ForeignStaticItem(Static, hir::Safety), /// `type`s from an extern block ForeignTypeItem, MacroItem(Macro), @@ -893,8 +893,8 @@ impl ItemKind { | TyMethodItem(_) | MethodItem(_, _) | StructFieldItem(_) - | ForeignFunctionItem(_) - | ForeignStaticItem(_) + | ForeignFunctionItem(_, _) + | ForeignStaticItem(_, _) | ForeignTypeItem | MacroItem(_) | ProcMacroItem(_) @@ -924,8 +924,8 @@ impl ItemKind { | StaticItem(_) | ConstantItem(_, _, _) | TraitAliasItem(_) - | ForeignFunctionItem(_) - | ForeignStaticItem(_) + | ForeignFunctionItem(_, _) + | ForeignStaticItem(_, _) | ForeignTypeItem | MacroItem(_) | ProcMacroItem(_) diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index c85b955d4c5..346e9a4e113 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -84,8 +84,8 @@ pub(crate) trait DocFolder: Sized { | TyMethodItem(_) | MethodItem(_, _) | StructFieldItem(_) - | ForeignFunctionItem(_) - | ForeignStaticItem(_) + | ForeignFunctionItem(..) + | ForeignStaticItem(..) | ForeignTypeItem | MacroItem(_) | ProcMacroItem(_) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index e1f79254b24..00973865915 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -254,7 +254,7 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf match &*item.kind { clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items), - clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => { + clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f, _) => { item_function(buf, cx, item, f) } clean::TraitItem(ref t) => item_trait(buf, cx, item, t), @@ -265,7 +265,8 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf clean::MacroItem(ref m) => item_macro(buf, cx, item, m), clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m), clean::PrimitiveItem(_) => item_primitive(buf, cx, item), - clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => item_static(buf, cx, item, i), + clean::StaticItem(ref i) => item_static(buf, cx, item, i, None), + clean::ForeignStaticItem(ref i, safety) => item_static(buf, cx, item, i, Some(*safety)), clean::ConstantItem(generics, ty, c) => item_constant(buf, cx, item, generics, ty, c), clean::ForeignTypeItem => item_foreign_type(buf, cx, item), clean::KeywordItem => item_keyword(buf, cx, item), @@ -491,11 +492,14 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: } let unsafety_flag = match *myitem.kind { - clean::FunctionItem(_) | clean::ForeignFunctionItem(_) + clean::FunctionItem(_) | clean::ForeignFunctionItem(..) if myitem.fn_header(tcx).unwrap().safety == hir::Safety::Unsafe => { "<sup title=\"unsafe function\">⚠</sup>" } + clean::ForeignStaticItem(_, hir::Safety::Unsafe) => { + "<sup title=\"unsafe static\">⚠</sup>" + } _ => "", }; @@ -1957,13 +1961,22 @@ fn item_fields( } } -fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { +fn item_static( + w: &mut impl fmt::Write, + cx: &mut Context<'_>, + it: &clean::Item, + s: &clean::Static, + safety: Option<hir::Safety>, +) { wrap_item(w, |buffer| { render_attributes_in_code(buffer, it, cx); write!( buffer, - "{vis}static {mutability}{name}: {typ}", + "{vis}{safe}static {mutability}{name}: {typ}", vis = visibility_print_with_space(it, cx), + safe = safety + .map(|safe| if safe == hir::Safety::Unsafe { "unsafe " } else { "" }) + .unwrap_or(""), mutability = s.mutability.print_with_space(), name = it.name.unwrap(), typ = s.type_.print(cx) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index afafb4fbe4b..d099a97f1cb 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -310,14 +310,16 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { EnumItem(e) => ItemEnum::Enum(e.into_tcx(tcx)), VariantItem(v) => ItemEnum::Variant(v.into_tcx(tcx)), FunctionItem(f) => ItemEnum::Function(from_function(f, true, header.unwrap(), tcx)), - ForeignFunctionItem(f) => ItemEnum::Function(from_function(f, false, header.unwrap(), tcx)), + ForeignFunctionItem(f, _) => { + ItemEnum::Function(from_function(f, false, header.unwrap(), tcx)) + } TraitItem(t) => ItemEnum::Trait((*t).into_tcx(tcx)), TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)), MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), tcx)), TyMethodItem(m) => ItemEnum::Function(from_function(m, false, header.unwrap(), tcx)), ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)), StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), - ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), + ForeignStaticItem(s, _) => ItemEnum::Static(s.into_tcx(tcx)), ForeignTypeItem => ItemEnum::ForeignType, TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_tcx(tcx)), OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into_tcx(tcx)), diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 592dd0a145c..9e576002dc3 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -1,4 +1,5 @@ //! Calculates information used for the --show-coverage flag. + use crate::clean; use crate::core::DocContext; use crate::html::markdown::{find_testable_code, ErrorCodes}; diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index c92cf9d3e80..9ac9941e521 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -1,6 +1,7 @@ //! Collects trait impls for each item in the crate. For example, if a crate //! defines a struct that implements a trait, this pass will note that the //! struct implements that trait. + use super::Pass; use crate::clean::*; use crate::core::DocContext; diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index c185442fd55..afeb7111e15 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -1,4 +1,5 @@ //! Validates syntax inside Rust code blocks (\`\`\`rust). + use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{ emitter::Emitter, diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index 25b0c61b826..a0064a90112 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -1,4 +1,5 @@ //! Detects invalid HTML (like an unclosed `<span>`) in doc comments. + use crate::clean::*; use crate::core::DocContext; use crate::html::markdown::main_body_opts; diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 95273a225a9..8de7f2379b4 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -1,4 +1,5 @@ //! Propagates [`#[doc(cfg(...))]`](https://github.com/rust-lang/rust/issues/43781) to child items. + use std::sync::Arc; use crate::clean::cfg::Cfg; diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs index 468712ba3d0..7b05756ae21 100644 --- a/src/librustdoc/passes/strip_priv_imports.rs +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -1,5 +1,6 @@ //! Strips all private import statements (use, extern crate) from a //! crate. + use crate::clean; use crate::core::DocContext; use crate::fold::DocFolder; diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 3b6f484fde6..1bafa450be9 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -1,5 +1,6 @@ //! Strip all private items from the output. Additionally implies strip_priv_imports. //! Basically, the goal is to remove items that are not relevant for public documentation. + use crate::clean::{self, ItemIdSet}; use crate::core::DocContext; use crate::fold::DocFolder; diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 1bea93c7842..1cf80a0d80c 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -1,4 +1,5 @@ //! A collection of utility functions for the `strip_*` passes. + use rustc_hir::def_id::DefId; use rustc_middle::ty::{TyCtxt, Visibility}; use std::mem; diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index 0660037e4d8..b335dc5bd16 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -33,8 +33,8 @@ pub(crate) trait DocVisitor: Sized { | TyMethodItem(_) | MethodItem(_, _) | StructFieldItem(_) - | ForeignFunctionItem(_) - | ForeignStaticItem(_) + | ForeignFunctionItem(..) + | ForeignStaticItem(..) | ForeignTypeItem | MacroItem(_) | ProcMacroItem(_) diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 3ed207e416fb2f678a40cc79c02dcf4f936a21c +Subproject bc89bffa5987d4af8f71011c7557119b39e44a6 diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs index 1743ce71add..5bc8692c289 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs @@ -21,6 +21,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, fn is_known_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { match constant(cx, cx.typeck_results(), e) { + // FIXME(f16_f128): add these types when nan checks are available on all platforms Some(Constant::F64(n)) => n.is_nan(), Some(Constant::F32(n)) => n.is_nan(), _ => false, diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs index 4d301daabe4..2261fcdbdab 100644 --- a/src/tools/clippy/clippy_lints/src/float_literal.rs +++ b/src/tools/clippy/clippy_lints/src/float_literal.rs @@ -141,18 +141,17 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { #[must_use] fn max_digits(fty: FloatTy) -> u32 { match fty { - // FIXME(f16_f128): replace the magic numbers once `{f16,f128}::DIGITS` are available - FloatTy::F16 => 3, + FloatTy::F16 => f16::DIGITS, FloatTy::F32 => f32::DIGITS, FloatTy::F64 => f64::DIGITS, - FloatTy::F128 => 33, + FloatTy::F128 => f128::DIGITS, } } /// Counts the digits excluding leading zeros #[must_use] fn count_digits(s: &str) -> usize { - // Note that s does not contain the f32/64 suffix, and underscores have been stripped + // Note that s does not contain the `f{16,32,64,128}` suffix, and underscores have been stripped s.chars() .filter(|c| *c != '-' && *c != '.') .take_while(|c| *c != 'e' && *c != 'E') diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index c65581d5203..ef322786dbc 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -1,6 +1,8 @@ #![feature(array_windows)] #![feature(binary_heap_into_iter_sorted)] #![feature(box_patterns)] +#![feature(f128)] +#![feature(f16)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs index 72cf1d7a354..89eea0b4456 100644 --- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs +++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs @@ -156,6 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { fn is_infinity(constant: &Constant<'_>) -> bool { match constant { + // FIXME(f16_f128): add f16 and f128 when constants are available Constant::F32(float) => *float == f32::INFINITY, Constant::F64(float) => *float == f64::INFINITY, _ => false, @@ -164,6 +165,7 @@ fn is_infinity(constant: &Constant<'_>) -> bool { fn is_neg_infinity(constant: &Constant<'_>) -> bool { match constant { + // FIXME(f16_f128): add f16 and f128 when constants are available Constant::F32(float) => *float == f32::NEG_INFINITY, Constant::F64(float) => *float == f64::NEG_INFINITY, _ => false, diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs index 0561739d160..faab79de9d3 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs @@ -86,6 +86,7 @@ fn get_lint_and_message(is_local: bool, is_comparing_arrays: bool) -> (&'static fn is_allowed(val: &Constant<'_>) -> bool { match val { + // FIXME(f16_f128): add when equality check is available on all platforms &Constant::F32(f) => f == 0.0 || f.is_infinite(), &Constant::F64(f) => f == 0.0 || f.is_infinite(), Constant::Vec(vec) => vec.iter().all(|f| match f { diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs index c56518ac72a..d65fffac5a8 100644 --- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs @@ -79,6 +79,7 @@ fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> }, _ => {}, }, + // FIXME(f16_f128): add when casting is available on all platforms Some(Constant::F32(f)) => { return Some(floating_point_operand_info(&f)); }, diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs index 662242f6196..60d8a13d359 100644 --- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs +++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs @@ -38,6 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv { // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too. && let Some(lhs_value) = constant_simple(cx, cx.typeck_results(), left) && let Some(rhs_value) = constant_simple(cx, cx.typeck_results(), right) + // FIXME(f16_f128): add these types when eq is available on all platforms && (Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value) && (Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value) { diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index 3a3aeb88216..6e53ff3ee6e 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -9,6 +9,8 @@ clippy_config = { path = "../clippy_config" } arrayvec = { version = "0.7", default-features = false } itertools = "0.12" rustc-semver = "1.1" +# FIXME(f16_f128): remove when no longer needed for parsing +rustc_apfloat = "0.2.0" [features] deny-warnings = ["clippy_config/deny-warnings"] diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index fb43f7d80af..785d5ed5dbe 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -449,13 +449,13 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { use ForeignItemKind::*; match (l, r) { ( - Static(box StaticForeignItem { + Static(box StaticItem { ty: lt, mutability: lm, expr: le, safety: ls, }), - Static(box StaticForeignItem { + Static(box StaticItem { ty: rt, mutability: rm, expr: re, diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index cfd142fe1ff..681c86f76d0 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -3,6 +3,8 @@ use crate::source::{get_source_text, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, unsext}; +use rustc_apfloat::ieee::{Half, Quad}; +use rustc_apfloat::Float; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; @@ -33,10 +35,14 @@ pub enum Constant<'tcx> { Char(char), /// An integer's bit representation. Int(u128), + /// An `f16`. + F16(f16), /// An `f32`. F32(f32), /// An `f64`. F64(f64), + /// An `f128`. + F128(f128), /// `true` or `false`. Bool(bool), /// An array of constants. @@ -161,12 +167,19 @@ impl<'tcx> Hash for Constant<'tcx> { Self::Int(i) => { i.hash(state); }, + Self::F16(f) => { + // FIXME(f16_f128): once conversions to/from `f128` are available on all platforms, + f.to_bits().hash(state); + }, Self::F32(f) => { f64::from(f).to_bits().hash(state); }, Self::F64(f) => { f.to_bits().hash(state); }, + Self::F128(f) => { + f.to_bits().hash(state); + }, Self::Bool(b) => { b.hash(state); }, @@ -268,6 +281,16 @@ impl<'tcx> Constant<'tcx> { } self } + + fn parse_f16(s: &str) -> Self { + let f: Half = s.parse().unwrap(); + Self::F16(f16::from_bits(f.to_bits().try_into().unwrap())) + } + + fn parse_f128(s: &str) -> Self { + let f: Quad = s.parse().unwrap(); + Self::F128(f128::from_bits(f.to_bits())) + } } /// Parses a `LitKind` to a `Constant`. @@ -279,16 +302,17 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option<Ty<'tcx>>) -> Constan LitKind::Char(c) => Constant::Char(c), LitKind::Int(n, _) => Constant::Int(n.get()), LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty { - ast::FloatTy::F16 => unimplemented!("f16_f128"), + // FIXME(f16_f128): just use `parse()` directly when available for `f16`/`f128` + ast::FloatTy::F16 => Constant::parse_f16(is.as_str()), ast::FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()), ast::FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()), - ast::FloatTy::F128 => unimplemented!("f16_f128"), + ast::FloatTy::F128 => Constant::parse_f128(is.as_str()), }, LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind() { - ty::Float(FloatTy::F16) => unimplemented!("f16_f128"), + ty::Float(FloatTy::F16) => Constant::parse_f16(is.as_str()), ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()), ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()), - ty::Float(FloatTy::F128) => unimplemented!("f16_f128"), + ty::Float(FloatTy::F128) => Constant::parse_f128(is.as_str()), _ => bug!(), }, LitKind::Bool(b) => Constant::Bool(b), @@ -625,15 +649,19 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { match (lhs, index) { (Some(Constant::Vec(vec)), Some(Constant::Int(index))) => match vec.get(index as usize) { + Some(Constant::F16(x)) => Some(Constant::F16(*x)), Some(Constant::F32(x)) => Some(Constant::F32(*x)), Some(Constant::F64(x)) => Some(Constant::F64(*x)), + Some(Constant::F128(x)) => Some(Constant::F128(*x)), _ => None, }, (Some(Constant::Vec(vec)), _) => { if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) { match vec.first() { + Some(Constant::F16(x)) => Some(Constant::F16(*x)), Some(Constant::F32(x)) => Some(Constant::F32(*x)), Some(Constant::F64(x)) => Some(Constant::F64(*x)), + Some(Constant::F128(x)) => Some(Constant::F128(*x)), _ => None, } } else { @@ -760,6 +788,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { }, _ => None, }, + // FIXME(f16_f128): add these types when binary operations are available on all platforms (Constant::F32(l), Some(Constant::F32(r))) => match op.node { BinOpKind::Add => Some(Constant::F32(l + r)), BinOpKind::Sub => Some(Constant::F32(l - r)), @@ -813,8 +842,10 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.to_bits(int.size()))), + ty::Float(FloatTy::F16) => Some(Constant::F16(f16::from_bits(int.into()))), ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(int.into()))), ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(int.into()))), + ty::Float(FloatTy::F128) => Some(Constant::F128(f128::from_bits(int.into()))), ty::RawPtr(_, _) => Some(Constant::RawPtr(int.to_bits(int.size()))), _ => None, }, @@ -835,10 +866,10 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> let range = alloc_range(offset + size * idx, size); let val = alloc.read_scalar(&lcx.tcx, range, /* read_provenance */ false).ok()?; res.push(match flt { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().ok()?)), FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)), FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().ok()?)), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => Constant::F128(f128::from_bits(val.to_u128().ok()?)), }); } Some(Constant::Vec(res)) diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 7dc341ec8d7..6848e8e5c30 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,6 +1,8 @@ #![feature(array_chunks)] #![feature(box_patterns)] #![feature(control_flow_enum)] +#![feature(f128)] +#![feature(f16)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(lint_reasons)] diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs index 63fdea710cb..17fceae0178 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs @@ -40,6 +40,7 @@ fn main() { a.sort_unstable(); + // FIXME(f16_f128): add a clamp test once the function is available let _ = 2.0f32.clamp(3.0f32, 4.0f32); let _ = 2.0f64.clamp(3.0f64, 4.0f64); diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr index 55e867d5f39..4afbbf5f807 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr @@ -28,61 +28,61 @@ LL | a.sort_unstable(); | ^^^^^^^^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:43:13 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:13 | LL | let _ = 2.0f32.clamp(3.0f32, 4.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed method `regex::Regex::new` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:46:61 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:47:61 | LL | let indirect: fn(&str) -> Result<Regex, regex::Error> = Regex::new; | ^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:49:28 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:50:28 | LL | let in_call = Box::new(f32::clamp); | ^^^^^^^^^^ error: use of a disallowed method `regex::Regex::new` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:50:53 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:51:53 | LL | let in_method_call = ["^", "$"].into_iter().map(Regex::new); | ^^^^^^^^^^ error: use of a disallowed method `futures::stream::select_all` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:53:31 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54:31 | LL | let same_name_as_module = select_all(vec![empty::<()>()]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_fn` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:55:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56:5 | LL | local_fn(); | ^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_mod::f` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:57:5 | LL | local_mod::f(); | ^^^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Struct::method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:58:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:5 | LL | s.method(); | ^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:5 | LL | s.provided_method(); | ^^^^^^^^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:5 | LL | s.implemented_method(); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs index 33a91e8bbbe..9d06e14e88c 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs @@ -11,6 +11,8 @@ unconditional_panic )] #![feature(const_mut_refs)] +#![feature(f128)] +#![feature(f16)] #![warn(clippy::arithmetic_side_effects)] extern crate proc_macro_derive; @@ -162,8 +164,10 @@ pub fn association_with_structures_should_not_trigger_the_lint() { } pub fn hard_coded_allowed() { + let _ = 1f16 + 1f16; let _ = 1f32 + 1f32; let _ = 1f64 + 1f64; + let _ = 1f128 + 1f128; let _ = Saturating(0u32) + Saturating(0u32); let _ = String::new() + ""; diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr index 8039c0bfa24..78914667bf3 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr @@ -1,731 +1,743 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:304:5 + --> tests/ui/arithmetic_side_effects.rs:167:13 | -LL | _n += 1; - | ^^^^^^^ +LL | let _ = 1f16 + 1f16; + | ^^^^^^^^^^^ | = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:305:5 + --> tests/ui/arithmetic_side_effects.rs:170:13 + | +LL | let _ = 1f128 + 1f128; + | ^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:308:5 + | +LL | _n += 1; + | ^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:309:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:306:5 + --> tests/ui/arithmetic_side_effects.rs:310:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:307:5 + --> tests/ui/arithmetic_side_effects.rs:311:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:308:5 + --> tests/ui/arithmetic_side_effects.rs:312:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:309:5 + --> tests/ui/arithmetic_side_effects.rs:313:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:310:5 + --> tests/ui/arithmetic_side_effects.rs:314:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:311:5 + --> tests/ui/arithmetic_side_effects.rs:315:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:312:5 + --> tests/ui/arithmetic_side_effects.rs:316:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:313:5 + --> tests/ui/arithmetic_side_effects.rs:317:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:314:5 + --> tests/ui/arithmetic_side_effects.rs:318:5 | LL | _n += -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:315:5 + --> tests/ui/arithmetic_side_effects.rs:319:5 | LL | _n += &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:316:5 + --> tests/ui/arithmetic_side_effects.rs:320:5 | LL | _n -= -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:317:5 + --> tests/ui/arithmetic_side_effects.rs:321:5 | LL | _n -= &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:318:5 + --> tests/ui/arithmetic_side_effects.rs:322:5 | LL | _n /= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:319:5 + --> tests/ui/arithmetic_side_effects.rs:323:5 | LL | _n /= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:320:5 + --> tests/ui/arithmetic_side_effects.rs:324:5 | LL | _n %= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:321:5 + --> tests/ui/arithmetic_side_effects.rs:325:5 | LL | _n %= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:322:5 + --> tests/ui/arithmetic_side_effects.rs:326:5 | LL | _n *= -2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:323:5 + --> tests/ui/arithmetic_side_effects.rs:327:5 | LL | _n *= &-2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:324:5 + --> tests/ui/arithmetic_side_effects.rs:328:5 | LL | _custom += Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:325:5 + --> tests/ui/arithmetic_side_effects.rs:329:5 | LL | _custom += &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:326:5 + --> tests/ui/arithmetic_side_effects.rs:330:5 | LL | _custom -= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:327:5 + --> tests/ui/arithmetic_side_effects.rs:331:5 | LL | _custom -= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:328:5 + --> tests/ui/arithmetic_side_effects.rs:332:5 | LL | _custom /= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:329:5 + --> tests/ui/arithmetic_side_effects.rs:333:5 | LL | _custom /= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:330:5 + --> tests/ui/arithmetic_side_effects.rs:334:5 | LL | _custom %= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:331:5 + --> tests/ui/arithmetic_side_effects.rs:335:5 | LL | _custom %= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:332:5 + --> tests/ui/arithmetic_side_effects.rs:336:5 | LL | _custom *= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:333:5 + --> tests/ui/arithmetic_side_effects.rs:337:5 | LL | _custom *= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:334:5 + --> tests/ui/arithmetic_side_effects.rs:338:5 | LL | _custom >>= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:335:5 + --> tests/ui/arithmetic_side_effects.rs:339:5 | LL | _custom >>= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:336:5 + --> tests/ui/arithmetic_side_effects.rs:340:5 | LL | _custom <<= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:337:5 + --> tests/ui/arithmetic_side_effects.rs:341:5 | LL | _custom <<= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:338:5 + --> tests/ui/arithmetic_side_effects.rs:342:5 | LL | _custom += -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:339:5 + --> tests/ui/arithmetic_side_effects.rs:343:5 | LL | _custom += &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:340:5 + --> tests/ui/arithmetic_side_effects.rs:344:5 | LL | _custom -= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:341:5 + --> tests/ui/arithmetic_side_effects.rs:345:5 | LL | _custom -= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:342:5 + --> tests/ui/arithmetic_side_effects.rs:346:5 | LL | _custom /= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:343:5 + --> tests/ui/arithmetic_side_effects.rs:347:5 | LL | _custom /= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:344:5 + --> tests/ui/arithmetic_side_effects.rs:348:5 | LL | _custom %= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:345:5 + --> tests/ui/arithmetic_side_effects.rs:349:5 | LL | _custom %= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:346:5 + --> tests/ui/arithmetic_side_effects.rs:350:5 | LL | _custom *= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:347:5 + --> tests/ui/arithmetic_side_effects.rs:351:5 | LL | _custom *= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:348:5 + --> tests/ui/arithmetic_side_effects.rs:352:5 | LL | _custom >>= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:349:5 + --> tests/ui/arithmetic_side_effects.rs:353:5 | LL | _custom >>= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:350:5 + --> tests/ui/arithmetic_side_effects.rs:354:5 | LL | _custom <<= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:351:5 + --> tests/ui/arithmetic_side_effects.rs:355:5 | LL | _custom <<= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:354:10 + --> tests/ui/arithmetic_side_effects.rs:358:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:355:10 + --> tests/ui/arithmetic_side_effects.rs:359:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:356:10 + --> tests/ui/arithmetic_side_effects.rs:360:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:357:10 + --> tests/ui/arithmetic_side_effects.rs:361:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:358:10 + --> tests/ui/arithmetic_side_effects.rs:362:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:359:10 + --> tests/ui/arithmetic_side_effects.rs:363:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:360:10 + --> tests/ui/arithmetic_side_effects.rs:364:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:361:10 + --> tests/ui/arithmetic_side_effects.rs:365:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:362:10 + --> tests/ui/arithmetic_side_effects.rs:366:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:363:10 + --> tests/ui/arithmetic_side_effects.rs:367:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:364:10 + --> tests/ui/arithmetic_side_effects.rs:368:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:365:10 + --> tests/ui/arithmetic_side_effects.rs:369:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:366:10 + --> tests/ui/arithmetic_side_effects.rs:370:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:367:10 + --> tests/ui/arithmetic_side_effects.rs:371:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:368:10 + --> tests/ui/arithmetic_side_effects.rs:372:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:369:10 + --> tests/ui/arithmetic_side_effects.rs:373:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:370:10 + --> tests/ui/arithmetic_side_effects.rs:374:10 | LL | _n = 23 + &85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:371:10 + --> tests/ui/arithmetic_side_effects.rs:375:10 | LL | _n = &23 + 85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:372:10 + --> tests/ui/arithmetic_side_effects.rs:376:10 | LL | _n = &23 + &85; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:373:15 + --> tests/ui/arithmetic_side_effects.rs:377:15 | LL | _custom = _custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:374:15 + --> tests/ui/arithmetic_side_effects.rs:378:15 | LL | _custom = _custom + &_custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:375:15 + --> tests/ui/arithmetic_side_effects.rs:379:15 | LL | _custom = Custom + _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:376:15 + --> tests/ui/arithmetic_side_effects.rs:380:15 | LL | _custom = &Custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:377:15 + --> tests/ui/arithmetic_side_effects.rs:381:15 | LL | _custom = _custom - Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:378:15 + --> tests/ui/arithmetic_side_effects.rs:382:15 | LL | _custom = _custom - &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:379:15 + --> tests/ui/arithmetic_side_effects.rs:383:15 | LL | _custom = Custom - _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:380:15 + --> tests/ui/arithmetic_side_effects.rs:384:15 | LL | _custom = &Custom - _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:381:15 + --> tests/ui/arithmetic_side_effects.rs:385:15 | LL | _custom = _custom / Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:382:15 + --> tests/ui/arithmetic_side_effects.rs:386:15 | LL | _custom = _custom / &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:383:15 + --> tests/ui/arithmetic_side_effects.rs:387:15 | LL | _custom = _custom % Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:384:15 + --> tests/ui/arithmetic_side_effects.rs:388:15 | LL | _custom = _custom % &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:385:15 + --> tests/ui/arithmetic_side_effects.rs:389:15 | LL | _custom = _custom * Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:386:15 + --> tests/ui/arithmetic_side_effects.rs:390:15 | LL | _custom = _custom * &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:387:15 + --> tests/ui/arithmetic_side_effects.rs:391:15 | LL | _custom = Custom * _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:388:15 + --> tests/ui/arithmetic_side_effects.rs:392:15 | LL | _custom = &Custom * _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:389:15 + --> tests/ui/arithmetic_side_effects.rs:393:15 | LL | _custom = Custom + &Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:390:15 + --> tests/ui/arithmetic_side_effects.rs:394:15 | LL | _custom = &Custom + Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:391:15 + --> tests/ui/arithmetic_side_effects.rs:395:15 | LL | _custom = &Custom + &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:392:15 + --> tests/ui/arithmetic_side_effects.rs:396:15 | LL | _custom = _custom >> _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:393:15 + --> tests/ui/arithmetic_side_effects.rs:397:15 | LL | _custom = _custom >> &_custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:394:15 + --> tests/ui/arithmetic_side_effects.rs:398:15 | LL | _custom = Custom << _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:395:15 + --> tests/ui/arithmetic_side_effects.rs:399:15 | LL | _custom = &Custom << _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:398:23 + --> tests/ui/arithmetic_side_effects.rs:402:23 | LL | _n.saturating_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:399:21 + --> tests/ui/arithmetic_side_effects.rs:403:21 | LL | _n.wrapping_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:400:21 + --> tests/ui/arithmetic_side_effects.rs:404:21 | LL | _n.wrapping_rem(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:401:28 + --> tests/ui/arithmetic_side_effects.rs:405:28 | LL | _n.wrapping_rem_euclid(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:403:23 + --> tests/ui/arithmetic_side_effects.rs:407:23 | LL | _n.saturating_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:404:21 + --> tests/ui/arithmetic_side_effects.rs:408:21 | LL | _n.wrapping_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:405:21 + --> tests/ui/arithmetic_side_effects.rs:409:21 | LL | _n.wrapping_rem(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:406:28 + --> tests/ui/arithmetic_side_effects.rs:410:28 | LL | _n.wrapping_rem_euclid(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:409:10 + --> tests/ui/arithmetic_side_effects.rs:413:10 | LL | _n = -_n; | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:410:10 + --> tests/ui/arithmetic_side_effects.rs:414:10 | LL | _n = -&_n; | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:411:15 + --> tests/ui/arithmetic_side_effects.rs:415:15 | LL | _custom = -_custom; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:412:15 + --> tests/ui/arithmetic_side_effects.rs:416:15 | LL | _custom = -&_custom; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:421:5 + --> tests/ui/arithmetic_side_effects.rs:425:5 | LL | 1 + i; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:422:5 + --> tests/ui/arithmetic_side_effects.rs:426:5 | LL | i * 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:423:5 + --> tests/ui/arithmetic_side_effects.rs:427:5 | LL | 1 % i / 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:424:5 + --> tests/ui/arithmetic_side_effects.rs:428:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:425:5 + --> tests/ui/arithmetic_side_effects.rs:429:5 | LL | -i; | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:436:5 + --> tests/ui/arithmetic_side_effects.rs:440:5 | LL | i += 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:437:5 + --> tests/ui/arithmetic_side_effects.rs:441:5 | LL | i -= 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:438:5 + --> tests/ui/arithmetic_side_effects.rs:442:5 | LL | i *= 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:440:5 + --> tests/ui/arithmetic_side_effects.rs:444:5 | LL | i /= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:442:5 + --> tests/ui/arithmetic_side_effects.rs:446:5 | LL | i /= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:443:5 + --> tests/ui/arithmetic_side_effects.rs:447:5 | LL | i /= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:445:5 + --> tests/ui/arithmetic_side_effects.rs:449:5 | LL | i %= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:447:5 + --> tests/ui/arithmetic_side_effects.rs:451:5 | LL | i %= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:448:5 + --> tests/ui/arithmetic_side_effects.rs:452:5 | LL | i %= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:458:5 + --> tests/ui/arithmetic_side_effects.rs:462:5 | LL | 10 / a | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:512:9 + --> tests/ui/arithmetic_side_effects.rs:516:9 | LL | x / maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:516:9 + --> tests/ui/arithmetic_side_effects.rs:520:9 | LL | x % maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:527:5 + --> tests/ui/arithmetic_side_effects.rs:531:5 | LL | one.add_assign(1); | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:531:5 + --> tests/ui/arithmetic_side_effects.rs:535:5 | LL | one.sub_assign(1); | ^^^^^^^^^^^^^^^^^ -error: aborting due to 121 previous errors +error: aborting due to 123 previous errors diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr index 73255651abe..b15857c325a 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr +++ b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr @@ -62,7 +62,7 @@ LL | } LL | match s.len() { LL ~ 10 => 2, LL | 20 => { - ... +... LL | if foo() { LL ~ return 20; LL | } diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs index 453d62ce607..c39f65a43e3 100644 --- a/src/tools/clippy/tests/ui/cast.rs +++ b/src/tools/clippy/tests/ui/cast.rs @@ -17,6 +17,8 @@ clippy::identity_op )] +// FIXME(f16_f128): add tests once const casting is available for these types + fn main() { // Test clippy::cast_precision_loss let x0 = 1i32; diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr index 43c0d8f4ed7..452482fc88e 100644 --- a/src/tools/clippy/tests/ui/cast.stderr +++ b/src/tools/clippy/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:23:5 + --> tests/ui/cast.rs:25:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -8,37 +8,37 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:27:5 + --> tests/ui/cast.rs:29:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:29:5 + --> tests/ui/cast.rs:31:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:32:5 + --> tests/ui/cast.rs:34:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:35:5 + --> tests/ui/cast.rs:37:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:37:5 + --> tests/ui/cast.rs:39:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:40:5 + --> tests/ui/cast.rs:42:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | 1f32 as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:42:5 + --> tests/ui/cast.rs:44:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | 1f32 as u32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:42:5 + --> tests/ui/cast.rs:44:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | 1f32 as u32; = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]` error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:46:5 + --> tests/ui/cast.rs:48:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | 1f64 as f32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:48:5 + --> tests/ui/cast.rs:50:5 | LL | 1i32 as i8; | ^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | i8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u8` may truncate the value - --> tests/ui/cast.rs:50:5 + --> tests/ui/cast.rs:52:5 | LL | 1i32 as u8; | ^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | u8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `f64` to `isize` may truncate the value - --> tests/ui/cast.rs:52:5 + --> tests/ui/cast.rs:54:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | 1f64 as isize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may truncate the value - --> tests/ui/cast.rs:54:5 + --> tests/ui/cast.rs:56:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ @@ -113,13 +113,13 @@ LL | 1f64 as usize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:54:5 + --> tests/ui/cast.rs:56:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u32` to `u16` may truncate the value - --> tests/ui/cast.rs:57:5 + --> tests/ui/cast.rs:59:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | u16::try_from(1f32 as u32); | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:57:5 + --> tests/ui/cast.rs:59:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ @@ -139,13 +139,13 @@ LL | 1f32 as u32 as u16; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:57:5 + --> tests/ui/cast.rs:59:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:62:22 + --> tests/ui/cast.rs:64:22 | LL | let _x: i8 = 1i32 as _; | ^^^^^^^^^ @@ -157,7 +157,7 @@ LL | let _x: i8 = 1i32.try_into(); | ~~~~~~~~~~~~~~~ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:64:9 + --> tests/ui/cast.rs:66:9 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | 1f32 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `i32` may truncate the value - --> tests/ui/cast.rs:66:9 + --> tests/ui/cast.rs:68:9 | LL | 1f64 as i32; | ^^^^^^^^^^^ @@ -173,7 +173,7 @@ LL | 1f64 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may truncate the value - --> tests/ui/cast.rs:68:9 + --> tests/ui/cast.rs:70:9 | LL | 1f32 as u8; | ^^^^^^^^^^ @@ -181,13 +181,13 @@ LL | 1f32 as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:68:9 + --> tests/ui/cast.rs:70:9 | LL | 1f32 as u8; | ^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> tests/ui/cast.rs:73:5 + --> tests/ui/cast.rs:75:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -196,31 +196,31 @@ LL | 1u8 as i8; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `u16` to `i16` may wrap around the value - --> tests/ui/cast.rs:76:5 + --> tests/ui/cast.rs:78:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> tests/ui/cast.rs:78:5 + --> tests/ui/cast.rs:80:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> tests/ui/cast.rs:80:5 + --> tests/ui/cast.rs:82:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> tests/ui/cast.rs:82:5 + --> tests/ui/cast.rs:84:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `usize` to `i8` may truncate the value - --> tests/ui/cast.rs:85:5 + --> tests/ui/cast.rs:87:5 | LL | 1usize as i8; | ^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL | i8::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may truncate the value - --> tests/ui/cast.rs:88:5 + --> tests/ui/cast.rs:90:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL | i16::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:88:5 + --> tests/ui/cast.rs:90:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | 1usize as i16; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:93:5 + --> tests/ui/cast.rs:95:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -265,19 +265,19 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:93:5 + --> tests/ui/cast.rs:95:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:97:5 + --> tests/ui/cast.rs:99:5 | LL | 1usize as i64; | ^^^^^^^^^^^^^ error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:102:5 + --> tests/ui/cast.rs:104:5 | LL | 1u16 as isize; | ^^^^^^^^^^^^^ @@ -286,13 +286,13 @@ LL | 1u16 as isize; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:106:5 + --> tests/ui/cast.rs:108:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:109:5 + --> tests/ui/cast.rs:111:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -304,55 +304,55 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:109:5 + --> tests/ui/cast.rs:111:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:114:5 + --> tests/ui/cast.rs:116:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:117:5 + --> tests/ui/cast.rs:119:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i8` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:128:5 + --> tests/ui/cast.rs:130:5 | LL | (i8::MIN).abs() as u8; | ^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:132:5 + --> tests/ui/cast.rs:134:5 | LL | (-1i64).abs() as u64; | ^^^^^^^^^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:133:5 + --> tests/ui/cast.rs:135:5 | LL | (-1isize).abs() as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:140:5 + --> tests/ui/cast.rs:142:5 | LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:155:5 + --> tests/ui/cast.rs:157:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> tests/ui/cast.rs:206:5 + --> tests/ui/cast.rs:208:5 | LL | (-99999999999i64).min(1) as i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL | i8::try_from((-99999999999i64).min(1)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:220:5 + --> tests/ui/cast.rs:222:5 | LL | 999999u64.clamp(0, 256) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> tests/ui/cast.rs:243:21 + --> tests/ui/cast.rs:245:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -388,7 +388,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> tests/ui/cast.rs:245:21 + --> tests/ui/cast.rs:247:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -397,7 +397,7 @@ LL | let _ = Self::B as u8; = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]` error: casting `main::E5` to `i8` may truncate the value - --> tests/ui/cast.rs:287:21 + --> tests/ui/cast.rs:289:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -409,13 +409,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> tests/ui/cast.rs:289:21 + --> tests/ui/cast.rs:291:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> tests/ui/cast.rs:306:21 + --> tests/ui/cast.rs:308:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:325:21 + --> tests/ui/cast.rs:327:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -439,7 +439,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> tests/ui/cast.rs:372:21 + --> tests/ui/cast.rs:374:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -451,7 +451,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:383:13 + --> tests/ui/cast.rs:385:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -463,7 +463,7 @@ LL | let c = u8::try_from(q >> 16); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:387:13 + --> tests/ui/cast.rs:389:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -475,85 +475,85 @@ LL | let c = u8::try_from(q / 1000); | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:399:9 + --> tests/ui/cast.rs:401:9 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:404:32 + --> tests/ui/cast.rs:406:32 | LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:406:5 + --> tests/ui/cast.rs:408:5 | LL | (2_i32).checked_pow(3).unwrap() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:407:5 + --> tests/ui/cast.rs:409:5 | LL | (-2_i32).pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:412:5 + --> tests/ui/cast.rs:414:5 | LL | (-5_i32 % 2) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:414:5 + --> tests/ui/cast.rs:416:5 | LL | (-5_i32 % -2) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:417:5 + --> tests/ui/cast.rs:419:5 | LL | (-2_i32 >> 1) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:421:5 + --> tests/ui/cast.rs:423:5 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:422:5 + --> tests/ui/cast.rs:424:5 | LL | (x * x * x) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:426:5 + --> tests/ui/cast.rs:428:5 | LL | (y * y * y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:428:5 + --> tests/ui/cast.rs:430:5 | LL | (y * y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:429:5 + --> tests/ui/cast.rs:431:5 | LL | (y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:431:5 + --> tests/ui/cast.rs:433:5 | LL | (y / y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `/` - --> tests/ui/cast.rs:431:6 + --> tests/ui/cast.rs:433:6 | LL | (y / y * y * -2) as u16; | ^^^^^ @@ -561,97 +561,97 @@ LL | (y / y * y * -2) as u16; = note: `#[deny(clippy::eq_op)]` on by default error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:434:5 + --> tests/ui/cast.rs:436:5 | LL | (y + y + y + -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:436:5 + --> tests/ui/cast.rs:438:5 | LL | (y + y + y + 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:440:5 + --> tests/ui/cast.rs:442:5 | LL | (z + -2) as u16; | ^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:442:5 + --> tests/ui/cast.rs:444:5 | LL | (z + z + 2) as u16; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:445:9 + --> tests/ui/cast.rs:447:9 | LL | (a * a * b * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:446:9 + --> tests/ui/cast.rs:448:9 | LL | (a * b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:448:9 + --> tests/ui/cast.rs:450:9 | LL | (a * -b * c) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:450:9 + --> tests/ui/cast.rs:452:9 | LL | (a * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:451:9 + --> tests/ui/cast.rs:453:9 | LL | (a * -2) as u32; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:453:9 + --> tests/ui/cast.rs:455:9 | LL | (a * b * c * -2) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:455:9 + --> tests/ui/cast.rs:457:9 | LL | (a / b) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:456:9 + --> tests/ui/cast.rs:458:9 | LL | (a / b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:458:9 + --> tests/ui/cast.rs:460:9 | LL | (a / b + b * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:460:9 + --> tests/ui/cast.rs:462:9 | LL | a.saturating_pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:462:9 + --> tests/ui/cast.rs:464:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:470:21 + --> tests/ui/cast.rs:472:21 | LL | let _ = i32::MIN as u32; // cast_sign_loss | ^^^^^^^^^^^^^^^ @@ -662,7 +662,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:471:21 + --> tests/ui/cast.rs:473:21 | LL | let _ = u32::MAX as u8; // cast_possible_truncation | ^^^^^^^^^^^^^^ @@ -678,7 +678,7 @@ LL | let _ = u8::try_from(u32::MAX); // cast_possible_truncation | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:472:21 + --> tests/ui/cast.rs:474:21 | LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -690,7 +690,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:481:5 + --> tests/ui/cast.rs:483:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -702,13 +702,13 @@ LL | usize::try_from(bar.unwrap().unwrap()) | error: casting `i64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:481:5 + --> tests/ui/cast.rs:483:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:496:5 + --> tests/ui/cast.rs:498:5 | LL | (256 & 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -720,7 +720,7 @@ LL | u8::try_from(256 & 999999u64); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:498:5 + --> tests/ui/cast.rs:500:5 | LL | (255 % 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.fixed b/src/tools/clippy/tests/ui/cast_lossless_float.fixed index 96a67b1945c..163432631e1 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_float.fixed +++ b/src/tools/clippy/tests/ui/cast_lossless_float.fixed @@ -1,6 +1,8 @@ #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] +// FIXME(f16_f128): add tests for these types once const casting is available + type F32 = f32; type F64 = f64; diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.rs b/src/tools/clippy/tests/ui/cast_lossless_float.rs index d37b2c1d920..afb2a3d890e 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_float.rs +++ b/src/tools/clippy/tests/ui/cast_lossless_float.rs @@ -1,6 +1,8 @@ #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] +// FIXME(f16_f128): add tests for these types once const casting is available + type F32 = f32; type F64 = f64; diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.stderr b/src/tools/clippy/tests/ui/cast_lossless_float.stderr index ad7de760adf..f2ba4e3b990 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_float.stderr +++ b/src/tools/clippy/tests/ui/cast_lossless_float.stderr @@ -1,5 +1,5 @@ error: casting `i8` to `f32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:10:13 + --> tests/ui/cast_lossless_float.rs:12:13 | LL | let _ = x0 as f32; | ^^^^^^^^^ help: try: `f32::from(x0)` @@ -8,73 +8,73 @@ LL | let _ = x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]` error: casting `i8` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:11:13 + --> tests/ui/cast_lossless_float.rs:13:13 | LL | let _ = x0 as f64; | ^^^^^^^^^ help: try: `f64::from(x0)` error: casting `i8` to `F32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:12:13 + --> tests/ui/cast_lossless_float.rs:14:13 | LL | let _ = x0 as F32; | ^^^^^^^^^ help: try: `F32::from(x0)` error: casting `i8` to `F64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:13:13 + --> tests/ui/cast_lossless_float.rs:15:13 | LL | let _ = x0 as F64; | ^^^^^^^^^ help: try: `F64::from(x0)` error: casting `u8` to `f32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:15:13 + --> tests/ui/cast_lossless_float.rs:17:13 | LL | let _ = x1 as f32; | ^^^^^^^^^ help: try: `f32::from(x1)` error: casting `u8` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:16:13 + --> tests/ui/cast_lossless_float.rs:18:13 | LL | let _ = x1 as f64; | ^^^^^^^^^ help: try: `f64::from(x1)` error: casting `i16` to `f32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:18:13 + --> tests/ui/cast_lossless_float.rs:20:13 | LL | let _ = x2 as f32; | ^^^^^^^^^ help: try: `f32::from(x2)` error: casting `i16` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:19:13 + --> tests/ui/cast_lossless_float.rs:21:13 | LL | let _ = x2 as f64; | ^^^^^^^^^ help: try: `f64::from(x2)` error: casting `u16` to `f32` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:21:13 + --> tests/ui/cast_lossless_float.rs:23:13 | LL | let _ = x3 as f32; | ^^^^^^^^^ help: try: `f32::from(x3)` error: casting `u16` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:22:13 + --> tests/ui/cast_lossless_float.rs:24:13 | LL | let _ = x3 as f64; | ^^^^^^^^^ help: try: `f64::from(x3)` error: casting `i32` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:24:13 + --> tests/ui/cast_lossless_float.rs:26:13 | LL | let _ = x4 as f64; | ^^^^^^^^^ help: try: `f64::from(x4)` error: casting `u32` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:26:13 + --> tests/ui/cast_lossless_float.rs:28:13 | LL | let _ = x5 as f64; | ^^^^^^^^^ help: try: `f64::from(x5)` error: casting `f32` to `f64` may become silently lossy if you later change the type - --> tests/ui/cast_lossless_float.rs:29:13 + --> tests/ui/cast_lossless_float.rs:31:13 | LL | let _ = 1.0f32 as f64; | ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)` diff --git a/src/tools/clippy/tests/ui/cast_nan_to_int.rs b/src/tools/clippy/tests/ui/cast_nan_to_int.rs index 2d7467ff040..aee38da9a15 100644 --- a/src/tools/clippy/tests/ui/cast_nan_to_int.rs +++ b/src/tools/clippy/tests/ui/cast_nan_to_int.rs @@ -1,3 +1,5 @@ +// FIXME(f16_f128): add tests when constants are available + #![warn(clippy::cast_nan_to_int)] #![allow(clippy::eq_op)] diff --git a/src/tools/clippy/tests/ui/cast_nan_to_int.stderr b/src/tools/clippy/tests/ui/cast_nan_to_int.stderr index 3cb46d1e79b..3aeb2d54525 100644 --- a/src/tools/clippy/tests/ui/cast_nan_to_int.stderr +++ b/src/tools/clippy/tests/ui/cast_nan_to_int.stderr @@ -1,5 +1,5 @@ error: casting a known NaN to usize - --> tests/ui/cast_nan_to_int.rs:5:13 + --> tests/ui/cast_nan_to_int.rs:7:13 | LL | let _ = (0.0_f32 / -0.0) as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | let _ = (0.0_f32 / -0.0) as usize; = help: to override `-D warnings` add `#[allow(clippy::cast_nan_to_int)]` error: casting a known NaN to usize - --> tests/ui/cast_nan_to_int.rs:8:13 + --> tests/ui/cast_nan_to_int.rs:10:13 | LL | let _ = (f64::INFINITY * -0.0) as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let _ = (f64::INFINITY * -0.0) as usize; = note: this always evaluates to 0 error: casting a known NaN to usize - --> tests/ui/cast_nan_to_int.rs:11:13 + --> tests/ui/cast_nan_to_int.rs:13:13 | LL | let _ = (0.0 * f32::INFINITY) as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = (0.0 * f32::INFINITY) as usize; = note: this always evaluates to 0 error: casting a known NaN to usize - --> tests/ui/cast_nan_to_int.rs:15:13 + --> tests/ui/cast_nan_to_int.rs:17:13 | LL | let _ = (f64::INFINITY + f64::NEG_INFINITY) as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let _ = (f64::INFINITY + f64::NEG_INFINITY) as usize; = note: this always evaluates to 0 error: casting a known NaN to usize - --> tests/ui/cast_nan_to_int.rs:18:13 + --> tests/ui/cast_nan_to_int.rs:20:13 | LL | let _ = (f32::INFINITY - f32::INFINITY) as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | let _ = (f32::INFINITY - f32::INFINITY) as usize; = note: this always evaluates to 0 error: casting a known NaN to usize - --> tests/ui/cast_nan_to_int.rs:21:13 + --> tests/ui/cast_nan_to_int.rs:23:13 | LL | let _ = (f32::INFINITY / f32::NEG_INFINITY) as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cast_size.64bit.stderr b/src/tools/clippy/tests/ui/cast_size.64bit.stderr index 0dc4ca91529..bc37107d80e 100644 --- a/src/tools/clippy/tests/ui/cast_size.64bit.stderr +++ b/src/tools/clippy/tests/ui/cast_size.64bit.stderr @@ -12,35 +12,35 @@ help: ... or use `try_from` and handle the error accordingly LL | i8::try_from(1isize); | ~~~~~~~~~~~~~~~~~~~~ -error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:18:5 +error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) + --> tests/ui/cast_size.rs:21:5 | -LL | x0 as f64; +LL | x0 as f32; | ^^^^^^^^^ | = note: `-D clippy::cast-precision-loss` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` -error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:19:5 +error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) + --> tests/ui/cast_size.rs:22:5 | -LL | x1 as f64; +LL | x1 as f32; | ^^^^^^^^^ -error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast_size.rs:20:5 +error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) + --> tests/ui/cast_size.rs:23:5 | -LL | x0 as f32; +LL | x0 as f64; | ^^^^^^^^^ -error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast_size.rs:21:5 +error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) + --> tests/ui/cast_size.rs:24:5 | -LL | x1 as f32; +LL | x1 as f64; | ^^^^^^^^^ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:22:5 + --> tests/ui/cast_size.rs:28:5 | LL | 1isize as i32; | ^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | i32::try_from(1isize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:23:5 + --> tests/ui/cast_size.rs:29:5 | LL | 1isize as u32; | ^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | u32::try_from(1isize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:24:5 + --> tests/ui/cast_size.rs:30:5 | LL | 1usize as u32; | ^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | u32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:25:5 + --> tests/ui/cast_size.rs:31:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:25:5 + --> tests/ui/cast_size.rs:31:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | 1usize as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `i64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:26:5 + --> tests/ui/cast_size.rs:32:5 | LL | 1i64 as isize; | ^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | isize::try_from(1i64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:27:5 + --> tests/ui/cast_size.rs:33:5 | LL | 1i64 as usize; | ^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | usize::try_from(1i64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:28:5 + --> tests/ui/cast_size.rs:34:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -133,13 +133,13 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:28:5 + --> tests/ui/cast_size.rs:34:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:29:5 + --> tests/ui/cast_size.rs:35:5 | LL | 1u64 as usize; | ^^^^^^^^^^^^^ @@ -151,19 +151,19 @@ LL | usize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:30:5 + --> tests/ui/cast_size.rs:36:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast_size.rs:35:5 + --> tests/ui/cast_size.rs:43:5 | LL | 999_999_999 as f32; | ^^^^^^^^^^^^^^^^^^ error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:36:5 + --> tests/ui/cast_size.rs:44:5 | LL | 9_999_999_999_999_999usize as f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cast_size.rs b/src/tools/clippy/tests/ui/cast_size.rs index d063a70ccdf..d0ed8e57d7a 100644 --- a/src/tools/clippy/tests/ui/cast_size.rs +++ b/src/tools/clippy/tests/ui/cast_size.rs @@ -15,10 +15,16 @@ fn main() { 1isize as i8; let x0 = 1isize; let x1 = 1usize; - x0 as f64; - x1 as f64; + // FIXME(f16_f128): enable f16 and f128 conversions once const eval supports them + // x0 as f16; + // x1 as f16; x0 as f32; x1 as f32; + x0 as f64; + x1 as f64; + // x0 as f128; + // x1 as f128; + 1isize as i32; 1isize as u32; 1usize as u32; @@ -31,7 +37,10 @@ fn main() { 1u32 as usize; // Should not trigger any lint 1i32 as isize; // Neither should this 1i32 as usize; + // Big integer literal to float + // 999_999 as f16; 999_999_999 as f32; 9_999_999_999_999_999usize as f64; + // 999_999_999_999_999_999_999_999_999_999u128 as f128; } diff --git a/src/tools/clippy/tests/ui/endian_bytes.rs b/src/tools/clippy/tests/ui/endian_bytes.rs index 6bf014fc809..580fc2fc24d 100644 --- a/src/tools/clippy/tests/ui/endian_bytes.rs +++ b/src/tools/clippy/tests/ui/endian_bytes.rs @@ -2,6 +2,8 @@ #![allow(clippy::diverging_sub_expression)] #![no_main] +// FIXME(f16_f128): add these types when `{to_from}_*_bytes` are available + macro_rules! fn_body { () => { 2u8.to_ne_bytes(); diff --git a/src/tools/clippy/tests/ui/endian_bytes.stderr b/src/tools/clippy/tests/ui/endian_bytes.stderr index 3fc26dcab88..fd19ec45872 100644 --- a/src/tools/clippy/tests/ui/endian_bytes.stderr +++ b/src/tools/clippy/tests/ui/endian_bytes.stderr @@ -1,5 +1,5 @@ error: usage of the `u8::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:7:9 + --> tests/ui/endian_bytes.rs:9:9 | LL | 2u8.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i8::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:8:9 + --> tests/ui/endian_bytes.rs:10:9 | LL | 2i8.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u16::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:9:9 + --> tests/ui/endian_bytes.rs:11:9 | LL | 2u16.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i16::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:10:9 + --> tests/ui/endian_bytes.rs:12:9 | LL | 2i16.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u32::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:11:9 + --> tests/ui/endian_bytes.rs:13:9 | LL | 2u32.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i32::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:12:9 + --> tests/ui/endian_bytes.rs:14:9 | LL | 2i32.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u64::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:13:9 + --> tests/ui/endian_bytes.rs:15:9 | LL | 2u64.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i64::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:14:9 + --> tests/ui/endian_bytes.rs:16:9 | LL | 2i64.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u128::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:15:9 + --> tests/ui/endian_bytes.rs:17:9 | LL | 2u128.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i128::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:16:9 + --> tests/ui/endian_bytes.rs:18:9 | LL | 2i128.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `f32::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:17:9 + --> tests/ui/endian_bytes.rs:19:9 | LL | 2.0f32.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `f64::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:18:9 + --> tests/ui/endian_bytes.rs:20:9 | LL | 2.0f64.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `usize::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:19:9 + --> tests/ui/endian_bytes.rs:21:9 | LL | 2usize.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `isize::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:20:9 + --> tests/ui/endian_bytes.rs:22:9 | LL | 2isize.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:21:9 + --> tests/ui/endian_bytes.rs:23:9 | LL | u8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:22:9 + --> tests/ui/endian_bytes.rs:24:9 | LL | i8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u16::from_ne_bytes` - --> tests/ui/endian_bytes.rs:23:9 + --> tests/ui/endian_bytes.rs:25:9 | LL | u16::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -205,7 +205,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i16::from_ne_bytes` - --> tests/ui/endian_bytes.rs:24:9 + --> tests/ui/endian_bytes.rs:26:9 | LL | i16::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u32::from_ne_bytes` - --> tests/ui/endian_bytes.rs:25:9 + --> tests/ui/endian_bytes.rs:27:9 | LL | u32::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i32::from_ne_bytes` - --> tests/ui/endian_bytes.rs:26:9 + --> tests/ui/endian_bytes.rs:28:9 | LL | i32::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u64::from_ne_bytes` - --> tests/ui/endian_bytes.rs:27:9 + --> tests/ui/endian_bytes.rs:29:9 | LL | u64::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i64::from_ne_bytes` - --> tests/ui/endian_bytes.rs:28:9 + --> tests/ui/endian_bytes.rs:30:9 | LL | i64::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -265,7 +265,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u128::from_ne_bytes` - --> tests/ui/endian_bytes.rs:29:9 + --> tests/ui/endian_bytes.rs:31:9 | LL | u128::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -277,7 +277,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i128::from_ne_bytes` - --> tests/ui/endian_bytes.rs:30:9 + --> tests/ui/endian_bytes.rs:32:9 | LL | i128::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -289,7 +289,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `usize::from_ne_bytes` - --> tests/ui/endian_bytes.rs:31:9 + --> tests/ui/endian_bytes.rs:33:9 | LL | usize::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -301,7 +301,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `isize::from_ne_bytes` - --> tests/ui/endian_bytes.rs:32:9 + --> tests/ui/endian_bytes.rs:34:9 | LL | isize::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `f32::from_ne_bytes` - --> tests/ui/endian_bytes.rs:33:9 + --> tests/ui/endian_bytes.rs:35:9 | LL | f32::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -325,7 +325,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `f64::from_ne_bytes` - --> tests/ui/endian_bytes.rs:34:9 + --> tests/ui/endian_bytes.rs:36:9 | LL | f64::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:36:9 + --> tests/ui/endian_bytes.rs:38:9 | LL | 2u8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -351,7 +351,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:37:9 + --> tests/ui/endian_bytes.rs:39:9 | LL | 2i8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -363,7 +363,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u16::to_le_bytes` method - --> tests/ui/endian_bytes.rs:38:9 + --> tests/ui/endian_bytes.rs:40:9 | LL | 2u16.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -375,7 +375,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i16::to_le_bytes` method - --> tests/ui/endian_bytes.rs:39:9 + --> tests/ui/endian_bytes.rs:41:9 | LL | 2i16.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -387,7 +387,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u32::to_le_bytes` method - --> tests/ui/endian_bytes.rs:40:9 + --> tests/ui/endian_bytes.rs:42:9 | LL | 2u32.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -399,7 +399,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i32::to_le_bytes` method - --> tests/ui/endian_bytes.rs:41:9 + --> tests/ui/endian_bytes.rs:43:9 | LL | 2i32.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -411,7 +411,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u64::to_le_bytes` method - --> tests/ui/endian_bytes.rs:42:9 + --> tests/ui/endian_bytes.rs:44:9 | LL | 2u64.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -423,7 +423,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i64::to_le_bytes` method - --> tests/ui/endian_bytes.rs:43:9 + --> tests/ui/endian_bytes.rs:45:9 | LL | 2i64.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -435,7 +435,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u128::to_le_bytes` method - --> tests/ui/endian_bytes.rs:44:9 + --> tests/ui/endian_bytes.rs:46:9 | LL | 2u128.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^^ @@ -447,7 +447,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i128::to_le_bytes` method - --> tests/ui/endian_bytes.rs:45:9 + --> tests/ui/endian_bytes.rs:47:9 | LL | 2i128.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^^ @@ -459,7 +459,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `f32::to_le_bytes` method - --> tests/ui/endian_bytes.rs:46:9 + --> tests/ui/endian_bytes.rs:48:9 | LL | 2.0f32.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -471,7 +471,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `f64::to_le_bytes` method - --> tests/ui/endian_bytes.rs:47:9 + --> tests/ui/endian_bytes.rs:49:9 | LL | 2.0f64.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -483,7 +483,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `usize::to_le_bytes` method - --> tests/ui/endian_bytes.rs:48:9 + --> tests/ui/endian_bytes.rs:50:9 | LL | 2usize.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -495,7 +495,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `isize::to_le_bytes` method - --> tests/ui/endian_bytes.rs:49:9 + --> tests/ui/endian_bytes.rs:51:9 | LL | 2isize.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -507,7 +507,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_le_bytes` - --> tests/ui/endian_bytes.rs:50:9 + --> tests/ui/endian_bytes.rs:52:9 | LL | u8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -519,7 +519,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i8::from_le_bytes` - --> tests/ui/endian_bytes.rs:51:9 + --> tests/ui/endian_bytes.rs:53:9 | LL | i8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -531,7 +531,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u16::from_le_bytes` - --> tests/ui/endian_bytes.rs:52:9 + --> tests/ui/endian_bytes.rs:54:9 | LL | u16::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -543,7 +543,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i16::from_le_bytes` - --> tests/ui/endian_bytes.rs:53:9 + --> tests/ui/endian_bytes.rs:55:9 | LL | i16::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -555,7 +555,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u32::from_le_bytes` - --> tests/ui/endian_bytes.rs:54:9 + --> tests/ui/endian_bytes.rs:56:9 | LL | u32::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -567,7 +567,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i32::from_le_bytes` - --> tests/ui/endian_bytes.rs:55:9 + --> tests/ui/endian_bytes.rs:57:9 | LL | i32::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -579,7 +579,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u64::from_le_bytes` - --> tests/ui/endian_bytes.rs:56:9 + --> tests/ui/endian_bytes.rs:58:9 | LL | u64::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -591,7 +591,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i64::from_le_bytes` - --> tests/ui/endian_bytes.rs:57:9 + --> tests/ui/endian_bytes.rs:59:9 | LL | i64::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -603,7 +603,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u128::from_le_bytes` - --> tests/ui/endian_bytes.rs:58:9 + --> tests/ui/endian_bytes.rs:60:9 | LL | u128::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -615,7 +615,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i128::from_le_bytes` - --> tests/ui/endian_bytes.rs:59:9 + --> tests/ui/endian_bytes.rs:61:9 | LL | i128::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -627,7 +627,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `usize::from_le_bytes` - --> tests/ui/endian_bytes.rs:60:9 + --> tests/ui/endian_bytes.rs:62:9 | LL | usize::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -639,7 +639,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `isize::from_le_bytes` - --> tests/ui/endian_bytes.rs:61:9 + --> tests/ui/endian_bytes.rs:63:9 | LL | isize::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -651,7 +651,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `f32::from_le_bytes` - --> tests/ui/endian_bytes.rs:62:9 + --> tests/ui/endian_bytes.rs:64:9 | LL | f32::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -663,7 +663,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `f64::from_le_bytes` - --> tests/ui/endian_bytes.rs:63:9 + --> tests/ui/endian_bytes.rs:65:9 | LL | f64::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -675,7 +675,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:70:9 + --> tests/ui/endian_bytes.rs:72:9 | LL | 2u8.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -687,7 +687,7 @@ LL | fn host_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:71:9 + --> tests/ui/endian_bytes.rs:73:9 | LL | u8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -699,7 +699,7 @@ LL | fn host_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_be_bytes` method - --> tests/ui/endian_bytes.rs:76:9 + --> tests/ui/endian_bytes.rs:78:9 | LL | 2u8.to_be_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -713,7 +713,7 @@ LL | fn host_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_be_bytes` - --> tests/ui/endian_bytes.rs:77:9 + --> tests/ui/endian_bytes.rs:79:9 | LL | u8::from_be_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -725,7 +725,7 @@ LL | fn host_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:70:9 + --> tests/ui/endian_bytes.rs:72:9 | LL | 2u8.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -737,7 +737,7 @@ LL | fn host_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:71:9 + --> tests/ui/endian_bytes.rs:73:9 | LL | u8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -749,7 +749,7 @@ LL | fn host_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:73:9 + --> tests/ui/endian_bytes.rs:75:9 | LL | 2u8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -761,7 +761,7 @@ LL | fn host_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_le_bytes` - --> tests/ui/endian_bytes.rs:74:9 + --> tests/ui/endian_bytes.rs:76:9 | LL | u8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -773,7 +773,7 @@ LL | fn host_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:70:9 + --> tests/ui/endian_bytes.rs:72:9 | LL | 2u8.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -784,7 +784,7 @@ LL | fn no_help() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:71:9 + --> tests/ui/endian_bytes.rs:73:9 | LL | u8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -795,7 +795,7 @@ LL | fn no_help() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:73:9 + --> tests/ui/endian_bytes.rs:75:9 | LL | 2u8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -806,7 +806,7 @@ LL | fn no_help() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_le_bytes` - --> tests/ui/endian_bytes.rs:74:9 + --> tests/ui/endian_bytes.rs:76:9 | LL | u8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -817,7 +817,7 @@ LL | fn no_help() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_be_bytes` method - --> tests/ui/endian_bytes.rs:76:9 + --> tests/ui/endian_bytes.rs:78:9 | LL | 2u8.to_be_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -828,7 +828,7 @@ LL | fn no_help() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_be_bytes` - --> tests/ui/endian_bytes.rs:77:9 + --> tests/ui/endian_bytes.rs:79:9 | LL | u8::from_be_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -839,7 +839,7 @@ LL | fn no_help() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:73:9 + --> tests/ui/endian_bytes.rs:75:9 | LL | 2u8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -851,7 +851,7 @@ LL | fn little_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_le_bytes` - --> tests/ui/endian_bytes.rs:74:9 + --> tests/ui/endian_bytes.rs:76:9 | LL | u8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -863,7 +863,7 @@ LL | fn little_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_be_bytes` method - --> tests/ui/endian_bytes.rs:76:9 + --> tests/ui/endian_bytes.rs:78:9 | LL | 2u8.to_be_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -875,7 +875,7 @@ LL | fn little_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_be_bytes` - --> tests/ui/endian_bytes.rs:77:9 + --> tests/ui/endian_bytes.rs:79:9 | LL | u8::from_be_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -887,7 +887,7 @@ LL | fn little_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:70:9 + --> tests/ui/endian_bytes.rs:72:9 | LL | 2u8.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -899,7 +899,7 @@ LL | fn little_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:71:9 + --> tests/ui/endian_bytes.rs:73:9 | LL | u8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -911,7 +911,7 @@ LL | fn little_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:73:9 + --> tests/ui/endian_bytes.rs:75:9 | LL | 2u8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -923,7 +923,7 @@ LL | fn little_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_le_bytes` - --> tests/ui/endian_bytes.rs:74:9 + --> tests/ui/endian_bytes.rs:76:9 | LL | u8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -935,7 +935,7 @@ LL | fn little_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:73:9 + --> tests/ui/endian_bytes.rs:75:9 | LL | 2u8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -947,7 +947,7 @@ LL | fn big_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_le_bytes` - --> tests/ui/endian_bytes.rs:74:9 + --> tests/ui/endian_bytes.rs:76:9 | LL | u8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -959,7 +959,7 @@ LL | fn big_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_be_bytes` method - --> tests/ui/endian_bytes.rs:76:9 + --> tests/ui/endian_bytes.rs:78:9 | LL | 2u8.to_be_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -971,7 +971,7 @@ LL | fn big_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_be_bytes` - --> tests/ui/endian_bytes.rs:77:9 + --> tests/ui/endian_bytes.rs:79:9 | LL | u8::from_be_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -983,7 +983,7 @@ LL | fn big_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:70:9 + --> tests/ui/endian_bytes.rs:72:9 | LL | 2u8.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -995,7 +995,7 @@ LL | fn big_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:71:9 + --> tests/ui/endian_bytes.rs:73:9 | LL | u8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1007,7 +1007,7 @@ LL | fn big_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_be_bytes` method - --> tests/ui/endian_bytes.rs:76:9 + --> tests/ui/endian_bytes.rs:78:9 | LL | 2u8.to_be_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -1019,7 +1019,7 @@ LL | fn big_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_be_bytes` - --> tests/ui/endian_bytes.rs:77:9 + --> tests/ui/endian_bytes.rs:79:9 | LL | u8::from_be_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/float_cmp.rs b/src/tools/clippy/tests/ui/float_cmp.rs index 5057c643732..1923ad7c677 100644 --- a/src/tools/clippy/tests/ui/float_cmp.rs +++ b/src/tools/clippy/tests/ui/float_cmp.rs @@ -1,3 +1,5 @@ +// FIXME(f16_f128): const casting is not yet supported for these types. Add when available. + #![warn(clippy::float_cmp)] #![allow( unused, diff --git a/src/tools/clippy/tests/ui/float_cmp.stderr b/src/tools/clippy/tests/ui/float_cmp.stderr index 49b65184f73..c8a0bde6e63 100644 --- a/src/tools/clippy/tests/ui/float_cmp.stderr +++ b/src/tools/clippy/tests/ui/float_cmp.stderr @@ -1,5 +1,5 @@ error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:70:5 + --> tests/ui/float_cmp.rs:72:5 | LL | ONE as f64 != 2.0; | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin` @@ -9,7 +9,7 @@ LL | ONE as f64 != 2.0; = help: to override `-D warnings` add `#[allow(clippy::float_cmp)]` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:77:5 + --> tests/ui/float_cmp.rs:79:5 | LL | x == 1.0; | ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin` @@ -17,7 +17,7 @@ LL | x == 1.0; = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:82:5 + --> tests/ui/float_cmp.rs:84:5 | LL | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin` @@ -25,7 +25,7 @@ LL | twice(x) != twice(ONE as f64); = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:104:5 + --> tests/ui/float_cmp.rs:106:5 | LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin` @@ -33,7 +33,7 @@ LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` arrays - --> tests/ui/float_cmp.rs:111:5 + --> tests/ui/float_cmp.rs:113:5 | LL | a1 == a2; | ^^^^^^^^ @@ -41,7 +41,7 @@ LL | a1 == a2; = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:114:5 + --> tests/ui/float_cmp.rs:116:5 | LL | a1[0] == a2[0]; | ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin` diff --git a/src/tools/clippy/tests/ui/float_equality_without_abs.rs b/src/tools/clippy/tests/ui/float_equality_without_abs.rs index 6363472d899..2b67c8bec10 100644 --- a/src/tools/clippy/tests/ui/float_equality_without_abs.rs +++ b/src/tools/clippy/tests/ui/float_equality_without_abs.rs @@ -1,5 +1,8 @@ #![warn(clippy::float_equality_without_abs)] //@no-rustfix + +// FIXME(f16_f128): add tests for these types when abs is available + pub fn is_roughly_equal(a: f32, b: f32) -> bool { (a - b) < f32::EPSILON //~^ ERROR: float equality check without `.abs()` diff --git a/src/tools/clippy/tests/ui/float_equality_without_abs.stderr b/src/tools/clippy/tests/ui/float_equality_without_abs.stderr index 0124dd983a3..cdaaf0cdbcf 100644 --- a/src/tools/clippy/tests/ui/float_equality_without_abs.stderr +++ b/src/tools/clippy/tests/ui/float_equality_without_abs.stderr @@ -1,5 +1,5 @@ error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:4:5 + --> tests/ui/float_equality_without_abs.rs:7:5 | LL | (a - b) < f32::EPSILON | -------^^^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | (a - b) < f32::EPSILON = help: to override `-D warnings` add `#[allow(clippy::float_equality_without_abs)]` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:15:13 + --> tests/ui/float_equality_without_abs.rs:18:13 | LL | let _ = (a - b) < f32::EPSILON; | -------^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | let _ = (a - b) < f32::EPSILON; | help: add `.abs()`: `(a - b).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:17:13 + --> tests/ui/float_equality_without_abs.rs:20:13 | LL | let _ = a - b < f32::EPSILON; | -----^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | let _ = a - b < f32::EPSILON; | help: add `.abs()`: `(a - b).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:19:13 + --> tests/ui/float_equality_without_abs.rs:22:13 | LL | let _ = a - b.abs() < f32::EPSILON; | -----------^^^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | let _ = a - b.abs() < f32::EPSILON; | help: add `.abs()`: `(a - b.abs()).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:21:13 + --> tests/ui/float_equality_without_abs.rs:24:13 | LL | let _ = (a as f64 - b as f64) < f64::EPSILON; | ---------------------^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL | let _ = (a as f64 - b as f64) < f64::EPSILON; | help: add `.abs()`: `(a as f64 - b as f64).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:23:13 + --> tests/ui/float_equality_without_abs.rs:26:13 | LL | let _ = 1.0 - 2.0 < f32::EPSILON; | ---------^^^^^^^^^^^^^^^ @@ -50,7 +50,7 @@ LL | let _ = 1.0 - 2.0 < f32::EPSILON; | help: add `.abs()`: `(1.0 - 2.0).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:26:13 + --> tests/ui/float_equality_without_abs.rs:29:13 | LL | let _ = f32::EPSILON > (a - b); | ^^^^^^^^^^^^^^^------- @@ -58,7 +58,7 @@ LL | let _ = f32::EPSILON > (a - b); | help: add `.abs()`: `(a - b).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:28:13 + --> tests/ui/float_equality_without_abs.rs:31:13 | LL | let _ = f32::EPSILON > a - b; | ^^^^^^^^^^^^^^^----- @@ -66,7 +66,7 @@ LL | let _ = f32::EPSILON > a - b; | help: add `.abs()`: `(a - b).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:30:13 + --> tests/ui/float_equality_without_abs.rs:33:13 | LL | let _ = f32::EPSILON > a - b.abs(); | ^^^^^^^^^^^^^^^----------- @@ -74,7 +74,7 @@ LL | let _ = f32::EPSILON > a - b.abs(); | help: add `.abs()`: `(a - b.abs()).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:32:13 + --> tests/ui/float_equality_without_abs.rs:35:13 | LL | let _ = f64::EPSILON > (a as f64 - b as f64); | ^^^^^^^^^^^^^^^--------------------- @@ -82,7 +82,7 @@ LL | let _ = f64::EPSILON > (a as f64 - b as f64); | help: add `.abs()`: `(a as f64 - b as f64).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:34:13 + --> tests/ui/float_equality_without_abs.rs:37:13 | LL | let _ = f32::EPSILON > 1.0 - 2.0; | ^^^^^^^^^^^^^^^--------- diff --git a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs index a42c6383cce..47c113d61c0 100644 --- a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs +++ b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs @@ -3,8 +3,8 @@ #![warn(clippy::suboptimal_flops)] #![no_std] -// The following should not lint, as the suggested methods {f32,f64}.mul_add() -// and {f32,f64}::abs() are not available in no_std +// The following should not lint, as the suggested methods `{f16,f32,f64,f128}.mul_add()` +// and ``{f16,f32,f64,f128}::abs()` are not available in no_std pub fn mul_add() { let a: f64 = 1234.567; diff --git a/src/tools/clippy/tests/ui/floating_point_exp.fixed b/src/tools/clippy/tests/ui/floating_point_exp.fixed index 15072bb1ee9..fbd91cbc9d7 100644 --- a/src/tools/clippy/tests/ui/floating_point_exp.fixed +++ b/src/tools/clippy/tests/ui/floating_point_exp.fixed @@ -1,3 +1,5 @@ +// FIXME(f16_f128): add tests when exp is available + #![warn(clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/src/tools/clippy/tests/ui/floating_point_exp.rs b/src/tools/clippy/tests/ui/floating_point_exp.rs index 7d8b17946d0..340bacaf56b 100644 --- a/src/tools/clippy/tests/ui/floating_point_exp.rs +++ b/src/tools/clippy/tests/ui/floating_point_exp.rs @@ -1,3 +1,5 @@ +// FIXME(f16_f128): add tests when exp is available + #![warn(clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/src/tools/clippy/tests/ui/floating_point_exp.stderr b/src/tools/clippy/tests/ui/floating_point_exp.stderr index a19edf87e24..6ce67254abc 100644 --- a/src/tools/clippy/tests/ui/floating_point_exp.stderr +++ b/src/tools/clippy/tests/ui/floating_point_exp.stderr @@ -1,5 +1,5 @@ error: (e.pow(x) - 1) can be computed more accurately - --> tests/ui/floating_point_exp.rs:6:13 + --> tests/ui/floating_point_exp.rs:8:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` @@ -8,25 +8,25 @@ LL | let _ = x.exp() - 1.0; = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]` error: (e.pow(x) - 1) can be computed more accurately - --> tests/ui/floating_point_exp.rs:7:13 + --> tests/ui/floating_point_exp.rs:9:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> tests/ui/floating_point_exp.rs:8:13 + --> tests/ui/floating_point_exp.rs:10:13 | LL | let _ = (x as f32).exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> tests/ui/floating_point_exp.rs:14:13 + --> tests/ui/floating_point_exp.rs:16:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> tests/ui/floating_point_exp.rs:15:13 + --> tests/ui/floating_point_exp.rs:17:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` diff --git a/src/tools/clippy/tests/ui/floating_point_log.fixed b/src/tools/clippy/tests/ui/floating_point_log.fixed index 15cc47eef0d..75e9c40a521 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.fixed +++ b/src/tools/clippy/tests/ui/floating_point_log.fixed @@ -1,6 +1,8 @@ #![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)] #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] +// FIXME(f16_f128): add tests for these types once math functions are available + const TWO: f32 = 2.0; const E: f32 = std::f32::consts::E; diff --git a/src/tools/clippy/tests/ui/floating_point_log.rs b/src/tools/clippy/tests/ui/floating_point_log.rs index 1241af82859..d68369a3861 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.rs +++ b/src/tools/clippy/tests/ui/floating_point_log.rs @@ -1,6 +1,8 @@ #![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)] #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] +// FIXME(f16_f128): add tests for these types once math functions are available + const TWO: f32 = 2.0; const E: f32 = std::f32::consts::E; diff --git a/src/tools/clippy/tests/ui/floating_point_log.stderr b/src/tools/clippy/tests/ui/floating_point_log.stderr index 3a449a98ead..19c28de8e39 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.stderr +++ b/src/tools/clippy/tests/ui/floating_point_log.stderr @@ -1,5 +1,5 @@ error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:9:13 + --> tests/ui/floating_point_log.rs:11:13 | LL | let _ = x.log(2f32); | ^^^^^^^^^^^ help: consider using: `x.log2()` @@ -8,55 +8,55 @@ LL | let _ = x.log(2f32); = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:10:13 + --> tests/ui/floating_point_log.rs:12:13 | LL | let _ = x.log(10f32); | ^^^^^^^^^^^^ help: consider using: `x.log10()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:11:13 + --> tests/ui/floating_point_log.rs:13:13 | LL | let _ = x.log(std::f32::consts::E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:12:13 + --> tests/ui/floating_point_log.rs:14:13 | LL | let _ = x.log(TWO); | ^^^^^^^^^^ help: consider using: `x.log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:13:13 + --> tests/ui/floating_point_log.rs:15:13 | LL | let _ = x.log(E); | ^^^^^^^^ help: consider using: `x.ln()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:14:13 + --> tests/ui/floating_point_log.rs:16:13 | LL | let _ = (x as f32).log(2f32); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:17:13 + --> tests/ui/floating_point_log.rs:19:13 | LL | let _ = x.log(2f64); | ^^^^^^^^^^^ help: consider using: `x.log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:18:13 + --> tests/ui/floating_point_log.rs:20:13 | LL | let _ = x.log(10f64); | ^^^^^^^^^^^^ help: consider using: `x.log10()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:19:13 + --> tests/ui/floating_point_log.rs:21:13 | LL | let _ = x.log(std::f64::consts::E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:24:13 + --> tests/ui/floating_point_log.rs:26:13 | LL | let _ = (1f32 + 2.).ln(); | ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()` @@ -65,115 +65,115 @@ LL | let _ = (1f32 + 2.).ln(); = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:25:13 + --> tests/ui/floating_point_log.rs:27:13 | LL | let _ = (1f32 + 2.0).ln(); | ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:26:13 + --> tests/ui/floating_point_log.rs:28:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:27:13 + --> tests/ui/floating_point_log.rs:29:13 | LL | let _ = (1.0 + x / 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:28:13 + --> tests/ui/floating_point_log.rs:30:13 | LL | let _ = (1.0 + x.powi(3)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:29:13 + --> tests/ui/floating_point_log.rs:31:13 | LL | let _ = (1.0 + x.powi(3) / 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(3) / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:30:13 + --> tests/ui/floating_point_log.rs:32:13 | LL | let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(std::f32::consts::E - 1.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:31:13 + --> tests/ui/floating_point_log.rs:33:13 | LL | let _ = (x + 1.0).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:32:13 + --> tests/ui/floating_point_log.rs:34:13 | LL | let _ = (x.powi(3) + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:33:13 + --> tests/ui/floating_point_log.rs:35:13 | LL | let _ = (x + 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:34:13 + --> tests/ui/floating_point_log.rs:36:13 | LL | let _ = (x / 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:42:13 + --> tests/ui/floating_point_log.rs:44:13 | LL | let _ = (1f64 + 2.).ln(); | ^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:43:13 + --> tests/ui/floating_point_log.rs:45:13 | LL | let _ = (1f64 + 2.0).ln(); | ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:44:13 + --> tests/ui/floating_point_log.rs:46:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:45:13 + --> tests/ui/floating_point_log.rs:47:13 | LL | let _ = (1.0 + x / 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:46:13 + --> tests/ui/floating_point_log.rs:48:13 | LL | let _ = (1.0 + x.powi(3)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:47:13 + --> tests/ui/floating_point_log.rs:49:13 | LL | let _ = (x + 1.0).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:48:13 + --> tests/ui/floating_point_log.rs:50:13 | LL | let _ = (x.powi(3) + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:49:13 + --> tests/ui/floating_point_log.rs:51:13 | LL | let _ = (x + 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:50:13 + --> tests/ui/floating_point_log.rs:52:13 | LL | let _ = (x / 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` diff --git a/src/tools/clippy/tests/ui/floating_point_powf.fixed b/src/tools/clippy/tests/ui/floating_point_powf.fixed index c2884ca318c..a44938fdf69 100644 --- a/src/tools/clippy/tests/ui/floating_point_powf.fixed +++ b/src/tools/clippy/tests/ui/floating_point_powf.fixed @@ -1,6 +1,8 @@ #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] +// FIXME(f16_f128): add tests for these types when `powf` is available + fn main() { let x = 3f32; let _ = x.exp2(); diff --git a/src/tools/clippy/tests/ui/floating_point_powf.rs b/src/tools/clippy/tests/ui/floating_point_powf.rs index 37d58af0551..80f6c1791d7 100644 --- a/src/tools/clippy/tests/ui/floating_point_powf.rs +++ b/src/tools/clippy/tests/ui/floating_point_powf.rs @@ -1,6 +1,8 @@ #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] +// FIXME(f16_f128): add tests for these types when `powf` is available + fn main() { let x = 3f32; let _ = 2f32.powf(x); diff --git a/src/tools/clippy/tests/ui/floating_point_powf.stderr b/src/tools/clippy/tests/ui/floating_point_powf.stderr index bd3fa771fe5..671383401b5 100644 --- a/src/tools/clippy/tests/ui/floating_point_powf.stderr +++ b/src/tools/clippy/tests/ui/floating_point_powf.stderr @@ -1,5 +1,5 @@ error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:6:13 + --> tests/ui/floating_point_powf.rs:8:13 | LL | let _ = 2f32.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` @@ -8,43 +8,43 @@ LL | let _ = 2f32.powf(x); = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:7:13 + --> tests/ui/floating_point_powf.rs:9:13 | LL | let _ = 2f32.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:8:13 + --> tests/ui/floating_point_powf.rs:10:13 | LL | let _ = 2f32.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:9:13 + --> tests/ui/floating_point_powf.rs:11:13 | LL | let _ = std::f32::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:10:13 + --> tests/ui/floating_point_powf.rs:12:13 | LL | let _ = std::f32::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:11:13 + --> tests/ui/floating_point_powf.rs:13:13 | LL | let _ = std::f32::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp()` error: square-root of a number can be computed more efficiently and accurately - --> tests/ui/floating_point_powf.rs:12:13 + --> tests/ui/floating_point_powf.rs:14:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> tests/ui/floating_point_powf.rs:13:13 + --> tests/ui/floating_point_powf.rs:15:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` @@ -53,139 +53,139 @@ LL | let _ = x.powf(1.0 / 3.0); = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]` error: cube-root of a number can be computed more accurately - --> tests/ui/floating_point_powf.rs:14:13 + --> tests/ui/floating_point_powf.rs:16:13 | LL | let _ = (x as f32).powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:15:13 + --> tests/ui/floating_point_powf.rs:17:13 | LL | let _ = x.powf(3.0); | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:16:13 + --> tests/ui/floating_point_powf.rs:18:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:17:13 + --> tests/ui/floating_point_powf.rs:19:13 | LL | let _ = x.powf(16_777_215.0); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(16_777_215)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:18:13 + --> tests/ui/floating_point_powf.rs:20:13 | LL | let _ = x.powf(-16_777_215.0); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-16_777_215)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:19:13 + --> tests/ui/floating_point_powf.rs:21:13 | LL | let _ = (x as f32).powf(-16_777_215.0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(-16_777_215)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:20:13 + --> tests/ui/floating_point_powf.rs:22:13 | LL | let _ = (x as f32).powf(3.0); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(3)` error: cube-root of a number can be computed more accurately - --> tests/ui/floating_point_powf.rs:21:13 + --> tests/ui/floating_point_powf.rs:23:13 | LL | let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(1.5_f32 + 1.0).cbrt()` error: cube-root of a number can be computed more accurately - --> tests/ui/floating_point_powf.rs:22:13 + --> tests/ui/floating_point_powf.rs:24:13 | LL | let _ = 1.5_f64.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.cbrt()` error: square-root of a number can be computed more efficiently and accurately - --> tests/ui/floating_point_powf.rs:23:13 + --> tests/ui/floating_point_powf.rs:25:13 | LL | let _ = 1.5_f64.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.sqrt()` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:24:13 + --> tests/ui/floating_point_powf.rs:26:13 | LL | let _ = 1.5_f64.powf(3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.powi(3)` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:33:13 + --> tests/ui/floating_point_powf.rs:35:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:34:13 + --> tests/ui/floating_point_powf.rs:36:13 | LL | let _ = 2f64.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:35:13 + --> tests/ui/floating_point_powf.rs:37:13 | LL | let _ = 2f64.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:36:13 + --> tests/ui/floating_point_powf.rs:38:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:37:13 + --> tests/ui/floating_point_powf.rs:39:13 | LL | let _ = std::f64::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:38:13 + --> tests/ui/floating_point_powf.rs:40:13 | LL | let _ = std::f64::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()` error: square-root of a number can be computed more efficiently and accurately - --> tests/ui/floating_point_powf.rs:39:13 + --> tests/ui/floating_point_powf.rs:41:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> tests/ui/floating_point_powf.rs:40:13 + --> tests/ui/floating_point_powf.rs:42:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:41:13 + --> tests/ui/floating_point_powf.rs:43:13 | LL | let _ = x.powf(3.0); | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:42:13 + --> tests/ui/floating_point_powf.rs:44:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:43:13 + --> tests/ui/floating_point_powf.rs:45:13 | LL | let _ = x.powf(-2_147_483_648.0); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:44:13 + --> tests/ui/floating_point_powf.rs:46:13 | LL | let _ = x.powf(2_147_483_647.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)` diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.fixed b/src/tools/clippy/tests/ui/lossy_float_literal.fixed index 92a0084a6ae..cc8c0b4a0d1 100644 --- a/src/tools/clippy/tests/ui/lossy_float_literal.fixed +++ b/src/tools/clippy/tests/ui/lossy_float_literal.fixed @@ -1,31 +1,55 @@ #![warn(clippy::lossy_float_literal)] #![allow(overflowing_literals, unused)] +#![feature(f128)] +#![feature(f16)] fn main() { // Lossy whole-number float literals + let _: f16 = 4_097.0; + let _: f16 = 4_097.; + let _: f16 = 4_097.000; + let _ = 4_097f16; + let _: f16 = -4_097.0; + let _: f32 = 16_777_216.0; let _: f32 = 16_777_220.0; let _: f32 = 16_777_220.0; let _: f32 = 16_777_220.0; let _ = 16_777_220_f32; let _: f32 = -16_777_220.0; + let _: f64 = 9_007_199_254_740_992.0; let _: f64 = 9_007_199_254_740_992.0; let _: f64 = 9_007_199_254_740_992.0; let _ = 9_007_199_254_740_992_f64; let _: f64 = -9_007_199_254_740_992.0; + let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.0; + let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.; + let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.00; + let _ = 10_384_593_717_069_655_257_060_992_658_440_193f128; + let _: f128 = -10_384_593_717_069_655_257_060_992_658_440_193.0; + // Lossless whole number float literals + let _: f16 = 4_096.0; + let _: f16 = -4_096.0; + let _: f32 = 16_777_216.0; let _: f32 = 16_777_218.0; let _: f32 = 16_777_220.0; let _: f32 = -16_777_216.0; let _: f32 = -16_777_220.0; + let _: f64 = 16_777_217.0; let _: f64 = -16_777_217.0; let _: f64 = 9_007_199_254_740_992.0; let _: f64 = -9_007_199_254_740_992.0; + let _: f128 = 9_007_199_254_740_993.0; + let _: f128 = -9_007_199_254_740_993.0; + let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_192.0; + let _: f128 = -10_384_593_717_069_655_257_060_992_658_440_192.0; + // Ignored whole number float literals let _: f32 = 1e25; let _: f32 = 1E25; diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.rs b/src/tools/clippy/tests/ui/lossy_float_literal.rs index 5abef3c442e..c84eef396d5 100644 --- a/src/tools/clippy/tests/ui/lossy_float_literal.rs +++ b/src/tools/clippy/tests/ui/lossy_float_literal.rs @@ -1,31 +1,55 @@ #![warn(clippy::lossy_float_literal)] #![allow(overflowing_literals, unused)] +#![feature(f128)] +#![feature(f16)] fn main() { // Lossy whole-number float literals + let _: f16 = 4_097.0; + let _: f16 = 4_097.; + let _: f16 = 4_097.000; + let _ = 4_097f16; + let _: f16 = -4_097.0; + let _: f32 = 16_777_217.0; let _: f32 = 16_777_219.0; let _: f32 = 16_777_219.; let _: f32 = 16_777_219.000; let _ = 16_777_219f32; let _: f32 = -16_777_219.0; + let _: f64 = 9_007_199_254_740_993.0; let _: f64 = 9_007_199_254_740_993.; let _: f64 = 9_007_199_254_740_993.00; let _ = 9_007_199_254_740_993f64; let _: f64 = -9_007_199_254_740_993.0; + let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.0; + let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.; + let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.00; + let _ = 10_384_593_717_069_655_257_060_992_658_440_193f128; + let _: f128 = -10_384_593_717_069_655_257_060_992_658_440_193.0; + // Lossless whole number float literals + let _: f16 = 4_096.0; + let _: f16 = -4_096.0; + let _: f32 = 16_777_216.0; let _: f32 = 16_777_218.0; let _: f32 = 16_777_220.0; let _: f32 = -16_777_216.0; let _: f32 = -16_777_220.0; + let _: f64 = 16_777_217.0; let _: f64 = -16_777_217.0; let _: f64 = 9_007_199_254_740_992.0; let _: f64 = -9_007_199_254_740_992.0; + let _: f128 = 9_007_199_254_740_993.0; + let _: f128 = -9_007_199_254_740_993.0; + let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_192.0; + let _: f128 = -10_384_593_717_069_655_257_060_992_658_440_192.0; + // Ignored whole number float literals let _: f32 = 1e25; let _: f32 = 1E25; diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.stderr b/src/tools/clippy/tests/ui/lossy_float_literal.stderr index 7904719141c..b5a07418734 100644 --- a/src/tools/clippy/tests/ui/lossy_float_literal.stderr +++ b/src/tools/clippy/tests/ui/lossy_float_literal.stderr @@ -1,5 +1,5 @@ error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:6:18 + --> tests/ui/lossy_float_literal.rs:14:18 | LL | let _: f32 = 16_777_217.0; | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_216.0` @@ -8,61 +8,61 @@ LL | let _: f32 = 16_777_217.0; = help: to override `-D warnings` add `#[allow(clippy::lossy_float_literal)]` error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:7:18 + --> tests/ui/lossy_float_literal.rs:15:18 | LL | let _: f32 = 16_777_219.0; | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:8:18 + --> tests/ui/lossy_float_literal.rs:16:18 | LL | let _: f32 = 16_777_219.; | ^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:9:18 + --> tests/ui/lossy_float_literal.rs:17:18 | LL | let _: f32 = 16_777_219.000; | ^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:10:13 + --> tests/ui/lossy_float_literal.rs:18:13 | LL | let _ = 16_777_219f32; | ^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220_f32` error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:11:19 + --> tests/ui/lossy_float_literal.rs:19:19 | LL | let _: f32 = -16_777_219.0; | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:12:18 + --> tests/ui/lossy_float_literal.rs:21:18 | LL | let _: f64 = 9_007_199_254_740_993.0; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:13:18 + --> tests/ui/lossy_float_literal.rs:22:18 | LL | let _: f64 = 9_007_199_254_740_993.; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:14:18 + --> tests/ui/lossy_float_literal.rs:23:18 | LL | let _: f64 = 9_007_199_254_740_993.00; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:15:13 + --> tests/ui/lossy_float_literal.rs:24:13 | LL | let _ = 9_007_199_254_740_993f64; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992_f64` error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:16:19 + --> tests/ui/lossy_float_literal.rs:25:19 | LL | let _: f64 = -9_007_199_254_740_993.0; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` diff --git a/src/tools/clippy/tests/ui/manual_float_methods.rs b/src/tools/clippy/tests/ui/manual_float_methods.rs index 80781ecda72..ee3daa12834 100644 --- a/src/tools/clippy/tests/ui/manual_float_methods.rs +++ b/src/tools/clippy/tests/ui/manual_float_methods.rs @@ -3,6 +3,8 @@ #![allow(clippy::needless_if, unused)] #![warn(clippy::manual_is_infinite, clippy::manual_is_finite)] +// FIXME(f16_f128): add tests for these types once constants are available + #[macro_use] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/manual_float_methods.stderr b/src/tools/clippy/tests/ui/manual_float_methods.stderr index 930df0b97cb..70057620a4a 100644 --- a/src/tools/clippy/tests/ui/manual_float_methods.stderr +++ b/src/tools/clippy/tests/ui/manual_float_methods.stderr @@ -1,5 +1,5 @@ error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:22:8 + --> tests/ui/manual_float_methods.rs:24:8 | LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` @@ -8,7 +8,7 @@ LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} = help: to override `-D warnings` add `#[allow(clippy::manual_is_infinite)]` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:23:8 + --> tests/ui/manual_float_methods.rs:25:8 | LL | if x != f32::INFINITY && x != f32::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,13 +29,13 @@ LL | if !x.is_infinite() {} | ~~~~~~~~~~~~~~~~ error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:24:8 + --> tests/ui/manual_float_methods.rs:26:8 | LL | if x == INFINITE || x == NEG_INFINITE {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:25:8 + --> tests/ui/manual_float_methods.rs:27:8 | LL | if x != INFINITE && x != NEG_INFINITE {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,13 +54,13 @@ LL | if !x.is_infinite() {} | ~~~~~~~~~~~~~~~~ error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:27:8 + --> tests/ui/manual_float_methods.rs:29:8 | LL | if x == f64::INFINITY || x == f64::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:28:8 + --> tests/ui/manual_float_methods.rs:30:8 | LL | if x != f64::INFINITY && x != f64::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs b/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs index 37895ea09e7..a5b63bed531 100644 --- a/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs +++ b/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs @@ -1,3 +1,5 @@ +#![feature(f128)] +#![feature(f16)] #![warn(clippy::modulo_arithmetic)] #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)] @@ -17,6 +19,19 @@ fn main() { //~| NOTE: double check for expected result especially when interoperating with differ // Lint on floating point numbers + let a_f16: f16 = -1.6; + let mut b_f16: f16 = 2.1; + a_f16 % b_f16; + //~^ ERROR: you are using modulo operator on types that might have different signs + //~| NOTE: double check for expected result especially when interoperating with differ + b_f16 % a_f16; + //~^ ERROR: you are using modulo operator on types that might have different signs + //~| NOTE: double check for expected result especially when interoperating with differ + b_f16 %= a_f16; + //~^ ERROR: you are using modulo operator on types that might have different signs + //~| NOTE: double check for expected result especially when interoperating with differ + + // Lint on floating point numbers let a_f32: f32 = -1.6; let mut b_f32: f32 = 2.1; a_f32 % b_f32; @@ -41,6 +56,18 @@ fn main() { //~^ ERROR: you are using modulo operator on types that might have different signs //~| NOTE: double check for expected result especially when interoperating with differ + let a_f128: f128 = -1.6; + let mut b_f128: f128 = 2.1; + a_f128 % b_f128; + //~^ ERROR: you are using modulo operator on types that might have different signs + //~| NOTE: double check for expected result especially when interoperating with differ + b_f128 % a_f128; + //~^ ERROR: you are using modulo operator on types that might have different signs + //~| NOTE: double check for expected result especially when interoperating with differ + b_f128 %= a_f128; + //~^ ERROR: you are using modulo operator on types that might have different signs + //~| NOTE: double check for expected result especially when interoperating with differ + // No lint when both sides are const and of the same sign 1.6 % 2.1; -1.6 % -2.1; diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr index fa3a64cfb71..2b4937552bd 100644 --- a/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr +++ b/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr @@ -1,5 +1,5 @@ error: you are using modulo operator on constants with different signs: `-1.600 % 2.100` - --> tests/ui/modulo_arithmetic_float.rs:6:5 + --> tests/ui/modulo_arithmetic_float.rs:8:5 | LL | -1.6 % 2.1; | ^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | -1.6 % 2.1; = help: to override `-D warnings` add `#[allow(clippy::modulo_arithmetic)]` error: you are using modulo operator on constants with different signs: `1.600 % -2.100` - --> tests/ui/modulo_arithmetic_float.rs:9:5 + --> tests/ui/modulo_arithmetic_float.rs:11:5 | LL | 1.6 % -2.1; | ^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | 1.6 % -2.1; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on constants with different signs: `-1.200 % 3.400` - --> tests/ui/modulo_arithmetic_float.rs:12:5 + --> tests/ui/modulo_arithmetic_float.rs:14:5 | LL | (1.1 - 2.3) % (1.1 + 2.3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | (1.1 - 2.3) % (1.1 + 2.3); = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on constants with different signs: `3.400 % -1.200` - --> tests/ui/modulo_arithmetic_float.rs:15:5 + --> tests/ui/modulo_arithmetic_float.rs:17:5 | LL | (1.1 + 2.3) % (1.1 - 2.3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,31 @@ LL | (1.1 + 2.3) % (1.1 - 2.3); = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:22:5 + --> tests/ui/modulo_arithmetic_float.rs:24:5 + | +LL | a_f16 % b_f16; + | ^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on types that might have different signs + --> tests/ui/modulo_arithmetic_float.rs:27:5 + | +LL | b_f16 % a_f16; + | ^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on types that might have different signs + --> tests/ui/modulo_arithmetic_float.rs:30:5 + | +LL | b_f16 %= a_f16; + | ^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on types that might have different signs + --> tests/ui/modulo_arithmetic_float.rs:37:5 | LL | a_f32 % b_f32; | ^^^^^^^^^^^^^ @@ -41,7 +65,7 @@ LL | a_f32 % b_f32; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:25:5 + --> tests/ui/modulo_arithmetic_float.rs:40:5 | LL | b_f32 % a_f32; | ^^^^^^^^^^^^^ @@ -49,7 +73,7 @@ LL | b_f32 % a_f32; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:28:5 + --> tests/ui/modulo_arithmetic_float.rs:43:5 | LL | b_f32 %= a_f32; | ^^^^^^^^^^^^^^ @@ -57,7 +81,7 @@ LL | b_f32 %= a_f32; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:34:5 + --> tests/ui/modulo_arithmetic_float.rs:49:5 | LL | a_f64 % b_f64; | ^^^^^^^^^^^^^ @@ -65,7 +89,7 @@ LL | a_f64 % b_f64; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:37:5 + --> tests/ui/modulo_arithmetic_float.rs:52:5 | LL | b_f64 % a_f64; | ^^^^^^^^^^^^^ @@ -73,12 +97,36 @@ LL | b_f64 % a_f64; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:40:5 + --> tests/ui/modulo_arithmetic_float.rs:55:5 | LL | b_f64 %= a_f64; | ^^^^^^^^^^^^^^ | = note: double check for expected result especially when interoperating with different languages -error: aborting due to 10 previous errors +error: you are using modulo operator on types that might have different signs + --> tests/ui/modulo_arithmetic_float.rs:61:5 + | +LL | a_f128 % b_f128; + | ^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on types that might have different signs + --> tests/ui/modulo_arithmetic_float.rs:64:5 + | +LL | b_f128 % a_f128; + | ^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: you are using modulo operator on types that might have different signs + --> tests/ui/modulo_arithmetic_float.rs:67:5 + | +LL | b_f128 %= a_f128; + | ^^^^^^^^^^^^^^^^ + | + = note: double check for expected result especially when interoperating with different languages + +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr index 0cce718a1ac..f25c0293754 100644 --- a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr +++ b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr @@ -212,7 +212,7 @@ help: check if the original Iterator contains an element instead of collecting t | LL ~ LL | - ... +... LL | // Do lint LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr index ce64861fa40..de048091cfb 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.stderr +++ b/src/tools/clippy/tests/ui/needless_late_init.stderr @@ -215,7 +215,7 @@ help: move the declaration `x` here | LL ~ LL | // types that should be considered insignificant - ... +... LL | let y = Box::new(4); LL ~ let x = SignificantDrop; | diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index bf5a89d8b75..b49f199ba5a 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -518,7 +518,7 @@ help: remove `return` | LL ~ 10 LL | }, - ... +... LL | }, LL ~ } | diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs index be6e071767d..46629526367 100644 --- a/src/tools/clippy/tests/ui/transmute.rs +++ b/src/tools/clippy/tests/ui/transmute.rs @@ -1,3 +1,5 @@ +#![feature(f128)] +#![feature(f16)] #![allow( dead_code, clippy::borrow_as_ptr, @@ -117,20 +119,34 @@ fn int_to_bool() { #[warn(clippy::transmute_int_to_float)] mod int_to_float { fn test() { + let _: f16 = unsafe { std::mem::transmute(0_u16) }; + //~^ ERROR: transmute from a `u16` to a `f16` + //~| NOTE: `-D clippy::transmute-int-to-float` implied by `-D warnings` + let _: f16 = unsafe { std::mem::transmute(0_i16) }; + //~^ ERROR: transmute from a `i16` to a `f16` let _: f32 = unsafe { std::mem::transmute(0_u32) }; //~^ ERROR: transmute from a `u32` to a `f32` - //~| NOTE: `-D clippy::transmute-int-to-float` implied by `-D warnings` let _: f32 = unsafe { std::mem::transmute(0_i32) }; //~^ ERROR: transmute from a `i32` to a `f32` let _: f64 = unsafe { std::mem::transmute(0_u64) }; //~^ ERROR: transmute from a `u64` to a `f64` let _: f64 = unsafe { std::mem::transmute(0_i64) }; //~^ ERROR: transmute from a `i64` to a `f64` + let _: f128 = unsafe { std::mem::transmute(0_u128) }; + //~^ ERROR: transmute from a `u128` to a `f128` + let _: f128 = unsafe { std::mem::transmute(0_i128) }; + //~^ ERROR: transmute from a `i128` to a `f128` } mod issue_5747 { + const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) }; const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) }; const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) }; + const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) }; + + const fn from_bits_16(v: i16) -> f16 { + unsafe { std::mem::transmute(v) } + } const fn from_bits_32(v: i32) -> f32 { unsafe { std::mem::transmute(v) } @@ -139,6 +155,10 @@ mod int_to_float { const fn from_bits_64(v: u64) -> f64 { unsafe { std::mem::transmute(v) } } + + const fn from_bits_128(v: u128) -> f128 { + unsafe { std::mem::transmute(v) } + } } } @@ -158,10 +178,15 @@ mod num_to_bytes { //~^ ERROR: transmute from a `i32` to a `[u8; 4]` let _: [u8; 16] = std::mem::transmute(0i128); //~^ ERROR: transmute from a `i128` to a `[u8; 16]` + + let _: [u8; 2] = std::mem::transmute(0.0f16); + //~^ ERROR: transmute from a `f16` to a `[u8; 2]` let _: [u8; 4] = std::mem::transmute(0.0f32); //~^ ERROR: transmute from a `f32` to a `[u8; 4]` let _: [u8; 8] = std::mem::transmute(0.0f64); //~^ ERROR: transmute from a `f64` to a `[u8; 8]` + let _: [u8; 16] = std::mem::transmute(0.0f128); + //~^ ERROR: transmute from a `f128` to a `[u8; 16]` } } const fn test_const() { @@ -178,8 +203,11 @@ mod num_to_bytes { //~^ ERROR: transmute from a `i32` to a `[u8; 4]` let _: [u8; 16] = std::mem::transmute(0i128); //~^ ERROR: transmute from a `i128` to a `[u8; 16]` + + let _: [u8; 2] = std::mem::transmute(0.0f16); let _: [u8; 4] = std::mem::transmute(0.0f32); let _: [u8; 8] = std::mem::transmute(0.0f64); + let _: [u8; 16] = std::mem::transmute(0.0f128); } } } diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index 375e8f19dd6..0072f62962a 100644 --- a/src/tools/clippy/tests/ui/transmute.stderr +++ b/src/tools/clippy/tests/ui/transmute.stderr @@ -1,5 +1,5 @@ error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:29:23 + --> tests/ui/transmute.rs:31:23 | LL | let _: *const T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` @@ -8,61 +8,61 @@ LL | let _: *const T = core::intrinsics::transmute(t); = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:33:21 + --> tests/ui/transmute.rs:35:21 | LL | let _: *mut T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:36:23 + --> tests/ui/transmute.rs:38:23 | LL | let _: *const U = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> tests/ui/transmute.rs:43:27 + --> tests/ui/transmute.rs:45:27 | LL | let _: Vec<i32> = core::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> tests/ui/transmute.rs:46:27 + --> tests/ui/transmute.rs:48:27 | LL | let _: Vec<i32> = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> tests/ui/transmute.rs:49:27 + --> tests/ui/transmute.rs:51:27 | LL | let _: Vec<i32> = std::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> tests/ui/transmute.rs:52:27 + --> tests/ui/transmute.rs:54:27 | LL | let _: Vec<i32> = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> tests/ui/transmute.rs:55:27 + --> tests/ui/transmute.rs:57:27 | LL | let _: Vec<i32> = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:58:31 + --> tests/ui/transmute.rs:60:31 | LL | let _: *const usize = std::mem::transmute(5_isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:63:31 + --> tests/ui/transmute.rs:65:31 | LL | let _: *const usize = std::mem::transmute(1 + 1usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize` error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:95:24 + --> tests/ui/transmute.rs:97:24 | LL | let _: Usize = core::intrinsics::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,25 +71,25 @@ LL | let _: Usize = core::intrinsics::transmute(int_const_ptr); = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:99:24 + --> tests/ui/transmute.rs:101:24 | LL | let _: Usize = core::intrinsics::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> tests/ui/transmute.rs:102:31 + --> tests/ui/transmute.rs:104:31 | LL | let _: *const Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> tests/ui/transmute.rs:105:29 + --> tests/ui/transmute.rs:107:29 | LL | let _: *mut Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u8` to a `bool` - --> tests/ui/transmute.rs:112:28 + --> tests/ui/transmute.rs:114:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -97,35 +97,59 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` -error: transmute from a `u32` to a `f32` - --> tests/ui/transmute.rs:120:31 +error: transmute from a `u16` to a `f16` + --> tests/ui/transmute.rs:122:31 | -LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` +LL | let _: f16 = unsafe { std::mem::transmute(0_u16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)` | = note: `-D clippy::transmute-int-to-float` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]` +error: transmute from a `i16` to a `f16` + --> tests/ui/transmute.rs:125:31 + | +LL | let _: f16 = unsafe { std::mem::transmute(0_i16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_i16 as u16)` + +error: transmute from a `u32` to a `f32` + --> tests/ui/transmute.rs:127:31 + | +LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` + error: transmute from a `i32` to a `f32` - --> tests/ui/transmute.rs:123:31 + --> tests/ui/transmute.rs:129:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` error: transmute from a `u64` to a `f64` - --> tests/ui/transmute.rs:125:31 + --> tests/ui/transmute.rs:131:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_u64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)` error: transmute from a `i64` to a `f64` - --> tests/ui/transmute.rs:127:31 + --> tests/ui/transmute.rs:133:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` +error: transmute from a `u128` to a `f128` + --> tests/ui/transmute.rs:135:32 + | +LL | let _: f128 = unsafe { std::mem::transmute(0_u128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_u128)` + +error: transmute from a `i128` to a `f128` + --> tests/ui/transmute.rs:137:32 + | +LL | let _: f128 = unsafe { std::mem::transmute(0_i128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` + error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:148:30 + --> tests/ui/transmute.rs:168:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` @@ -134,85 +158,97 @@ LL | let _: [u8; 1] = std::mem::transmute(0u8); = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:151:30 + --> tests/ui/transmute.rs:171:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:153:31 + --> tests/ui/transmute.rs:173:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:155:30 + --> tests/ui/transmute.rs:175:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:157:30 + --> tests/ui/transmute.rs:177:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:159:31 + --> tests/ui/transmute.rs:179:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` +error: transmute from a `f16` to a `[u8; 2]` + --> tests/ui/transmute.rs:182:30 + | +LL | let _: [u8; 2] = std::mem::transmute(0.0f16); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` + error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:161:30 + --> tests/ui/transmute.rs:184:30 | LL | let _: [u8; 4] = std::mem::transmute(0.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` error: transmute from a `f64` to a `[u8; 8]` - --> tests/ui/transmute.rs:163:30 + --> tests/ui/transmute.rs:186:30 | LL | let _: [u8; 8] = std::mem::transmute(0.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` +error: transmute from a `f128` to a `[u8; 16]` + --> tests/ui/transmute.rs:188:31 + | +LL | let _: [u8; 16] = std::mem::transmute(0.0f128); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` + error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:169:30 + --> tests/ui/transmute.rs:194:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:171:30 + --> tests/ui/transmute.rs:196:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:173:31 + --> tests/ui/transmute.rs:198:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:175:30 + --> tests/ui/transmute.rs:200:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:177:30 + --> tests/ui/transmute.rs:202:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:179:31 + --> tests/ui/transmute.rs:204:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:190:28 + --> tests/ui/transmute.rs:218:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -221,16 +257,16 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> tests/ui/transmute.rs:193:32 + --> tests/ui/transmute.rs:221:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:195:30 + --> tests/ui/transmute.rs:223:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 36 previous errors +error: aborting due to 42 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed index 82d5f7fdca1..4361a7407d1 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed @@ -1,5 +1,7 @@ #![warn(clippy::transmute_float_to_int)] #![allow(clippy::missing_transmute_annotations)] +#![feature(f128)] +#![feature(f16)] fn float_to_int() { let _: u32 = unsafe { 1f32.to_bits() }; @@ -18,8 +20,14 @@ fn float_to_int() { } mod issue_5747 { + const VALUE16: i16 = unsafe { std::mem::transmute(1f16) }; const VALUE32: i32 = unsafe { std::mem::transmute(1f32) }; const VALUE64: u64 = unsafe { std::mem::transmute(1f64) }; + const VALUE128: u128 = unsafe { std::mem::transmute(1f128) }; + + const fn to_bits_16(v: f16) -> u16 { + unsafe { std::mem::transmute(v) } + } const fn to_bits_32(v: f32) -> u32 { unsafe { std::mem::transmute(v) } @@ -28,6 +36,10 @@ mod issue_5747 { const fn to_bits_64(v: f64) -> i64 { unsafe { std::mem::transmute(v) } } + + const fn to_bits_128(v: f128) -> i128 { + unsafe { std::mem::transmute(v) } + } } fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.rs b/src/tools/clippy/tests/ui/transmute_float_to_int.rs index 9f056330adf..363ce0bcb16 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.rs +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.rs @@ -1,5 +1,7 @@ #![warn(clippy::transmute_float_to_int)] #![allow(clippy::missing_transmute_annotations)] +#![feature(f128)] +#![feature(f16)] fn float_to_int() { let _: u32 = unsafe { std::mem::transmute(1f32) }; @@ -18,8 +20,14 @@ fn float_to_int() { } mod issue_5747 { + const VALUE16: i16 = unsafe { std::mem::transmute(1f16) }; const VALUE32: i32 = unsafe { std::mem::transmute(1f32) }; const VALUE64: u64 = unsafe { std::mem::transmute(1f64) }; + const VALUE128: u128 = unsafe { std::mem::transmute(1f128) }; + + const fn to_bits_16(v: f16) -> u16 { + unsafe { std::mem::transmute(v) } + } const fn to_bits_32(v: f32) -> u32 { unsafe { std::mem::transmute(v) } @@ -28,6 +36,10 @@ mod issue_5747 { const fn to_bits_64(v: f64) -> i64 { unsafe { std::mem::transmute(v) } } + + const fn to_bits_128(v: f128) -> i128 { + unsafe { std::mem::transmute(v) } + } } fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr index ac3aae5f8b7..9cac75f72cd 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr @@ -1,5 +1,5 @@ error: transmute from a `f32` to a `u32` - --> tests/ui/transmute_float_to_int.rs:5:27 + --> tests/ui/transmute_float_to_int.rs:7:27 | LL | let _: u32 = unsafe { std::mem::transmute(1f32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits()` @@ -8,31 +8,31 @@ LL | let _: u32 = unsafe { std::mem::transmute(1f32) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_float_to_int)]` error: transmute from a `f32` to a `i32` - --> tests/ui/transmute_float_to_int.rs:8:27 + --> tests/ui/transmute_float_to_int.rs:10:27 | LL | let _: i32 = unsafe { std::mem::transmute(1f32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32` error: transmute from a `f64` to a `u64` - --> tests/ui/transmute_float_to_int.rs:10:27 + --> tests/ui/transmute_float_to_int.rs:12:27 | LL | let _: u64 = unsafe { std::mem::transmute(1f64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()` error: transmute from a `f64` to a `i64` - --> tests/ui/transmute_float_to_int.rs:12:27 + --> tests/ui/transmute_float_to_int.rs:14:27 | LL | let _: i64 = unsafe { std::mem::transmute(1f64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits() as i64` error: transmute from a `f64` to a `u64` - --> tests/ui/transmute_float_to_int.rs:14:27 + --> tests/ui/transmute_float_to_int.rs:16:27 | LL | let _: u64 = unsafe { std::mem::transmute(1.0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.0f64.to_bits()` error: transmute from a `f64` to a `u64` - --> tests/ui/transmute_float_to_int.rs:16:27 + --> tests/ui/transmute_float_to_int.rs:18:27 | LL | let _: u64 = unsafe { std::mem::transmute(-1.0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()` diff --git a/src/tools/clippy/tests/ui/unused_rounding.fixed b/src/tools/clippy/tests/ui/unused_rounding.fixed index 02f970f42a4..7af2c8650a3 100644 --- a/src/tools/clippy/tests/ui/unused_rounding.fixed +++ b/src/tools/clippy/tests/ui/unused_rounding.fixed @@ -1,3 +1,5 @@ +// FIXME(f16_f128): add tests when math functions are available + #![warn(clippy::unused_rounding)] fn main() { diff --git a/src/tools/clippy/tests/ui/unused_rounding.rs b/src/tools/clippy/tests/ui/unused_rounding.rs index fd14c466f12..1b0b22a9b68 100644 --- a/src/tools/clippy/tests/ui/unused_rounding.rs +++ b/src/tools/clippy/tests/ui/unused_rounding.rs @@ -1,3 +1,5 @@ +// FIXME(f16_f128): add tests when math functions are available + #![warn(clippy::unused_rounding)] fn main() { diff --git a/src/tools/clippy/tests/ui/unused_rounding.stderr b/src/tools/clippy/tests/ui/unused_rounding.stderr index 75ad895012b..c5ae2da75f8 100644 --- a/src/tools/clippy/tests/ui/unused_rounding.stderr +++ b/src/tools/clippy/tests/ui/unused_rounding.stderr @@ -1,5 +1,5 @@ error: used the `ceil` method with a whole number float - --> tests/ui/unused_rounding.rs:4:13 + --> tests/ui/unused_rounding.rs:6:13 | LL | let _ = 1f32.ceil(); | ^^^^^^^^^^^ help: remove the `ceil` method call: `1f32` @@ -8,25 +8,25 @@ LL | let _ = 1f32.ceil(); = help: to override `-D warnings` add `#[allow(clippy::unused_rounding)]` error: used the `floor` method with a whole number float - --> tests/ui/unused_rounding.rs:5:13 + --> tests/ui/unused_rounding.rs:7:13 | LL | let _ = 1.0f64.floor(); | ^^^^^^^^^^^^^^ help: remove the `floor` method call: `1.0f64` error: used the `round` method with a whole number float - --> tests/ui/unused_rounding.rs:6:13 + --> tests/ui/unused_rounding.rs:8:13 | LL | let _ = 1.00f32.round(); | ^^^^^^^^^^^^^^^ help: remove the `round` method call: `1.00f32` error: used the `round` method with a whole number float - --> tests/ui/unused_rounding.rs:12:13 + --> tests/ui/unused_rounding.rs:14:13 | LL | let _ = 3.0_f32.round(); | ^^^^^^^^^^^^^^^ help: remove the `round` method call: `3.0_f32` error: used the `round` method with a whole number float - --> tests/ui/unused_rounding.rs:14:13 + --> tests/ui/unused_rounding.rs:16:13 | LL | let _ = 3_3.0_0_f32.round(); | ^^^^^^^^^^^^^^^^^^^ help: remove the `round` method call: `3_3.0_0_f32` diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 5469b9f1a0a..82d80fcc19c 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -779,6 +779,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-haiku", "ignore-horizon", "ignore-i686-pc-windows-msvc", + "ignore-illumos", "ignore-ios", "ignore-linux", "ignore-lldb", @@ -843,6 +844,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-x32", "ignore-x86", "ignore-x86_64", + "ignore-x86_64-apple-darwin", "ignore-x86_64-unknown-linux-gnu", "incremental", "known-bug", diff --git a/src/tools/miri/src/alloc_bytes.rs b/src/tools/miri/src/alloc_bytes.rs index 97841a05cde..8f691456a59 100644 --- a/src/tools/miri/src/alloc_bytes.rs +++ b/src/tools/miri/src/alloc_bytes.rs @@ -108,4 +108,8 @@ impl AllocBytes for MiriAllocBytes { fn as_mut_ptr(&mut self) -> *mut u8 { self.ptr } + + fn as_ptr(&self) -> *const u8 { + self.ptr + } } diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.rs index 6d68b9a46d9..dc192d03196 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.rs +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.rs @@ -1,5 +1,3 @@ -#![feature(c_unwind)] - #[no_mangle] extern "C-unwind" fn unwind() { panic!(); diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs index e6aff19b02d..1382e9571f3 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs @@ -4,7 +4,7 @@ //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" //@[definition,both]error-in-other-file: aborted execution -#![feature(rustc_attrs, c_unwind)] +#![feature(rustc_attrs)] #[cfg_attr(any(definition, both), rustc_nounwind)] #[no_mangle] diff --git a/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs b/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs index 888c548e49b..fa7c0bf5c0c 100644 --- a/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs +++ b/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs @@ -1,4 +1,4 @@ -#![feature(rustc_attrs, effects)] +#![feature(rustc_attrs)] #[rustc_intrinsic] #[rustc_nounwind] diff --git a/src/tools/miri/tests/fail/panic/bad_unwind.rs b/src/tools/miri/tests/fail/panic/bad_unwind.rs index 8c8a9f18cdc..5370485b2a6 100644 --- a/src/tools/miri/tests/fail/panic/bad_unwind.rs +++ b/src/tools/miri/tests/fail/panic/bad_unwind.rs @@ -1,5 +1,3 @@ -#![feature(c_unwind)] - //! Unwinding when the caller ABI is "C" (without "-unwind") is UB. // The opposite version (callee does not allow unwinding) is impossible to // even write: MIR validation catches functions that have `UnwindContinue` but diff --git a/src/tools/miri/tests/fail/terminate-terminator.rs b/src/tools/miri/tests/fail/terminate-terminator.rs index 7c672828030..465625c7572 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.rs +++ b/src/tools/miri/tests/fail/terminate-terminator.rs @@ -7,8 +7,6 @@ // Enable MIR inlining to ensure that `TerminatorKind::UnwindTerminate` is generated // instead of just `UnwindAction::Terminate`. -#![feature(c_unwind)] - struct Foo; impl Drop for Foo { diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.rs b/src/tools/miri/tests/fail/unwind-action-terminate.rs index 86406872c59..465e07c8db4 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.rs +++ b/src/tools/miri/tests/fail/unwind-action-terminate.rs @@ -3,8 +3,6 @@ //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" -#![feature(c_unwind)] - extern "C" fn panic_abort() { panic!() } diff --git a/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.rs b/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.rs index 71b799a1f12..0e8d45af27f 100644 --- a/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.rs +++ b/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.rs @@ -2,7 +2,7 @@ // found in this form" errors works without `-C prefer-dynamic` (`panic!` calls foreign function // `__rust_start_panic`). // no-prefer-dynamic -#![feature(c_unwind, unboxed_closures)] +#![feature(unboxed_closures)] use std::panic; diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index f39bcfd60df..0a1bd9b0b34 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -36,8 +36,10 @@ impl Command { Self { cmd: StdCommand::new(program), stdin: None, drop_bomb: DropBomb::arm(program) } } - pub fn set_stdin(&mut self, stdin: Box<[u8]>) { - self.stdin = Some(stdin); + /// Specify a stdin input + pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self { + self.stdin = Some(input.as_ref().to_vec().into_boxed_slice()); + self } /// Specify an environment variable. diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index f4c101cf81c..487132683e9 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -387,7 +387,7 @@ pub fn recursive_diff(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) { }); } -pub fn read_dir<F: Fn(&Path)>(dir: impl AsRef<Path>, callback: F) { +pub fn read_dir<F: FnMut(&Path)>(dir: impl AsRef<Path>, mut callback: F) { for entry in fs_wrapper::read_dir(dir) { callback(&entry.unwrap().path()); } diff --git a/src/tools/run-make-support/src/llvm.rs b/src/tools/run-make-support/src/llvm.rs index 99bce08fc23..7f42223bf7f 100644 --- a/src/tools/run-make-support/src/llvm.rs +++ b/src/tools/run-make-support/src/llvm.rs @@ -102,6 +102,24 @@ impl LlvmReadobj { self } + /// Pass `--program-headers` to display program headers. + pub fn program_headers(&mut self) -> &mut Self { + self.cmd.arg("--program-headers"); + self + } + + /// Pass `--symbols` to display the symbol. + pub fn symbols(&mut self) -> &mut Self { + self.cmd.arg("--symbols"); + self + } + + /// Pass `--dynamic-table` to display the dynamic symbol table. + pub fn dynamic_table(&mut self) -> &mut Self { + self.cmd.arg("--dynamic-table"); + self + } + /// Specify the section to display. pub fn section(&mut self, section: &str) -> &mut Self { self.cmd.arg("--string-dump"); @@ -153,7 +171,7 @@ impl LlvmFilecheck { /// Pipe a read file into standard input containing patterns that will be matched against the .patterns(path) call. pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self { - self.cmd.set_stdin(input.as_ref().to_vec().into_boxed_slice()); + self.cmd.stdin(input); self } diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 331e1a5ab8b..28ece1dff12 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -73,6 +73,12 @@ impl Rustc { self } + /// Incorporate a hashed string to mangled symbols. + pub fn metadata(&mut self, meta: &str) -> &mut Self { + self.cmd.arg(format!("-Cmetadata={meta}")); + self + } + /// Add a suffix in each output filename. pub fn extra_filename(&mut self, suffix: &str) -> &mut Self { self.cmd.arg(format!("-Cextra-filename={suffix}")); @@ -230,9 +236,15 @@ impl Rustc { self } + /// Add multiple extra arguments to the linker invocation, via `-Clink-args`. + pub fn link_args(&mut self, link_args: &str) -> &mut Self { + self.cmd.arg(format!("-Clink-args={link_args}")); + self + } + /// Specify a stdin input pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self { - self.cmd.set_stdin(input.as_ref().to_vec().into_boxed_slice()); + self.cmd.stdin(input); self } @@ -248,4 +260,10 @@ impl Rustc { self.cmd.arg(format!("-Clinker={linker}")); self } + + /// Specify the linker flavor + pub fn linker_flavor(&mut self, linker_flavor: &str) -> &mut Self { + self.cmd.arg(format!("-Clinker-flavor={linker_flavor}")); + self + } } diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs index 93078561254..fb00427b1c1 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -92,7 +92,7 @@ impl Rustdoc { /// Specify a stdin input pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self { - self.cmd.set_stdin(input.as_ref().to_vec().into_boxed_slice()); + self.cmd.stdin(input); self } diff --git a/src/tools/rustfmt/.github/workflows/integration.yml b/src/tools/rustfmt/.github/workflows/integration.yml index 314ce0e84c6..f0dd0cf73bb 100644 --- a/src/tools/rustfmt/.github/workflows/integration.yml +++ b/src/tools/rustfmt/.github/workflows/integration.yml @@ -19,7 +19,6 @@ jobs: matrix: integration: [ bitflags, - error-chain, log, mdbook, packed_simd, diff --git a/src/tools/rustfmt/CHANGELOG.md b/src/tools/rustfmt/CHANGELOG.md index ec4c682d2c4..89e90fb17dd 100644 --- a/src/tools/rustfmt/CHANGELOG.md +++ b/src/tools/rustfmt/CHANGELOG.md @@ -2,6 +2,99 @@ ## [Unreleased] +### Fixed + +- Fix an idempotency issue when rewriting where clauses in which rustfmt would continuously add a trailing comma `,` to the end of trailing line comments [#5941](https://github.com/rust-lang/rustfmt/issues/5941). +- Prevent enum variant attributes from wrapping one character early when using `version=Two` [#5801](https://github.com/rust-lang/rustfmt/issues/5801) +- Properly wrap macro matchers at the `max_width` when using `version=Two` and `format_macro_matchers=true` [#3805](https://github.com/rust-lang/rustfmt/issues/3805) +- Prevent panic when formatting trait declaration with non [Unicode Normalization Form] C (NFC) identifiers [#6069](https://github.com/rust-lang/rustfmt/issues/6069) + ```rust + // The ó below is two codepoints, ASCII o followed by U+0301 COMBINING ACUTE ACCENT. + // It NFC-normalizes to ó, U+00F3 LATIN SMALL LETTER O WITH ACUTE. + trait Foó: Bar {} + ``` + [unicode normalization form]: https://unicode.org/reports/tr15/ +- Ensure a space is added to a range expression, when the right hand side of the range expression is a binary expression that ends with a trailing period [#6059](https://github.com/rust-lang/rustfmt/issues/6059) + ```rust + let range = 3. / 2. ..4.; + ``` +- When using `version=Two`, comments in match arms that contain `=>` no longer prevent formatting [#5998](https://github.com/rust-lang/rustfmt/issues/5998) + ```rust + match a { + _ => + // comment with => + { + println!("A") + } + } + ``` +- Prevent panics when formatting input that contains the expanded form of `offset_of!` [#5885](https://github.com/rust-lang/rustfmt/issues/5885) [#6105](https://github.com/rust-lang/rustfmt/issues/6105) + ```rust + const _: () = builtin # offset_of(x, x); + ``` +- When using `version=Two` inner attributes in `match` expressions are correctly indented [#6147](https://github.com/rust-lang/rustfmt/issues/6147) + ```rust + pub fn main() { + match x { + #![attr1] + #![attr2] + _ => (), + } + } + ``` +- Output correct syntax for type ascription builtin [#6159](https://github.com/rust-lang/rustfmt/issues/6159) + ```rust + fn main() { + builtin # type_ascribe(10, usize) + } + ``` +- rustfmt no longer removes inner attributes from inline const blocks [#6158](https://github.com/rust-lang/rustfmt/issues/6158) + ```rust + fn main() { + const { + #![allow(clippy::assertions_on_constants)] + + assert!(1 < 2); + } + } + ``` +- rustfmt no longer removes `safe` and `unsafe` keywords from static items in extern blocks. + This helps support [`#![feature(unsafe_extern_blocks)]`](https://github.com/rust-lang/rust/issues/123743) [#6204](https://github.com/rust-lang/rustfmt/pull/6204) + ```rust + #![feature(unsafe_extern_blocks)] + + unsafe extern "C" { + safe static TEST1: i32; + unsafe static TEST2: i32; + } + ``` + + +### Changed + +- `hide_parse_errors` has been soft deprecated and it's been renamed to `show_parse_errors` [#5961](https://github.com/rust-lang/rustfmt/pull/5961). +- The diff output produced by `rustfmt --check` is more compatable with editors that support navigating directly to line numbers [#5971](https://github.com/rust-lang/rustfmt/pull/5971) +- When using `version=Two`, the `trace!` macro from the [log crate] is now formatted similarly to `debug!`, `info!`, `warn!`, and `error!` [#5987](https://github.com/rust-lang/rustfmt/issues/5987). + + [log crate]: https://crates.io/crates/log + + +### Added + +- `generated_marker_line_search_limit` is a new unstable configuration option that allows users to configure how many lines to search for an `@generated` marker when `format_generated_files=false` [#5658](https://github.com/rust-lang/rustfmt/issues/5658) + + +### Misc + +- Updating `dirs 4.0.0 -> 5.0.1` and `cargo_metadata 0.15.4 -> 0.18.0` [#6033] (https://github.com/rust-lang/rustfmt/issues/6033) + - For reference, here's the [dirs v5 changelog](https://github.com/dirs-dev/dirs-rs/blob/main/README.md#5) +- Updated [itertools v0.11 -> v0.12](https://github.com/rust-itertools/itertools/blob/v0.12.1/CHANGELOG.md#0120) [#6093](https://github.com/rust-lang/rustfmt/pull/6093) +- Addressed clap deprecations output when running `cargo check --features clap/deprecated` [#6101](https://github.com/rust-lang/rustfmt/pull/6101) +- Bumped bytecount `0.6.4` -> `0.6.8` to fix compilation issues with the `generic-simd` feature. See [bytecount#92] and [bytecount#93] + + [bytecount#92]: https://github.com/llogiq/bytecount/pull/92 + [bytecount#93]: https://github.com/llogiq/bytecount/pull/93 +- Replace the `lazy_static` dependency with `std::sync::OnceLock` [#6154](https://github.com/rust-lang/rustfmt/pull/6154) ## [1.7.0] 2023-10-22 @@ -27,7 +120,7 @@ } ``` - Prevent ICE when formatting `vec!{}` [#5735](https://github.com/rust-lang/rustfmt/issues/5735) -- Prevent internal trailing whitespace error when formatting an empty `macro_rules!` defintion e.g. `macro_rules! foo {}` [#5882](https://github.com/rust-lang/rustfmt/issues/5882) +- Prevent internal trailing whitespace error when formatting an empty `macro_rules!` definition e.g. `macro_rules! foo {}` [#5882](https://github.com/rust-lang/rustfmt/issues/5882) - Formatting doc comment lines that start with `.` or `)` won't be treated as ordered markdown lists because `.` or `)` must be preceded by a number to start an ordered markdown list [#5835](https://github.com/rust-lang/rustfmt/pull/5835) - Add parenthesis around closures when they're used as method receives, don't have a block body, and end with `.` [#4808](https://github.com/rust-lang/rustfmt/issues/4808) ```rust @@ -184,7 +277,7 @@ - Simplify the rustfmt help text by eliding the full path to the rustfmt binary path from the usage string when running `rustfmt --help` [#5214](https://github.com/rust-lang/rustfmt/issues/5214) -- Bumped the version for serveral dependencies. Most notably `dirs` `v2.0.1` -> `v4.0.0`. This changed the global user config directory on macOS from `$HOME/Library/Preferences` to `$HOME/Library/Application Support` [#5237](https://github.com/rust-lang/rustfmt/pull/5237) +- Bumped the version for several dependencies. Most notably `dirs` `v2.0.1` -> `v4.0.0`. This changed the global user config directory on macOS from `$HOME/Library/Preferences` to `$HOME/Library/Application Support` [#5237](https://github.com/rust-lang/rustfmt/pull/5237) ### Fixed @@ -942,7 +1035,7 @@ from formatting an attribute #3665 ### Fixed -- Do not remove path disambiugator inside macro #3142 +- Do not remove path disambiguator inside macro #3142 - Improve handling of Windows newlines #3141 - Fix alignment of a struct's fields (`struct_field_align_threshold` option) with the Visual `indent_style` #3165 - Fix a bug in formatting markdown lists within comments #3172 @@ -1031,7 +1124,7 @@ from formatting an attribute #3665 ### Changed -- Replace '--conifig-help' with '--config=help' cb10e06 +- Replace '--config-help' with '--config=help' cb10e06 - Improve formatting of slice patterns #2912 ### Fixed @@ -1075,7 +1168,7 @@ from formatting an attribute #3665 - Add max_width option for all heuristics c2ae39e - Add config option `format_macro_matchers` to format the metavariable matching patterns in macros 79c5ee8 - Add config option `format_macro_bodies` to format the bodies of macros 79c5ee8 -- Format exitential type fc307ff +- Format existential type fc307ff - Support raw identifiers in struct expressions f121b1a - Format Async block and async function 0b25f60 @@ -1131,7 +1224,7 @@ from formatting an attribute #3665 ### Changed -- Update rustc-ap-syntax to 128.0.0 and ustc-ap-rustc_target to 128.0.0 195395f +- Update rustc-ap-syntax to 128.0.0 and rustc-ap-rustc_target to 128.0.0 195395f - Put operands on its own line when each fits in a single line f8439ce - Improve CLI options 55ac062 1869888 798bffb 4d9de48 eca7796 8396da1 5d9f5aa @@ -1195,7 +1288,7 @@ from formatting an attribute #3665 - Do not collapse block around expr with condition on match arm 5b9b7d5 - Use vertical layout for complex attributes c77708f - Format array using heuristics for function calls 98c6f7b -- Implement stable ordering for impl items with the the following item priority: type, const, macro, then method fa80ddf +- Implement stable ordering for impl items with the following item priority: type, const, macro, then method fa80ddf - Reorder imports by default 164cf7d - Group `extern crate` by default 3a138a2 - Make `error_on_line_overflow` false by default f146711 diff --git a/src/tools/rustfmt/Cargo.lock b/src/tools/rustfmt/Cargo.lock index 8fcefa97489..2a1fffa50fe 100644 --- a/src/tools/rustfmt/Cargo.lock +++ b/src/tools/rustfmt/Cargo.lock @@ -98,12 +98,9 @@ dependencies = [ [[package]] name = "bytecount" -version = "0.6.4" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad152d03a2c813c80bb94fedbf3a3f02b28f793e39e7c214c8a0bcc196343de7" -dependencies = [ - "packed_simd", -] +checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" [[package]] name = "camino" @@ -125,9 +122,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.15.4" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +checksum = "fb9ac64500cc83ce4b9f8dafa78186aa008c8dea77a09b94cd307fd0cd5022a8" dependencies = [ "camino", "cargo-platform", @@ -217,9 +214,9 @@ checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" [[package]] name = "dirs" -version = "4.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys", ] @@ -236,13 +233,14 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.7" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", - "winapi", + "windows-sys", ] [[package]] @@ -343,9 +341,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.3" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] @@ -369,12 +367,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] name = "log" version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -409,36 +401,22 @@ dependencies = [ ] [[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] name = "once_cell" version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] -name = "overload" -version = "0.1.1" +name = "option-ext" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] -name = "packed_simd" -version = "0.3.9" +name = "overload" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f9f08af0c877571712e2e3e686ad79efad9657dbf0f7c3c8ba943ff6c38932d" -dependencies = [ - "cfg-if", - "num-traits", -] +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pin-project-lite" @@ -521,7 +499,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.7.0" +version = "1.7.1" dependencies = [ "annotate-snippets", "anyhow", @@ -534,7 +512,6 @@ dependencies = [ "getopts", "ignore", "itertools", - "lazy_static", "regex", "rustfmt-config_proc_macro", "serde", diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml index 032b9b54810..a16620ed99b 100644 --- a/src/tools/rustfmt/Cargo.toml +++ b/src/tools/rustfmt/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustfmt-nightly" -version = "1.7.0" +version = "1.7.1" description = "Tool to find and fix Rust formatting issues" repository = "https://github.com/rust-lang/rustfmt" readme = "README.md" @@ -35,16 +35,15 @@ generic-simd = ["bytecount/generic-simd"] [dependencies] annotate-snippets = { version = "0.9", features = ["color"] } anyhow = "1.0" -bytecount = "0.6.4" -cargo_metadata = "0.15.4" +bytecount = "0.6.8" +cargo_metadata = "0.18" clap = { version = "4.4.2", features = ["derive"] } clap-cargo = "0.12.0" diff = "0.1" -dirs = "4.0" +dirs = "5.0" getopts = "0.2" ignore = "0.4" -itertools = "0.11" -lazy_static = "1.4" +itertools = "0.12" regex = "1.7" serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0" diff --git a/src/tools/rustfmt/Configurations.md b/src/tools/rustfmt/Configurations.md index ac5747800b2..f52c2573154 100644 --- a/src/tools/rustfmt/Configurations.md +++ b/src/tools/rustfmt/Configurations.md @@ -1,6 +1,6 @@ # Configuring Rustfmt -Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well. +Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/5.0.1/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well. A possible content of `rustfmt.toml` or `.rustfmt.toml` might look like this: @@ -1050,8 +1050,8 @@ Max width for code snippets included in doc comments. Only used if [`format_code ## `format_generated_files` -Format generated files. A file is considered generated -if any of the first five lines contain a `@generated` comment marker. +Format generated files. A file is considered generated if any of the first several lines contain a `@generated` comment marker. The number of lines to check is configured by `generated_marker_line_search_limit`. + By default, generated files are reformatted, i. e. `@generated` marker is ignored. This option is currently ignored for stdin (`@generated` in stdin is ignored.) @@ -1059,6 +1059,16 @@ This option is currently ignored for stdin (`@generated` in stdin is ignored.) - **Possible values**: `true`, `false` - **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080)) +## `generated_marker_line_search_limit` + +Number of lines to check for a `@generated` pragma header, starting from the top of the file. Setting this value to `0` will treat all files as non-generated. When`format_generated_files` is `true`, this option has no effect. + +- **Default value**: `5` +- **Possible values**: any positive integer +- **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080)) + +See also [format_generated_files](#format_generated_files) link here. + ## `format_macro_matchers` Format the metavariable matching patterns in macros. @@ -1098,7 +1108,7 @@ See also [`format_macro_bodies`](#format_macro_bodies). ## `format_macro_bodies` -Format the bodies of macros. +Format the bodies of declarative macro definitions. - **Default value**: `true` - **Possible values**: `true`, `false` @@ -1248,12 +1258,20 @@ Control the case of the letters in hexadecimal literal values ## `hide_parse_errors` -Do not show parse errors if the parser failed to parse files. +This option is deprecated and has been renamed to `show_parse_errors` to avoid confusion around the double negative default of `hide_parse_errors=false`. - **Default value**: `false` - **Possible values**: `true`, `false` - **Stable**: No (tracking issue: [#3390](https://github.com/rust-lang/rustfmt/issues/3390)) +## `show_parse_errors` + +Show parse errors if the parser failed to parse files. + +- **Default value**: `true` +- **Possible values**: `true`, `false` +- **Stable**: No (tracking issue: [#5977](https://github.com/rust-lang/rustfmt/issues/5977)) + ## `ignore` Skip formatting files and directories that match the specified pattern. @@ -1288,6 +1306,15 @@ If you want to ignore every file under the directory where you put your rustfmt. ignore = ["/"] ``` +If you want to allow specific paths that would otherwise be ignored, prefix those paths with a `!`: + +```toml +ignore = ["bar_dir/*", "!bar_dir/*/what.rs"] +``` + +In this case, all files under `bar_dir` will be ignored, except files like `bar_dir/sub/what.rs` +or `bar_dir/another/what.rs`. + ## `imports_indent` Indent style of imports @@ -1655,7 +1682,7 @@ use core::slice; Controls whether arm bodies are wrapped in cases where the first line of the body cannot fit on the same line as the `=>` operator. -The Style Guide requires that bodies are block wrapped by default if a line break is required after the `=>`, but this option can be used to disable that behavior to prevent wrapping arm bodies in that event, so long as the body does not contain multiple statements nor line comments. +The Style Guide requires that bodies are block wrapped by default if a line break is required after the `=>`, but this option can be used to disable that behavior to prevent wrapping arm bodies in that event, so long as the body contains neither multiple statements nor line comments. - **Default value**: `true` - **Possible values**: `true`, `false` diff --git a/src/tools/rustfmt/Contributing.md b/src/tools/rustfmt/Contributing.md index 69a2c76369f..2f2ccfb175a 100644 --- a/src/tools/rustfmt/Contributing.md +++ b/src/tools/rustfmt/Contributing.md @@ -59,7 +59,7 @@ example, the `issue-1111.rs` test file is configured by the file ## Debugging Some `rewrite_*` methods use the `debug!` macro for printing useful information. -These messages can be printed by using the environment variable `RUSTFMT_LOG=rustfmt=DEBUG`. +These messages can be printed by using the environment variable `RUSTFMT_LOG=debug`. These traces can be helpful in understanding which part of the code was used and get a better grasp on the execution flow. diff --git a/src/tools/rustfmt/Processes.md b/src/tools/rustfmt/Processes.md index 61abc87eec9..64ef20a9bd7 100644 --- a/src/tools/rustfmt/Processes.md +++ b/src/tools/rustfmt/Processes.md @@ -16,7 +16,7 @@ In this Section, we describe how to stabilise an option of the rustfmt's configu Open a pull request that closes the tracking issue. The tracking issue is listed beside the option in `Configurations.md`. - Update the `Config` enum marking the option as stable. -- Update the the `Configuration.md` file marking the option as stable. +- Update the `Configuration.md` file marking the option as stable. - Update `CHANGELOG.md` marking the option as stable. ## After the stabilisation diff --git a/src/tools/rustfmt/build.rs b/src/tools/rustfmt/build.rs index e7b1e1b854c..9a8bb77a8ed 100644 --- a/src/tools/rustfmt/build.rs +++ b/src/tools/rustfmt/build.rs @@ -40,7 +40,7 @@ fn channel() -> String { fn commit_hash() -> Option<String> { Command::new("git") - .args(&["rev-parse", "--short", "HEAD"]) + .args(["rev-parse", "--short", "HEAD"]) .output() .ok() .and_then(|r| String::from_utf8(r.stdout).ok()) @@ -48,7 +48,7 @@ fn commit_hash() -> Option<String> { fn commit_date() -> Option<String> { Command::new("git") - .args(&["log", "-1", "--date=short", "--pretty=format:%cd"]) + .args(["log", "-1", "--date=short", "--pretty=format:%cd"]) .output() .ok() .and_then(|r| String::from_utf8(r.stdout).ok()) diff --git a/src/tools/rustfmt/check_diff/.gitignore b/src/tools/rustfmt/check_diff/.gitignore new file mode 100644 index 00000000000..ea8c4bf7f35 --- /dev/null +++ b/src/tools/rustfmt/check_diff/.gitignore @@ -0,0 +1 @@ +/target diff --git a/src/tools/rustfmt/check_diff/Cargo.lock b/src/tools/rustfmt/check_diff/Cargo.lock new file mode 100644 index 00000000000..6716ccdf9a0 --- /dev/null +++ b/src/tools/rustfmt/check_diff/Cargo.lock @@ -0,0 +1,237 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "check_diff" +version = "0.1.0" +dependencies = [ + "clap", +] + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "proc-macro2" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/src/tools/rustfmt/check_diff/Cargo.toml b/src/tools/rustfmt/check_diff/Cargo.toml new file mode 100644 index 00000000000..a1ed154481a --- /dev/null +++ b/src/tools/rustfmt/check_diff/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "check_diff" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4.4.2", features = ["derive"] } diff --git a/src/tools/rustfmt/check_diff/src/main.rs b/src/tools/rustfmt/check_diff/src/main.rs new file mode 100644 index 00000000000..6d07c1b0df6 --- /dev/null +++ b/src/tools/rustfmt/check_diff/src/main.rs @@ -0,0 +1,25 @@ +use clap::Parser; +/// Inputs for the check_diff script +#[derive(Parser)] +struct CliInputs { + /// Git url of a rustfmt fork to compare against the latest master rustfmt + remote_repo_url: String, + /// Name of the feature branch on the forked repo + feature_branch: String, + /// Optional commit hash from the feature branch + #[arg(short, long)] + commit_hash: Option<String>, + /// Optional comma separated list of rustfmt config options to + /// pass when running the feature branch + #[arg(value_delimiter = ',', short, long, num_args = 1..)] + rustfmt_config: Option<Vec<String>>, +} + +fn main() { + let args = CliInputs::parse(); + println!( + "remote_repo_url: {:?}, feature_branch: {:?}, + optional_commit_hash: {:?}, optional_rustfmt_config: {:?}", + args.remote_repo_url, args.feature_branch, args.commit_hash, args.rustfmt_config + ); +} diff --git a/src/tools/rustfmt/ci/check_diff.sh b/src/tools/rustfmt/ci/check_diff.sh index 50c58b1f492..2a29cb138ef 100755 --- a/src/tools/rustfmt/ci/check_diff.sh +++ b/src/tools/rustfmt/ci/check_diff.sh @@ -2,9 +2,6 @@ set -e -# https://github.com/rust-lang/rustfmt/issues/5675 -export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH - function print_usage() { echo "usage check_diff REMOTE_REPO FEATURE_BRANCH [COMMIT_HASH] [OPTIONAL_RUSTFMT_CONFIGS]" } @@ -31,7 +28,7 @@ function clone_repo() { GIT_TERMINAL_PROMPT=0 git clone --quiet $1 --depth 1 $2 && cd $2 } -# Initialize Git submoduels for the repo. +# Initialize Git submodules for the repo. # # Parameters # $1: list of directories to initialize @@ -46,7 +43,7 @@ function init_submodules() { # $2: Output file path for the diff # $3: Any additional configuration options to pass to rustfmt # -# Globlas: +# Globals: # $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4 function create_diff() { local config; @@ -67,7 +64,7 @@ function create_diff() { # Parameters # $1: Name of the repository (used for logging) # -# Globlas: +# Globals: # $RUSFMT_BIN: Path to the rustfmt master binary. Created when running `compile_rustfmt` # $FEATURE_BIN: Path to the rustfmt feature binary. Created when running `compile_rustfmt` # $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4 @@ -90,7 +87,7 @@ function check_diff() { ) if [ -z "$diff" ]; then - echo "no diff detected between rustfmt and the feture branch" + echo "no diff detected between rustfmt and the feature branch" return 0 else echo "$diff" @@ -104,7 +101,7 @@ function check_diff() { # Parameters: # $1: Directory where rustfmt will be cloned # -# Globlas: +# Globals: # $REMOTE_REPO: Clone URL to the rustfmt fork that we want to test # $FEATURE_BRANCH: Name of the feature branch # $OPTIONAL_COMMIT_HASH: Optional commit hash that will be checked out if provided @@ -114,15 +111,42 @@ function compile_rustfmt() { git remote add feature $REMOTE_REPO git fetch feature $FEATURE_BRANCH - cargo build --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt + CARGO_VERSION=$(cargo --version) + echo -e "\ncompiling with $CARGO_VERSION\n" + + # Because we're building standalone binaries we need to set `LD_LIBRARY_PATH` so each + # binary can find it's runtime dependencies. See https://github.com/rust-lang/rustfmt/issues/5675 + # This will prepend the `LD_LIBRARY_PATH` for the master rustfmt binary + export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH + + echo "Building rustfmt from src" + cargo build -q --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt + if [ -z "$OPTIONAL_COMMIT_HASH" ] || [ "$FEATURE_BRANCH" = "$OPTIONAL_COMMIT_HASH" ]; then git switch $FEATURE_BRANCH else git switch $OPTIONAL_COMMIT_HASH --detach fi - cargo build --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt + + # This will prepend the `LD_LIBRARY_PATH` for the feature branch rustfmt binary. + # In most cases the `LD_LIBRARY_PATH` should be the same for both rustfmt binaries that we build + # in `compile_rustfmt`, however, there are scenarios where each binary has different runtime + # dependencies. For example, during subtree syncs we bump the nightly toolchain required to build + # rustfmt, and therefore the feature branch relies on a newer set of runtime dependencies. + export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH + + echo "Building feature rustfmt from src" + cargo build -q --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt + + echo -e "\nRuntime dependencies for rustfmt -- LD_LIBRARY_PATH: $LD_LIBRARY_PATH" + RUSFMT_BIN=$1/rustfmt + RUSTFMT_VERSION=$($RUSFMT_BIN --version) + echo -e "\nRUSFMT_BIN $RUSTFMT_VERSION\n" + FEATURE_BIN=$1/feature_rustfmt + FEATURE_VERSION=$($FEATURE_BIN --version) + echo -e "FEATURE_BIN $FEATURE_VERSION\n" } # Check the diff for running rustfmt and the feature branch on all the .rs files in the repo. @@ -155,7 +179,7 @@ function check_repo() { STATUSES+=($?) set -e - echo "removing tmp_dir $tmp_dir" + echo -e "removing tmp_dir $tmp_dir\n\n" rm -rf $tmp_dir cd $WORKDIR } diff --git a/src/tools/rustfmt/ci/integration.sh b/src/tools/rustfmt/ci/integration.sh index 19d502bc5c7..ea96e4be130 100755 --- a/src/tools/rustfmt/ci/integration.sh +++ b/src/tools/rustfmt/ci/integration.sh @@ -104,7 +104,7 @@ case ${INTEGRATION} in check_fmt_with_all_tests cd - ;; - error-chain | tempdir) + tempdir) git clone --depth=1 https://github.com/rust-lang-deprecated/${INTEGRATION}.git cd ${INTEGRATION} show_head diff --git a/src/tools/rustfmt/config_proc_macro/src/attrs.rs b/src/tools/rustfmt/config_proc_macro/src/attrs.rs index d8de9aae088..e7534b813d7 100644 --- a/src/tools/rustfmt/config_proc_macro/src/attrs.rs +++ b/src/tools/rustfmt/config_proc_macro/src/attrs.rs @@ -68,7 +68,11 @@ fn get_name_value_str_lit(attr: &syn::Attribute, name: &str) -> Option<String> { match &attr.meta { syn::Meta::NameValue(syn::MetaNameValue { path, - value: syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(lit_str), .. }), + value: + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit_str), + .. + }), .. }) if path.is_ident(name) => Some(lit_str.value()), _ => None, diff --git a/src/tools/rustfmt/docs/index.html b/src/tools/rustfmt/docs/index.html index ee0339bc50d..5e588d1db54 100644 --- a/src/tools/rustfmt/docs/index.html +++ b/src/tools/rustfmt/docs/index.html @@ -3,13 +3,33 @@ <head> <meta name="viewport" content="width=device-width"> <title>Rustfmt</title> - <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/3.0.1/github-markdown.css" /> - <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/styles/github-gist.min.css"> - <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> - <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> + <link rel="stylesheet" + href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/3.0.1/github-markdown.min.css" + integrity="sha512-7e0rszTy0dKTIgYzCeBXpmycq0EOkwAvxZ0dv/LAtQfcXWCoaRhzs+v2Mn6of3jImxPazbYxiK0kpE/7wZ/UQA==" + crossorigin="anonymous" + referrerpolicy="no-referrer" /> + <link rel="stylesheet" + href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/styles/github-gist.min.css" + integrity="sha512-od7JLoOTxM8w/HSKGzP9Kexc20K9p/M2zxSWsd7H1e4Ctf+8SQFtCWEZnW5u6ul5ehSECa5QmOk9ju2nQMmlVA==" + crossorigin="anonymous" + referrerpolicy="no-referrer" /> + <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.2/marked.min.js" + integrity="sha512-xeUh+KxNyTufZOje++oQHstlMQ8/rpyzPuM+gjMFYK3z5ILJGE7l2NvYL+XfliKURMpBIKKp1XoPN/qswlSMFA==" + crossorigin="anonymous" + referrerpolicy="no-referrer"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js" + integrity="sha512-PwQ5+jgXxxprNGc80ycHE3spgj6TuDieHe/yTkbEJ+U5aol7dTupi/4VbwHHzlQVW77Vb0GLOIsiYigHgC5vcg==" + crossorigin="anonymous" + referrerpolicy="no-referrer"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/highlight.min.js" + integrity="sha512-av6ZR84Ldk6j29DMhf6v0cssEhow1VROFLoKbX7wrvzZB++/nV8m0jXbYeWcHPEzSNONImx6zwBskCUT9AQidA==" + crossorigin="anonymous" + referrerpolicy="no-referrer"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js" + integrity="sha512-3BBFWr73Xrf8GRjO+0pl0cbVwESBvg3ovnuCXpoqOkC/mkt/hTkFtutUPrwRz8eLySYvy5v1daulkyUZYvH8jw==" + crossorigin="anonymous" + referrerpolicy="no-referrer"></script> <script src="https://unpkg.com/vue-async-computed@3.8.1"></script> - <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/highlight.min.js"></script> - <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script> <style> @media (max-width: 767px) { .markdown-body { diff --git a/src/tools/rustfmt/intellij.md b/src/tools/rustfmt/intellij.md index 6a711c0171a..70170df388f 100644 --- a/src/tools/rustfmt/intellij.md +++ b/src/tools/rustfmt/intellij.md @@ -20,7 +20,7 @@ - Open Rustfmt settings (File → Settings → Languages & Frameworks → Rust → Rustfmt) and enable "Run rustfmt on Save"  -- IntellJ uses autosave, so now your files will always be formatted according to rustfmt. Alternatively you can use Ctrl+S to reformat file manually +- IntelliJ uses autosave, so now your files will always be formatted according to rustfmt. Alternatively you can use Ctrl+S to reformat file manually ### Bind shortcut to "Reformat File with Rustfmt" action diff --git a/src/tools/rustfmt/rust-toolchain b/src/tools/rustfmt/rust-toolchain index 0057e2f370a..25e3961d32a 100644 --- a/src/tools/rustfmt/rust-toolchain +++ b/src/tools/rustfmt/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-10-22" +channel = "nightly-2024-06-13" components = ["llvm-tools", "rustc-dev"] diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index 83f59837d44..433b9256202 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -353,10 +353,18 @@ impl Rewrite for ast::Attribute { // 1 = `[` let shape = shape.offset_left(prefix.len() + 1)?; - Some( - meta.rewrite(context, shape) - .map_or_else(|| snippet.to_owned(), |rw| format!("{}[{}]", prefix, rw)), - ) + Some(meta.rewrite(context, shape).map_or_else( + || snippet.to_owned(), + |rw| match &self.kind { + ast::AttrKind::Normal(normal_attr) => match normal_attr.item.unsafety { + // For #![feature(unsafe_attributes)] + // See https://github.com/rust-lang/rust/issues/123757 + ast::Safety::Unsafe(_) => format!("{}[unsafe({})]", prefix, rw), + _ => format!("{}[{}]", prefix, rw), + }, + _ => format!("{}[{}]", prefix, rw), + }, + )) } else { Some(snippet.to_owned()) } diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs index 6f564083656..88281d296be 100644 --- a/src/tools/rustfmt/src/bin/main.rs +++ b/src/tools/rustfmt/src/bin/main.rs @@ -387,16 +387,11 @@ fn format_and_emit_report<T: Write>(session: &mut Session<'_, T>, input: Input) } fn should_print_with_colors<T: Write>(session: &mut Session<'_, T>) -> bool { - match term::stderr() { - Some(ref t) - if session.config.color().use_colored_tty() - && t.supports_color() - && t.supports_attr(term::Attr::Bold) => - { - true - } - _ => false, - } + term::stderr().is_some_and(|t| { + session.config.color().use_colored_tty() + && t.supports_color() + && t.supports_attr(term::Attr::Bold) + }) } fn print_usage_to_stdout(opts: &Options, reason: &str) { @@ -445,7 +440,7 @@ fn print_version() { fn determine_operation(matches: &Matches) -> Result<Operation, OperationError> { if matches.opt_present("h") { let topic = matches.opt_str("h"); - if topic == None { + if topic.is_none() { return Ok(Operation::Help(HelpOp::None)); } else if topic == Some("config".to_owned()) { return Ok(Operation::Help(HelpOp::Config)); diff --git a/src/tools/rustfmt/src/cargo-fmt/main.rs b/src/tools/rustfmt/src/cargo-fmt/main.rs index a1ad1aafac4..eedb43defb9 100644 --- a/src/tools/rustfmt/src/cargo-fmt/main.rs +++ b/src/tools/rustfmt/src/cargo-fmt/main.rs @@ -61,7 +61,7 @@ pub struct Opts { /// Options passed to rustfmt // 'raw = true' to make `--` explicit. - #[arg(name = "rustfmt_options", raw = true)] + #[arg(id = "rustfmt_options", raw = true)] rustfmt_options: Vec<String>, /// Format all packages, and also their local path-based dependencies @@ -209,9 +209,8 @@ fn convert_message_format_to_rustfmt_args( fn print_usage_to_stderr(reason: &str) { eprintln!("{reason}"); let app = Opts::command(); - app.after_help("") - .write_help(&mut io::stderr()) - .expect("failed to write to stderr"); + let help = app.after_help("").render_help(); + eprintln!("{help}"); } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -507,7 +506,7 @@ fn run_rustfmt( let mut command = rustfmt_command() .stdout(stdout) .args(files) - .args(&["--edition", edition.as_str()]) + .args(["--edition", edition.as_str()]) .args(fmt_args) .spawn() .map_err(|e| match e.kind() { diff --git a/src/tools/rustfmt/src/cargo-fmt/test/mod.rs b/src/tools/rustfmt/src/cargo-fmt/test/mod.rs index 696326e4f94..255e0d679d4 100644 --- a/src/tools/rustfmt/src/cargo-fmt/test/mod.rs +++ b/src/tools/rustfmt/src/cargo-fmt/test/mod.rs @@ -20,7 +20,7 @@ fn default_options() { #[test] fn good_options() { - let o = Opts::parse_from(&[ + let o = Opts::parse_from([ "test", "-q", "-p", @@ -48,7 +48,7 @@ fn good_options() { fn unexpected_option() { assert!( Opts::command() - .try_get_matches_from(&["test", "unexpected"]) + .try_get_matches_from(["test", "unexpected"]) .is_err() ); } @@ -57,7 +57,7 @@ fn unexpected_option() { fn unexpected_flag() { assert!( Opts::command() - .try_get_matches_from(&["test", "--flag"]) + .try_get_matches_from(["test", "--flag"]) .is_err() ); } @@ -66,19 +66,19 @@ fn unexpected_flag() { fn mandatory_separator() { assert!( Opts::command() - .try_get_matches_from(&["test", "--emit"]) + .try_get_matches_from(["test", "--emit"]) .is_err() ); assert!( Opts::command() - .try_get_matches_from(&["test", "--", "--emit"]) + .try_get_matches_from(["test", "--", "--emit"]) .is_ok() ); } #[test] fn multiple_packages_one_by_one() { - let o = Opts::parse_from(&[ + let o = Opts::parse_from([ "test", "-p", "package1", @@ -92,7 +92,7 @@ fn multiple_packages_one_by_one() { #[test] fn multiple_packages_grouped() { - let o = Opts::parse_from(&[ + let o = Opts::parse_from([ "test", "--package", "package1", @@ -108,7 +108,7 @@ fn multiple_packages_grouped() { fn empty_packages_1() { assert!( Opts::command() - .try_get_matches_from(&["test", "-p"]) + .try_get_matches_from(["test", "-p"]) .is_err() ); } @@ -117,7 +117,7 @@ fn empty_packages_1() { fn empty_packages_2() { assert!( Opts::command() - .try_get_matches_from(&["test", "-p", "--", "--check"]) + .try_get_matches_from(["test", "-p", "--", "--check"]) .is_err() ); } @@ -126,7 +126,7 @@ fn empty_packages_2() { fn empty_packages_3() { assert!( Opts::command() - .try_get_matches_from(&["test", "-p", "--verbose"]) + .try_get_matches_from(["test", "-p", "--verbose"]) .is_err() ); } @@ -135,7 +135,7 @@ fn empty_packages_3() { fn empty_packages_4() { assert!( Opts::command() - .try_get_matches_from(&["test", "-p", "--check"]) + .try_get_matches_from(["test", "-p", "--check"]) .is_err() ); } diff --git a/src/tools/rustfmt/src/comment.rs b/src/tools/rustfmt/src/comment.rs index 7d1b0384431..24a5a1be2c3 100644 --- a/src/tools/rustfmt/src/comment.rs +++ b/src/tools/rustfmt/src/comment.rs @@ -3,8 +3,6 @@ use std::{borrow::Cow, iter}; use itertools::{multipeek, MultiPeek}; -use lazy_static::lazy_static; -use regex::Regex; use rustc_span::Span; use crate::config::Config; @@ -17,17 +15,6 @@ use crate::utils::{ }; use crate::{ErrorKind, FormattingError}; -lazy_static! { - /// A regex matching reference doc links. - /// - /// ```markdown - /// /// An [example]. - /// /// - /// /// [example]: this::is::a::link - /// ``` - static ref REFERENCE_LINK_URL: Regex = Regex::new(r"^\[.+\]\s?:").unwrap(); -} - fn is_custom_comment(comment: &str) -> bool { if !comment.starts_with("//") { false @@ -173,10 +160,7 @@ pub(crate) fn combine_strs_with_missing_comments( ) -> Option<String> { trace!( "combine_strs_with_missing_comments `{}` `{}` {:?} {:?}", - prev_str, - next_str, - span, - shape + prev_str, next_str, span, shape ); let mut result = @@ -208,7 +192,7 @@ pub(crate) fn combine_strs_with_missing_comments( // We have a missing comment between the first expression and the second expression. - // Peek the the original source code and find out whether there is a newline between the first + // Peek the original source code and find out whether there is a newline between the first // expression and the second expression or the missing comment. We will preserve the original // layout whenever possible. let original_snippet = context.snippet(span); @@ -506,7 +490,7 @@ impl ItemizedBlock { let mut line_start = " ".repeat(indent); // Markdown blockquote start with a "> " - if line.trim_start().starts_with(">") { + if line.trim_start().starts_with('>') { // remove the original +2 indent because there might be multiple nested block quotes // and it's easier to reason about the final indent by just taking the length // of the new line_start. We update the indent because it effects the max width @@ -657,7 +641,7 @@ impl<'a> CommentRewrite<'a> { while let Some(line) = iter.next() { result.push_str(line); result.push_str(match iter.peek() { - Some(next_line) if next_line.is_empty() => sep.trim_end(), + Some(&"") => sep.trim_end(), Some(..) => sep, None => "", }); @@ -666,7 +650,7 @@ impl<'a> CommentRewrite<'a> { } /// Check if any characters were written to the result buffer after the start of the comment. - /// when calling [`CommentRewrite::new()`] the result buffer is initiazlied with the opening + /// when calling [`CommentRewrite::new()`] the result buffer is initialized with the opening /// characters for the comment. fn buffer_contains_comment(&self) -> bool { // if self.result.len() < self.opener.len() then an empty comment is in the buffer @@ -839,7 +823,7 @@ impl<'a> CommentRewrite<'a> { } } - let is_markdown_header_doc_comment = is_doc_comment && line.starts_with("#"); + let is_markdown_header_doc_comment = is_doc_comment && line.starts_with('#'); // We only want to wrap the comment if: // 1) wrap_comments = true is configured @@ -979,12 +963,21 @@ fn trim_custom_comment_prefix(s: &str) -> String { /// Returns `true` if the given string MAY include URLs or alike. fn has_url(s: &str) -> bool { + // A regex matching reference doc links. + // + // ```markdown + // /// An [example]. + // /// + // /// [example]: this::is::a::link + // ``` + let reference_link_url = static_regex!(r"^\[.+\]\s?:"); + // This function may return false positive, but should get its job done in most cases. s.contains("https://") || s.contains("http://") || s.contains("ftp://") || s.contains("file://") - || REFERENCE_LINK_URL.is_match(s) + || reference_link_url.is_match(s) } /// Returns true if the given string may be part of a Markdown table. @@ -1263,15 +1256,15 @@ pub(crate) enum FullCodeCharKind { InComment, /// Last character of a comment, '\n' for a line comment, '/' for a block comment. EndComment, - /// Start of a mutlitine string inside a comment + /// Start of a multiline string inside a comment StartStringCommented, - /// End of a mutlitine string inside a comment + /// End of a multiline string inside a comment EndStringCommented, /// Inside a commented string InStringCommented, - /// Start of a mutlitine string + /// Start of a multiline string StartString, - /// End of a mutlitine string + /// End of a multiline string EndString, /// Inside a string. InString, @@ -1764,7 +1757,7 @@ fn changed_comment_content(orig: &str, new: &str) -> bool { let code_comment_content = |code| { let slices = UngroupedCommentCodeSlices::new(code); slices - .filter(|&(ref kind, _, _)| *kind == CodeCharKind::Comment) + .filter(|(kind, _, _)| *kind == CodeCharKind::Comment) .flat_map(|(_, _, s)| CommentReducer::new(s)) }; let res = code_comment_content(orig).ne(code_comment_content(new)); diff --git a/src/tools/rustfmt/src/config/config_type.rs b/src/tools/rustfmt/src/config/config_type.rs index feb452d7235..f7cff1a1729 100644 --- a/src/tools/rustfmt/src/config/config_type.rs +++ b/src/tools/rustfmt/src/config/config_type.rs @@ -66,7 +66,7 @@ impl ConfigType for IgnoreList { } macro_rules! create_config { - // Options passed in to the macro. + // Options passed into the macro. // // - $i: the ident name of the option // - $ty: the type of the option value @@ -129,6 +129,7 @@ macro_rules! create_config { | "chain_width" => self.0.set_heuristics(), "merge_imports" => self.0.set_merge_imports(), "fn_args_layout" => self.0.set_fn_args_layout(), + "hide_parse_errors" => self.0.set_hide_parse_errors(), &_ => (), } } @@ -184,6 +185,7 @@ macro_rules! create_config { self.set_ignore(dir); self.set_merge_imports(); self.set_fn_args_layout(); + self.set_hide_parse_errors(); self } @@ -278,19 +280,21 @@ macro_rules! create_config { | "chain_width" => self.set_heuristics(), "merge_imports" => self.set_merge_imports(), "fn_args_layout" => self.set_fn_args_layout(), + "hide_parse_errors" => self.set_hide_parse_errors(), &_ => (), } } #[allow(unreachable_pub)] pub fn is_hidden_option(name: &str) -> bool { - const HIDE_OPTIONS: [&str; 6] = [ + const HIDE_OPTIONS: [&str; 7] = [ "verbose", "verbose_diff", "file_lines", "width_heuristics", "merge_imports", - "fn_args_layout" + "fn_args_layout", + "hide_parse_errors" ]; HIDE_OPTIONS.contains(&name) } @@ -461,6 +465,18 @@ macro_rules! create_config { } } + fn set_hide_parse_errors(&mut self) { + if self.was_set().hide_parse_errors() { + eprintln!( + "Warning: the `hide_parse_errors` option is deprecated. \ + Use `show_parse_errors` instead" + ); + if !self.was_set().show_parse_errors() { + self.show_parse_errors.2 = self.hide_parse_errors(); + } + } + } + #[allow(unreachable_pub)] /// Returns `true` if the config key was explicitly set and is the default value. pub fn is_default(&self, key: &str) -> bool { diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs index 9d454137b2c..9484b2e5829 100644 --- a/src/tools/rustfmt/src/config/mod.rs +++ b/src/tools/rustfmt/src/config/mod.rs @@ -26,6 +26,7 @@ pub(crate) mod file_lines; #[allow(unreachable_pub)] pub(crate) mod lists; pub(crate) mod macro_names; +pub(crate) mod style_edition; // This macro defines configuration options used in rustfmt. Each option // is defined as follows: @@ -73,7 +74,7 @@ create_config! { format_strings: bool, false, false, "Format string literals where necessary"; format_macro_matchers: bool, false, false, "Format the metavariable matching patterns in macros"; - format_macro_bodies: bool, true, false, "Format the bodies of macros"; + format_macro_bodies: bool, true, false, "Format the bodies of declarative macro definitions"; skip_macro_invocations: MacroSelectors, MacroSelectors::default(), false, "Skip formatting the bodies of macros invoked with the following names."; hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false, @@ -150,6 +151,8 @@ create_config! { "Write an item and its attribute on the same line \ if their combined width is below a threshold"; format_generated_files: bool, true, false, "Format generated files"; + generated_marker_line_search_limit: usize, 5, false, "Number of lines to check for a \ + `@generated` marker when `format_generated_files` is enabled"; // Options that can change the source code beyond whitespace/blocks (somewhat linty things) merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one"; @@ -168,7 +171,8 @@ create_config! { "Enables unstable features. Only available on nightly channel"; disable_all_formatting: bool, false, true, "Don't reformat anything"; skip_children: bool, false, false, "Don't reformat out of line modules"; - hide_parse_errors: bool, false, false, "Hide errors from the parser"; + hide_parse_errors: bool, false, false, "(deprecated: use show_parse_errors instead)"; + show_parse_errors: bool, true, false, "Show errors from the parser (unstable)"; error_on_line_overflow: bool, false, false, "Error if unable to get all lines within max_width"; error_on_unformatted: bool, false, false, "Error if unable to get comments or string literals within max_width, \ @@ -203,6 +207,7 @@ impl PartialConfig { cloned.print_misformatted_file_names = None; cloned.merge_imports = None; cloned.fn_args_layout = None; + cloned.hide_parse_errors = None; ::toml::to_string(&cloned).map_err(ToTomlError) } @@ -282,7 +287,7 @@ impl Config { } } - // If none was found ther either, check in the user's configuration directory. + // If none was found there either, check in the user's configuration directory. if let Some(mut config_dir) = dirs::config_dir() { config_dir.push("rustfmt"); if let Some(path) = get_toml_path(&config_dir)? { @@ -455,6 +460,13 @@ mod test { fn_params_layout: Density, Density::Tall, true, "Control the layout of parameters in a function signatures."; + // hide_parse_errors renamed to show_parse_errors + hide_parse_errors: bool, false, false, + "(deprecated: use show_parse_errors instead)"; + show_parse_errors: bool, true, false, + "Show errors from the parser (unstable)"; + + // Width Heuristics use_small_heuristics: Heuristics, Heuristics::Default, true, "Whether to use different formatting for items and \ @@ -670,6 +682,7 @@ edition = "2015" version = "One" inline_attribute_width = 0 format_generated_files = true +generated_marker_line_search_limit = 5 merge_derives = true use_try_shorthand = false use_field_init_shorthand = false @@ -680,7 +693,7 @@ required_version = "{}" unstable_features = false disable_all_formatting = false skip_children = false -hide_parse_errors = false +show_parse_errors = true error_on_line_overflow = false error_on_unformatted = false ignore = [] diff --git a/src/tools/rustfmt/src/config/options.rs b/src/tools/rustfmt/src/config/options.rs index 03fd91eb10f..3c5c713a33a 100644 --- a/src/tools/rustfmt/src/config/options.rs +++ b/src/tools/rustfmt/src/config/options.rs @@ -191,7 +191,7 @@ pub enum Color { pub enum Version { /// 1.x.y. When specified, rustfmt will format in the same style as 1.0.0. One, - /// 2.x.y. When specified, rustfmt will format in the the latest style. + /// 2.x.y. When specified, rustfmt will format in the latest style. Two, } @@ -416,7 +416,7 @@ pub trait CliOptions { fn config_path(&self) -> Option<&Path>; } -/// The edition of the syntax and semntics of code (RFC 2052). +/// The edition of the syntax and semantics of code (RFC 2052). #[config_type] pub enum Edition { #[value = "2015"] @@ -470,3 +470,27 @@ pub enum MatchArmLeadingPipe { /// Preserve any existing leading pipes Preserve, } + +/// Defines the default values for each config according to [the style guide]. +/// rustfmt output may differ between style editions. +/// +/// [the style guide]: https://doc.rust-lang.org/nightly/style-guide/ +#[config_type] +pub enum StyleEdition { + #[value = "2015"] + #[doc_hint = "2015"] + /// [Edition 2015]() + Edition2015, + #[value = "2018"] + #[doc_hint = "2018"] + /// [Edition 2018]() + Edition2018, + #[value = "2021"] + #[doc_hint = "2021"] + /// [Edition 2021]() + Edition2021, + #[value = "2024"] + #[doc_hint = "2024"] + /// [Edition 2024](). + Edition2024, +} diff --git a/src/tools/rustfmt/src/config/style_edition.rs b/src/tools/rustfmt/src/config/style_edition.rs new file mode 100644 index 00000000000..7b3ea3bc119 --- /dev/null +++ b/src/tools/rustfmt/src/config/style_edition.rs @@ -0,0 +1,70 @@ +use crate::config::StyleEdition; + +/// Defines the default value for the given style edition +#[allow(dead_code)] +pub(crate) trait StyleEditionDefault { + type ConfigType; + fn style_edition_default(style_edition: StyleEdition) -> Self::ConfigType; +} + +/// macro to help implement `StyleEditionDefault` for config options +#[macro_export] +macro_rules! style_edition_default { + ($ty:ident, $config_ty:ty, _ => $default:expr) => { + impl $crate::config::style_edition::StyleEditionDefault for $ty { + type ConfigType = $config_ty; + + fn style_edition_default(_: $crate::config::StyleEdition) -> Self::ConfigType { + $default + } + } + }; + ($ty:ident, $config_ty:ty, Edition2024 => $default_2024:expr, _ => $default_2015:expr) => { + impl $crate::config::style_edition::StyleEditionDefault for $ty { + type ConfigType = $config_ty; + + fn style_edition_default( + style_edition: $crate::config::StyleEdition, + ) -> Self::ConfigType { + match style_edition { + $crate::config::StyleEdition::Edition2015 + | $crate::config::StyleEdition::Edition2018 + | $crate::config::StyleEdition::Edition2021 => $default_2015, + $crate::config::StyleEdition::Edition2024 => $default_2024, + } + } + } + }; +} + +#[cfg(test)] +mod test { + use super::*; + use crate::config::StyleEdition; + + #[test] + fn test_impl_default_style_edition_struct_for_all_editions() { + struct Unit; + style_edition_default!(Unit, usize, _ => 100); + + // regardless of the style edition used the value will always return 100 + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2015), 100); + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2018), 100); + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2021), 100); + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2024), 100); + } + + #[test] + fn test_impl_default_style_edition_for_old_and_new_editions() { + struct Unit; + style_edition_default!(Unit, usize, Edition2024 => 50, _ => 100); + + // style edition 2015-2021 are all the same + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2015), 100); + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2018), 100); + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2021), 100); + + // style edition 2024 + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2024), 50); + } +} diff --git a/src/tools/rustfmt/src/emitter/checkstyle.rs b/src/tools/rustfmt/src/emitter/checkstyle.rs index 2a4a9dfce8e..9385ae59a06 100644 --- a/src/tools/rustfmt/src/emitter/checkstyle.rs +++ b/src/tools/rustfmt/src/emitter/checkstyle.rs @@ -89,11 +89,11 @@ mod tests { #[test] fn emits_single_xml_tree_containing_all_files() { let bin_file = "src/bin.rs"; - let bin_original = vec!["fn main() {", "println!(\"Hello, world!\");", "}"]; - let bin_formatted = vec!["fn main() {", " println!(\"Hello, world!\");", "}"]; + let bin_original = ["fn main() {", "println!(\"Hello, world!\");", "}"]; + let bin_formatted = ["fn main() {", " println!(\"Hello, world!\");", "}"]; let lib_file = "src/lib.rs"; - let lib_original = vec!["fn greet() {", "println!(\"Greetings!\");", "}"]; - let lib_formatted = vec!["fn greet() {", " println!(\"Greetings!\");", "}"]; + let lib_original = ["fn greet() {", "println!(\"Greetings!\");", "}"]; + let lib_formatted = ["fn greet() {", " println!(\"Greetings!\");", "}"]; let mut writer = Vec::new(); let mut emitter = CheckstyleEmitter::default(); let _ = emitter.emit_header(&mut writer); @@ -118,7 +118,7 @@ mod tests { ) .unwrap(); let _ = emitter.emit_footer(&mut writer); - let exp_bin_xml = vec![ + let exp_bin_xml = [ format!(r#"<file name="{}">"#, bin_file), format!( r#"<error line="2" severity="warning" message="Should be `{}`" />"#, @@ -126,7 +126,7 @@ mod tests { ), String::from("</file>"), ]; - let exp_lib_xml = vec![ + let exp_lib_xml = [ format!(r#"<file name="{}">"#, lib_file), format!( r#"<error line="2" severity="warning" message="Should be `{}`" />"#, @@ -136,7 +136,7 @@ mod tests { ]; assert_eq!( String::from_utf8(writer).unwrap(), - vec![ + [ r#"<?xml version="1.0" encoding="utf-8"?>"#, "\n", r#"<checkstyle version="4.3">"#, diff --git a/src/tools/rustfmt/src/emitter/diff.rs b/src/tools/rustfmt/src/emitter/diff.rs index 0af19a7d0b2..4e48c59ea29 100644 --- a/src/tools/rustfmt/src/emitter/diff.rs +++ b/src/tools/rustfmt/src/emitter/diff.rs @@ -32,7 +32,7 @@ impl Emitter for DiffEmitter { } else { print_diff( mismatch, - |line_num| format!("Diff in {} at line {}:", filename, line_num), + |line_num| format!("Diff in {}:{}:", filename, line_num), &self.config, ); } diff --git a/src/tools/rustfmt/src/emitter/json.rs b/src/tools/rustfmt/src/emitter/json.rs index f47c3260a02..084f565804c 100644 --- a/src/tools/rustfmt/src/emitter/json.rs +++ b/src/tools/rustfmt/src/emitter/json.rs @@ -212,7 +212,7 @@ mod tests { #[test] fn emits_array_with_files_with_diffs() { let file_name = "src/bin.rs"; - let original = vec![ + let original = [ "fn main() {", "println!(\"Hello, world!\");", "}", @@ -225,7 +225,7 @@ mod tests { "}", "}", ]; - let formatted = vec![ + let formatted = [ "fn main() {", " println!(\"Hello, world!\");", "}", @@ -285,11 +285,11 @@ mod tests { #[test] fn emits_valid_json_with_multiple_files() { let bin_file = "src/bin.rs"; - let bin_original = vec!["fn main() {", "println!(\"Hello, world!\");", "}"]; - let bin_formatted = vec!["fn main() {", " println!(\"Hello, world!\");", "}"]; + let bin_original = ["fn main() {", "println!(\"Hello, world!\");", "}"]; + let bin_formatted = ["fn main() {", " println!(\"Hello, world!\");", "}"]; let lib_file = "src/lib.rs"; - let lib_original = vec!["fn greet() {", "println!(\"Greetings!\");", "}"]; - let lib_formatted = vec!["fn greet() {", " println!(\"Greetings!\");", "}"]; + let lib_original = ["fn greet() {", "println!(\"Greetings!\");", "}"]; + let lib_formatted = ["fn greet() {", " println!(\"Greetings!\");", "}"]; let mut writer = Vec::new(); let mut emitter = JsonEmitter::default(); let _ = emitter.emit_header(&mut writer); diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 053afcc52d4..8266f95fd70 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -139,7 +139,17 @@ pub(crate) fn format_expr( | ast::ExprKind::While(..) => to_control_flow(expr, expr_type) .and_then(|control_flow| control_flow.rewrite(context, shape)), ast::ExprKind::ConstBlock(ref anon_const) => { - Some(format!("const {}", anon_const.rewrite(context, shape)?)) + let rewrite = match anon_const.value.kind { + ast::ExprKind::Block(ref block, opt_label) => { + // Inner attributes are associated with the `ast::ExprKind::ConstBlock` node, + // not the `ast::Block` node we're about to rewrite. To prevent dropping inner + // attributes call `rewrite_block` directly. + // See https://github.com/rust-lang/rustfmt/issues/6158 + rewrite_block(block, Some(&expr.attrs), opt_label, context, shape)? + } + _ => anon_const.rewrite(context, shape)?, + }; + Some(format!("const {}", rewrite)) } ast::ExprKind::Block(ref block, opt_label) => { match expr_type { @@ -253,14 +263,6 @@ pub(crate) fn format_expr( shape, SeparatorPlace::Front, ), - ast::ExprKind::Type(ref expr, ref ty) => rewrite_pair( - &**expr, - &**ty, - PairParts::infix(": "), - context, - shape, - SeparatorPlace::Back, - ), ast::ExprKind::Index(ref expr, ref index, _) => { rewrite_index(&**expr, &**index, context, shape) } @@ -282,6 +284,9 @@ pub(crate) fn format_expr( match lhs.kind { ast::ExprKind::Lit(token_lit) => lit_ends_in_dot(&token_lit), ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr), + ast::ExprKind::Binary(_, _, ref rhs_expr) => { + needs_space_before_range(context, rhs_expr) + } _ => false, } } @@ -399,10 +404,14 @@ pub(crate) fn format_expr( } ast::ExprKind::Underscore => Some("_".to_owned()), ast::ExprKind::FormatArgs(..) + | ast::ExprKind::Type(..) | ast::ExprKind::IncludedBytes(..) | ast::ExprKind::OffsetOf(..) => { - // These do not occur in the AST because macros aren't expanded. - unreachable!() + // These don't normally occur in the AST because macros aren't expanded. However, + // rustfmt tries to parse macro arguments when formatting macros, so it's not totally + // impossible for rustfmt to come across one of these nodes when formatting a file. + // Also, rustfmt might get passed the output from `-Zunpretty=expanded`. + None } ast::ExprKind::Err(_) | ast::ExprKind::Dummy => None, }; diff --git a/src/tools/rustfmt/src/format-diff/main.rs b/src/tools/rustfmt/src/format-diff/main.rs index 61e2cb711a5..f9eb70f6e04 100644 --- a/src/tools/rustfmt/src/format-diff/main.rs +++ b/src/tools/rustfmt/src/format-diff/main.rs @@ -38,14 +38,14 @@ enum FormatDiffError { } #[derive(Parser, Debug)] -#[clap( +#[command( name = "rustfmt-format-diff", disable_version_flag = true, next_line_help = true )] pub struct Opts { /// Skip the smallest prefix containing NUMBER slashes - #[clap( + #[arg( short = 'p', long = "skip-prefix", value_name = "NUMBER", @@ -54,7 +54,7 @@ pub struct Opts { skip_prefix: u32, /// Custom pattern selecting file paths to reformat - #[clap( + #[arg( short = 'f', long = "filter", value_name = "PATTERN", @@ -234,14 +234,14 @@ mod cmd_line_tests { #[test] fn default_options() { let empty: Vec<String> = vec![]; - let o = Opts::parse_from(&empty); + let o = Opts::parse_from(empty); assert_eq!(DEFAULT_PATTERN, o.filter); assert_eq!(0, o.skip_prefix); } #[test] fn good_options() { - let o = Opts::parse_from(&["test", "-p", "10", "-f", r".*\.hs"]); + let o = Opts::parse_from(["test", "-p", "10", "-f", r".*\.hs"]); assert_eq!(r".*\.hs", o.filter); assert_eq!(10, o.skip_prefix); } @@ -250,7 +250,7 @@ mod cmd_line_tests { fn unexpected_option() { assert!( Opts::command() - .try_get_matches_from(&["test", "unexpected"]) + .try_get_matches_from(["test", "unexpected"]) .is_err() ); } @@ -259,7 +259,7 @@ mod cmd_line_tests { fn unexpected_flag() { assert!( Opts::command() - .try_get_matches_from(&["test", "--flag"]) + .try_get_matches_from(["test", "--flag"]) .is_err() ); } @@ -268,7 +268,7 @@ mod cmd_line_tests { fn overridden_option() { assert!( Opts::command() - .try_get_matches_from(&["test", "-p", "10", "-p", "20"]) + .try_get_matches_from(["test", "-p", "10", "-p", "20"]) .is_err() ); } @@ -277,7 +277,7 @@ mod cmd_line_tests { fn negative_filter() { assert!( Opts::command() - .try_get_matches_from(&["test", "-p", "-1"]) + .try_get_matches_from(["test", "-p", "-1"]) .is_err() ); } diff --git a/src/tools/rustfmt/src/formatting.rs b/src/tools/rustfmt/src/formatting.rs index 3bcb4d15184..7f442230b12 100644 --- a/src/tools/rustfmt/src/formatting.rs +++ b/src/tools/rustfmt/src/formatting.rs @@ -82,7 +82,7 @@ fn should_skip_module<T: FormatHandler>( let source_file = context.psess.span_to_file_contents(module.span); let src = source_file.src.as_ref().expect("SourceFile without src"); - if is_generated_file(src) { + if is_generated_file(src, config) { return true; } } diff --git a/src/tools/rustfmt/src/formatting/generated.rs b/src/tools/rustfmt/src/formatting/generated.rs index 58f43f17ee1..68ffee6e664 100644 --- a/src/tools/rustfmt/src/formatting/generated.rs +++ b/src/tools/rustfmt/src/formatting/generated.rs @@ -1,7 +1,10 @@ +use crate::Config; + /// Returns `true` if the given span is a part of generated files. -pub(super) fn is_generated_file(original_snippet: &str) -> bool { +pub(super) fn is_generated_file(original_snippet: &str, config: &Config) -> bool { original_snippet .lines() - .take(5) // looking for marker only in the beginning of the file + // looking for marker only in the beginning of the file + .take(config.generated_marker_line_search_limit()) .any(|line| line.contains("@generated")) } diff --git a/src/tools/rustfmt/src/ignore_path.rs b/src/tools/rustfmt/src/ignore_path.rs index 7b5697bec3e..5c25f233ce3 100644 --- a/src/tools/rustfmt/src/ignore_path.rs +++ b/src/tools/rustfmt/src/ignore_path.rs @@ -49,4 +49,22 @@ mod test { assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs")))); assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs")))); } + + #[nightly_only_test] + #[test] + fn test_negated_ignore_path_set() { + use crate::config::{Config, FileName}; + use crate::ignore_path::IgnorePathSet; + use std::path::{Path, PathBuf}; + + let config = Config::from_toml( + r#"ignore = ["foo.rs", "bar_dir/*", "!bar_dir/*/what.rs"]"#, + Path::new(""), + ) + .unwrap(); + let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap(); + assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/what.rs")))); + assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz/a.rs")))); + assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz/what.rs")))); + } } diff --git a/src/tools/rustfmt/src/imports.rs b/src/tools/rustfmt/src/imports.rs index 2da746295fc..12c178e136f 100644 --- a/src/tools/rustfmt/src/imports.rs +++ b/src/tools/rustfmt/src/imports.rs @@ -685,9 +685,9 @@ impl UseTree { let prefix = &self.path[..self.path.len() - 1]; let mut result = vec![]; for nested_use_tree in list { - for flattend in &mut nested_use_tree.clone().flatten(import_granularity) { + for flattened in &mut nested_use_tree.clone().flatten(import_granularity) { let mut new_path = prefix.to_vec(); - new_path.append(&mut flattend.path); + new_path.append(&mut flattened.path); result.push(UseTree { path: new_path, span: self.span, diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index e869787b394..c8ea104e9d6 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -656,9 +656,16 @@ impl<'a> FmtVisitor<'a> { } let context = self.get_context(); - // 1 = ',' - let shape = self.shape().sub_width(1)?; - let attrs_str = field.attrs.rewrite(&context, shape)?; + let shape = self.shape(); + let attrs_str = if context.config.version() == Version::Two { + field.attrs.rewrite(&context, shape)? + } else { + // Version::One formatting that was off by 1. See issue #5801 + field.attrs.rewrite(&context, shape.sub_width(1)?)? + }; + // sub_width(1) to take the trailing comma into account + let shape = shape.sub_width(1)?; + let lo = field .attrs .last() @@ -836,13 +843,15 @@ pub(crate) fn format_impl( if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? { result.push_str(&where_clause_str); - if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) { - // if the where_clause contains extra comments AND - // there is only one where-clause predicate - // recover the suppressed comma in single line where_clause formatting + if where_clause_str.contains('\n') { + // If there is only one where-clause predicate + // and the where-clause spans multiple lines, + // then recover the suppressed comma in single line where-clause formatting if generics.where_clause.predicates.len() == 1 { result.push(','); } + } + if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) { result.push_str(&format!("{sep}{{{sep}}}")); } else { result.push_str(" {}"); @@ -1161,9 +1170,9 @@ pub(crate) fn format_trait( // FIXME(#2055): rustfmt fails to format when there are comments between trait bounds. if !bounds.is_empty() { - let ident_hi = context - .snippet_provider - .span_after(item.span, item.ident.as_str()); + // Retrieve *unnormalized* ident (See #6069) + let source_ident = context.snippet(item.ident.span); + let ident_hi = context.snippet_provider.span_after(item.span, source_ident); let bound_hi = bounds.last().unwrap().span().hi(); let snippet = context.snippet(mk_sp(ident_hi, bound_hi)); if contains_comment(snippet) { @@ -1906,6 +1915,7 @@ pub(crate) fn rewrite_struct_field( pub(crate) struct StaticParts<'a> { prefix: &'a str, + safety: ast::Safety, vis: &'a ast::Visibility, ident: symbol::Ident, ty: &'a ast::Ty, @@ -1917,11 +1927,12 @@ pub(crate) struct StaticParts<'a> { impl<'a> StaticParts<'a> { pub(crate) fn from_item(item: &'a ast::Item) -> Self { - let (defaultness, prefix, ty, mutability, expr) = match &item.kind { - ast::ItemKind::Static(s) => (None, "static", &s.ty, s.mutability, &s.expr), + let (defaultness, prefix, safety, ty, mutability, expr) = match &item.kind { + ast::ItemKind::Static(s) => (None, "static", s.safety, &s.ty, s.mutability, &s.expr), ast::ItemKind::Const(c) => ( Some(c.defaultness), "const", + ast::Safety::Default, &c.ty, ast::Mutability::Not, &c.expr, @@ -1930,6 +1941,7 @@ impl<'a> StaticParts<'a> { }; StaticParts { prefix, + safety, vis: &item.vis, ident: item.ident, ty, @@ -1947,6 +1959,7 @@ impl<'a> StaticParts<'a> { }; StaticParts { prefix: "const", + safety: ast::Safety::Default, vis: &ti.vis, ident: ti.ident, ty, @@ -1964,6 +1977,7 @@ impl<'a> StaticParts<'a> { }; StaticParts { prefix: "const", + safety: ast::Safety::Default, vis: &ii.vis, ident: ii.ident, ty, @@ -1980,11 +1994,13 @@ fn rewrite_static( static_parts: &StaticParts<'_>, offset: Indent, ) -> Option<String> { + println!("rewriting static"); let colon = colon_spaces(context.config); let mut prefix = format!( - "{}{}{} {}{}{}", + "{}{}{}{} {}{}{}", format_visibility(context, static_parts.vis), static_parts.defaultness.map_or("", format_defaultness), + format_safety(static_parts.safety), static_parts.prefix, format_mutability(static_parts.mutability), rewrite_ident(context, static_parts.ident), @@ -2483,7 +2499,7 @@ fn rewrite_fn_base( || context.config.indent_style() == IndentStyle::Visual { let indent = if param_str.is_empty() { - // Aligning with non-existent params looks silly. + // Aligning with nonexistent params looks silly. force_new_line_for_brace = true; indent + 4 } else { @@ -2498,7 +2514,7 @@ fn rewrite_fn_base( } else { let mut ret_shape = Shape::indented(indent, context.config); if param_str.is_empty() { - // Aligning with non-existent params looks silly. + // Aligning with nonexistent params looks silly. force_new_line_for_brace = true; ret_shape = if context.use_block_indent() { ret_shape.offset_left(4).unwrap_or(ret_shape) @@ -3329,10 +3345,12 @@ impl Rewrite for ast::ForeignItem { // FIXME(#21): we're dropping potential comments in between the // function kw here. let vis = format_visibility(context, &self.vis); + let safety = format_safety(static_foreign_item.safety); let mut_str = format_mutability(static_foreign_item.mutability); let prefix = format!( - "{}static {}{}:", + "{}{}static {}{}:", vis, + safety, mut_str, rewrite_ident(context, self.ident) ); diff --git a/src/tools/rustfmt/src/lib.rs b/src/tools/rustfmt/src/lib.rs index 877d057a34b..ff2b14af078 100644 --- a/src/tools/rustfmt/src/lib.rs +++ b/src/tools/rustfmt/src/lib.rs @@ -5,9 +5,6 @@ #![allow(clippy::match_like_matches_macro)] #![allow(unreachable_pub)] -#[cfg(test)] -#[macro_use] -extern crate lazy_static; #[macro_use] extern crate tracing; @@ -62,6 +59,13 @@ pub use crate::rustfmt_diff::{ModifiedChunk, ModifiedLines}; #[macro_use] mod utils; +macro_rules! static_regex { + ($re:literal) => {{ + static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new(); + RE.get_or_init(|| ::regex::Regex::new($re).unwrap()) + }}; +} + mod attr; mod chains; mod closures; @@ -258,8 +262,8 @@ impl FormatReport { self.internal .borrow() .0 - .iter() - .map(|(_, errors)| errors.len()) + .values() + .map(|errors| errors.len()) .sum() } @@ -305,7 +309,7 @@ fn format_snippet(snippet: &str, config: &Config, is_macro_def: bool) -> Option< let mut out: Vec<u8> = Vec::with_capacity(snippet.len() * 2); config.set().emit_mode(config::EmitMode::Stdout); config.set().verbose(Verbosity::Quiet); - config.set().hide_parse_errors(true); + config.set().show_parse_errors(false); if is_macro_def { config.set().error_on_unformatted(true); } diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index 6b24b1aec5d..a0582b061c0 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -25,6 +25,7 @@ use crate::comment::{ contains_comment, CharClasses, FindUncommented, FullCodeCharKind, LineClasses, }; use crate::config::lists::*; +use crate::config::Version; use crate::expr::{rewrite_array, rewrite_assign_rhs, RhsAssignKind}; use crate::lists::{itemize_list, write_list, ListFormatting}; use crate::overflow; @@ -389,7 +390,7 @@ fn rewrite_empty_macro_def_body( stmts: vec![].into(), id: rustc_ast::node_id::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Default, - span: span, + span, tokens: None, could_be_bare_literal: false, }; @@ -1245,8 +1246,16 @@ impl MacroBranch { return None; } - // 5 = " => {" - let mut result = format_macro_args(context, self.args.clone(), shape.sub_width(5)?)?; + let old_body = context.snippet(self.body).trim(); + let has_block_body = old_body.starts_with('{'); + let mut prefix_width = 5; // 5 = " => {" + if context.config.version() == Version::Two { + if has_block_body { + prefix_width = 6; // 6 = " => {{" + } + } + let mut result = + format_macro_args(context, self.args.clone(), shape.sub_width(prefix_width)?)?; if multi_branch_style { result += " =>"; @@ -1264,12 +1273,10 @@ impl MacroBranch { // `$$`). We'll try and format like an AST node, but we'll substitute // variables for new names with the same length first. - let old_body = context.snippet(self.body).trim(); let (body_str, substs) = replace_names(old_body)?; - let has_block_body = old_body.starts_with('{'); let mut config = context.config.clone(); - config.set().hide_parse_errors(true); + config.set().show_parse_errors(false); result += " {"; diff --git a/src/tools/rustfmt/src/matches.rs b/src/tools/rustfmt/src/matches.rs index e68903c8715..e4fa077073c 100644 --- a/src/tools/rustfmt/src/matches.rs +++ b/src/tools/rustfmt/src/matches.rs @@ -5,7 +5,7 @@ use std::iter::repeat; use rustc_ast::{ast, ptr, MatchKind}; use rustc_span::{BytePos, Span}; -use crate::comment::{combine_strs_with_missing_comments, rewrite_comment}; +use crate::comment::{combine_strs_with_missing_comments, rewrite_comment, FindUncommented}; use crate::config::lists::*; use crate::config::{Config, ControlBraceStyle, IndentStyle, MatchArmLeadingPipe, Version}; use crate::expr::{ @@ -104,6 +104,10 @@ pub(crate) fn rewrite_match( let inner_attrs_str = if inner_attrs.is_empty() { String::new() } else { + let shape = match context.config.version() { + Version::One => shape, + _ => shape.block_indent(context.config.tab_spaces()), + }; inner_attrs .rewrite(context, shape) .map(|s| format!("{}{}\n", nested_indent_str, s))? @@ -352,10 +356,10 @@ fn flatten_arm_body<'a>( (true, body) } } else { - let cond_becomes_muti_line = opt_shape + let cond_becomes_multi_line = opt_shape .and_then(|shape| rewrite_cond(context, expr, shape)) .map_or(false, |cond| cond.contains('\n')); - if cond_becomes_muti_line { + if cond_becomes_multi_line { (false, &*body) } else { (can_extend(expr), &*expr) @@ -415,7 +419,11 @@ fn rewrite_match_body( let arrow_snippet = context.snippet(arrow_span).trim(); // search for the arrow starting from the end of the snippet since there may be a match // expression within the guard - let arrow_index = arrow_snippet.rfind("=>").unwrap(); + let arrow_index = if context.config.version() == Version::One { + arrow_snippet.rfind("=>").unwrap() + } else { + arrow_snippet.find_last_uncommented("=>").unwrap() + }; // 2 = `=>` let comment_str = arrow_snippet[arrow_index + 2..].trim(); if comment_str.is_empty() { @@ -464,8 +472,8 @@ fn rewrite_match_body( }; let block_sep = match context.config.control_brace_style() { - ControlBraceStyle::AlwaysNextLine => format!("{}{}", alt_block_sep, body_prefix), _ if body_prefix.is_empty() => "".to_owned(), + ControlBraceStyle::AlwaysNextLine => format!("{}{}", alt_block_sep, body_prefix), _ if forbid_same_line || !arrow_comment.is_empty() => { format!("{}{}", alt_block_sep, body_prefix) } diff --git a/src/tools/rustfmt/src/overflow.rs b/src/tools/rustfmt/src/overflow.rs index f46583b1c89..c44f3788d97 100644 --- a/src/tools/rustfmt/src/overflow.rs +++ b/src/tools/rustfmt/src/overflow.rs @@ -8,8 +8,8 @@ use rustc_ast::{ast, ptr}; use rustc_span::Span; use crate::closures; -use crate::config::lists::*; use crate::config::Version; +use crate::config::{lists::*, Config}; use crate::expr::{ can_be_overflowed_expr, is_every_expr_simple, is_method_call, is_nested_call, is_simple_expr, rewrite_cond, @@ -60,6 +60,13 @@ const SPECIAL_CASE_MACROS: &[(&str, usize)] = &[ ("debug_assert_ne!", 2), ]; +/// Additional special case macros for version 2; these are separated to avoid breaking changes in +/// version 1. +const SPECIAL_CASE_MACROS_V2: &[(&str, usize)] = &[ + // From the `log` crate. + ("trace!", 0), +]; + const SPECIAL_CASE_ATTR: &[(&str, usize)] = &[ // From the `failure` crate. ("fail", 0), @@ -182,12 +189,17 @@ impl<'a> OverflowableItem<'a> { } } - fn special_cases(&self) -> &'static [(&'static str, usize)] { - match self { + fn special_cases(&self, config: &Config) -> impl Iterator<Item = &(&'static str, usize)> { + let base_cases = match self { OverflowableItem::MacroArg(..) => SPECIAL_CASE_MACROS, OverflowableItem::NestedMetaItem(..) => SPECIAL_CASE_ATTR, _ => &[], - } + }; + let additional_cases = match (self, config.version()) { + (OverflowableItem::MacroArg(..), Version::Two) => SPECIAL_CASE_MACROS_V2, + _ => &[], + }; + base_cases.iter().chain(additional_cases) } } @@ -511,7 +523,7 @@ impl<'a> Context<'a> { // However, when the inner function has a prefix or a suffix // (e.g., `foo() as u32`), this budget reduction may produce poorly // formatted code, where a prefix or a suffix being left on its own - // line. Here we explicitlly check those cases. + // line. Here we explicitly check those cases. if count_newlines(overflowed) == 1 { let rw = self .items @@ -551,7 +563,7 @@ impl<'a> Context<'a> { if tactic == DefinitiveListTactic::Vertical { if let Some((all_simple, num_args_before)) = - maybe_get_args_offset(self.ident, &self.items) + maybe_get_args_offset(self.ident, &self.items, &self.context.config) { let one_line = all_simple && definitive_tactic( @@ -771,11 +783,11 @@ fn no_long_items(list: &[ListItem], short_array_element_width_threshold: usize) pub(crate) fn maybe_get_args_offset( callee_str: &str, args: &[OverflowableItem<'_>], + config: &Config, ) -> Option<(bool, usize)> { if let Some(&(_, num_args_before)) = args .get(0)? - .special_cases() - .iter() + .special_cases(config) .find(|&&(s, _)| s == callee_str) { let all_simple = args.len() > num_args_before diff --git a/src/tools/rustfmt/src/parse/macros/lazy_static.rs b/src/tools/rustfmt/src/parse/macros/lazy_static.rs index 7026935294a..7baac247e22 100644 --- a/src/tools/rustfmt/src/parse/macros/lazy_static.rs +++ b/src/tools/rustfmt/src/parse/macros/lazy_static.rs @@ -31,7 +31,6 @@ pub(crate) fn parse_lazy_static( } } } - while parser.token.kind != TokenKind::Eof { // Parse a `lazy_static!` item. let vis = parse_or!(parse_visibility, rustc_parse::parser::FollowedByType::No); diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index f4fbabaf6c9..05cf467167c 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -97,7 +97,7 @@ fn default_dcx( source_map: Lrc<SourceMap>, ignore_path_set: Lrc<IgnorePathSet>, can_reset: Lrc<AtomicBool>, - hide_parse_errors: bool, + show_parse_errors: bool, color: Color, ) -> DiagCtxt { let supports_color = term::stderr().map_or(false, |term| term.supports_color()); @@ -116,7 +116,7 @@ fn default_dcx( .sm(Some(source_map.clone())), ); - let emitter: Box<DynEmitter> = if hide_parse_errors { + let emitter: Box<DynEmitter> = if !show_parse_errors { Box::new(SilentEmitter { fallback_bundle, fatal_dcx: DiagCtxt::new(emitter), @@ -148,7 +148,7 @@ impl ParseSess { Lrc::clone(&source_map), Lrc::clone(&ignore_path_set), Lrc::clone(&can_reset_errors), - config.hide_parse_errors(), + config.show_parse_errors(), config.color(), ); let raw_psess = RawParseSess::with_dcx(dcx, source_map); @@ -164,7 +164,7 @@ impl ParseSess { /// /// * `id` - The name of the module /// * `relative` - If Some(symbol), the symbol name is a directory relative to the dir_path. - /// If relative is Some, resolve the submodle at {dir_path}/{symbol}/{id}.rs + /// If relative is Some, resolve the submodule at {dir_path}/{symbol}/{id}.rs /// or {dir_path}/{symbol}/{id}/mod.rs. if None, resolve the module at {dir_path}/{id}.rs. /// * `dir_path` - Module resolution will occur relative to this directory. pub(crate) fn default_submod_path( @@ -175,7 +175,7 @@ impl ParseSess { ) -> Result<ModulePathSuccess, ModError<'_>> { rustc_expand::module::default_submod_path(&self.raw_psess, id, relative, dir_path).or_else( |e| { - // If resloving a module relative to {dir_path}/{symbol} fails because a file + // If resolving a module relative to {dir_path}/{symbol} fails because a file // could not be found, then try to resolve the module relative to {dir_path}. // If we still can't find the module after searching for it in {dir_path}, // surface the original error. diff --git a/src/tools/rustfmt/src/source_file.rs b/src/tools/rustfmt/src/source_file.rs index 2b43ec94b6b..5eea8021b32 100644 --- a/src/tools/rustfmt/src/source_file.rs +++ b/src/tools/rustfmt/src/source_file.rs @@ -33,7 +33,7 @@ where let mut emitter = create_emitter(config); emitter.emit_header(out)?; - for &(ref filename, ref text) in source_file { + for (filename, text) in source_file { write_file( None, filename, diff --git a/src/tools/rustfmt/src/test/configuration_snippet.rs b/src/tools/rustfmt/src/test/configuration_snippet.rs index 80b61c88a00..e4a390ada66 100644 --- a/src/tools/rustfmt/src/test/configuration_snippet.rs +++ b/src/tools/rustfmt/src/test/configuration_snippet.rs @@ -24,19 +24,13 @@ impl ConfigurationSection { fn get_section<I: Iterator<Item = String>>( file: &mut Enumerate<I>, ) -> Option<ConfigurationSection> { - lazy_static! { - static ref CONFIG_NAME_REGEX: regex::Regex = - regex::Regex::new(r"^## `([^`]+)`").expect("failed creating configuration pattern"); - // Configuration values, which will be passed to `from_str`: - // - // - must be prefixed with `####` - // - must be wrapped in backticks - // - may by wrapped in double quotes (which will be stripped) - static ref CONFIG_VALUE_REGEX: regex::Regex = - regex::Regex::new(r#"^#### `"?([^`]+?)"?`"#) - .expect("failed creating configuration value pattern"); - } - + let config_name_regex = static_regex!(r"^## `([^`]+)`"); + // Configuration values, which will be passed to `from_str`: + // + // - must be prefixed with `####` + // - must be wrapped in backticks + // - may by wrapped in double quotes (which will be stripped) + let config_value_regex = static_regex!(r#"^#### `"?([^`]+?)"?`"#); loop { match file.next() { Some((i, line)) => { @@ -53,9 +47,9 @@ impl ConfigurationSection { let start_line = (i + 2) as u32; return Some(ConfigurationSection::CodeBlock((block, start_line))); - } else if let Some(c) = CONFIG_NAME_REGEX.captures(&line) { + } else if let Some(c) = config_name_regex.captures(&line) { return Some(ConfigurationSection::ConfigName(String::from(&c[1]))); - } else if let Some(c) = CONFIG_VALUE_REGEX.captures(&line) { + } else if let Some(c) = config_value_regex.captures(&line) { return Some(ConfigurationSection::ConfigValue(String::from(&c[1]))); } } @@ -208,7 +202,7 @@ impl ConfigCodeBlock { } // Extract a code block from the iterator. Behavior: - // - Rust code blocks are identifed by lines beginning with "```rust". + // - Rust code blocks are identified by lines beginning with "```rust". // - One explicit configuration setting is supported per code block. // - Rust code blocks with no configuration setting are illegal and cause an // assertion failure, unless the snippet begins with #![rustfmt::skip]. diff --git a/src/tools/rustfmt/src/test/mod.rs b/src/tools/rustfmt/src/test/mod.rs index 47f89c1871a..7c563801c32 100644 --- a/src/tools/rustfmt/src/test/mod.rs +++ b/src/tools/rustfmt/src/test/mod.rs @@ -332,7 +332,7 @@ fn assert_stdin_output( let mut session = Session::new(config, Some(&mut buf)); session.format(input).unwrap(); let errors = ReportedErrors { - has_diff: has_diff, + has_diff, ..Default::default() }; assert_eq!(session.errors, errors); @@ -390,6 +390,26 @@ fn self_tests() { path.push("main.rs"); files.push(path); } + // for crates that need to be included but lies outside src + let external_crates = vec!["check_diff", "config_proc_macro"]; + for external_crate in external_crates { + let mut path = PathBuf::from(external_crate); + path.push("src"); + let directory = fs::read_dir(&path).unwrap(); + let search_files = directory.filter_map(|file| { + file.ok().and_then(|f| { + let name = f.file_name(); + if matches!(name.as_os_str().to_str(), Some("main.rs" | "lib.rs")) { + Some(f.path()) + } else { + None + } + }) + }); + for file in search_files { + files.push(file); + } + } files.push(PathBuf::from("src/lib.rs")); let (reports, count, fails) = check_files(files, &Some(PathBuf::from("rustfmt.toml"))); @@ -835,7 +855,7 @@ fn handle_result( // Ignore LF and CRLF difference for Windows. if !string_eq_ignore_newline_repr(&fmt_text, &text) { if std::env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0") { - std::fs::write(file_name, fmt_text).unwrap(); + std::fs::write(target, fmt_text).unwrap(); continue; } let diff = make_diff(&text, &fmt_text, DIFF_CONTEXT_SIZE); diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index c2c192738c9..c12f271bc5d 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -43,11 +43,13 @@ pub(crate) fn rewrite_path( ) -> Option<String> { let skip_count = qself.as_ref().map_or(0, |x| x.position); - let mut result = if path.is_global() && qself.is_none() && path_context != PathContext::Import { - "::".to_owned() - } else { - String::new() - }; + // 32 covers almost all path lengths measured when compiling core, and there isn't a big + // downside from allocating slightly more than necessary. + let mut result = String::with_capacity(32); + + if path.is_global() && qself.is_none() && path_context != PathContext::Import { + result.push_str("::"); + } let mut span_lo = path.span.lo(); @@ -693,10 +695,12 @@ impl Rewrite for ast::Ty { }; let mut res = bounds.rewrite(context, shape)?; // We may have falsely removed a trailing `+` inside macro call. - if context.inside_macro() && bounds.len() == 1 { - if context.snippet(self.span).ends_with('+') && !res.ends_with('+') { - res.push('+'); - } + if context.inside_macro() + && bounds.len() == 1 + && context.snippet(self.span).ends_with('+') + && !res.ends_with('+') + { + res.push('+'); } Some(format!("{prefix}{res}")) } diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 7a0c68c214c..1de9f5a9524 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -81,7 +81,7 @@ pub(crate) struct FmtVisitor<'a> { pub(crate) snippet_provider: &'a SnippetProvider, pub(crate) line_number: usize, /// List of 1-based line ranges which were annotated with skip - /// Both bounds are inclusifs. + /// Both bounds are inclusive. pub(crate) skipped_range: Rc<RefCell<Vec<(usize, usize)>>>, pub(crate) macro_rewrite_failure: bool, pub(crate) report: FormatReport, diff --git a/src/tools/rustfmt/tests/config/issue-5801-v1.toml b/src/tools/rustfmt/tests/config/issue-5801-v1.toml new file mode 100644 index 00000000000..8695df0099e --- /dev/null +++ b/src/tools/rustfmt/tests/config/issue-5801-v1.toml @@ -0,0 +1,3 @@ +max_width = 120 +version = "One" +attr_fn_like_width = 120 \ No newline at end of file diff --git a/src/tools/rustfmt/tests/config/issue-5801-v2.toml b/src/tools/rustfmt/tests/config/issue-5801-v2.toml new file mode 100644 index 00000000000..948f4fb66bf --- /dev/null +++ b/src/tools/rustfmt/tests/config/issue-5801-v2.toml @@ -0,0 +1,3 @@ +max_width = 120 +version = "Two" +attr_fn_like_width = 120 \ No newline at end of file diff --git a/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/main.rs b/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/main.rs index 3122e4f220f..f102bf9d181 100644 --- a/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/main.rs +++ b/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/main.rs @@ -6,4 +6,4 @@ mod one; fn main() {println!("Hello, world!"); } -// trailing commet +// trailing comment diff --git a/src/tools/rustfmt/tests/rustfmt/main.rs b/src/tools/rustfmt/tests/rustfmt/main.rs index e66fad1e7fa..58cf0e5e4db 100644 --- a/src/tools/rustfmt/tests/rustfmt/main.rs +++ b/src/tools/rustfmt/tests/rustfmt/main.rs @@ -176,7 +176,14 @@ fn rustfmt_emits_error_on_line_overflow_true() { #[test] #[allow(non_snake_case)] fn dont_emit_ICE() { - let files = ["tests/target/issue_5728.rs", "tests/target/issue_5729.rs", "tests/target/issue_6082.rs"]; + let files = [ + "tests/target/issue_5728.rs", + "tests/target/issue_5729.rs", + "tests/target/issue-5885.rs", + "tests/target/issue_6082.rs", + "tests/target/issue_6069.rs", + "tests/target/issue-6105.rs", + ]; for file in files { let args = [file]; @@ -184,3 +191,19 @@ fn dont_emit_ICE() { assert!(!stderr.contains("thread 'main' panicked")); } } + +#[test] +fn rustfmt_emits_error_when_control_brace_style_is_always_next_line() { + // See also https://github.com/rust-lang/rustfmt/issues/5912 + let args = [ + "--config=color=Never", + "--config", + "control_brace_style=AlwaysNextLine", + "--config", + "match_arm_blocks=false", + "tests/target/issue_5912.rs", + ]; + + let (_stdout, stderr) = rustfmt(&args); + assert!(!stderr.contains("error[internal]: left behind trailing whitespace")) +} diff --git a/src/tools/rustfmt/tests/source/arrow_in_comments/arrow_in_single_comment.rs b/src/tools/rustfmt/tests/source/arrow_in_comments/arrow_in_single_comment.rs new file mode 100644 index 00000000000..fb0576a4822 --- /dev/null +++ b/src/tools/rustfmt/tests/source/arrow_in_comments/arrow_in_single_comment.rs @@ -0,0 +1,10 @@ +// rustfmt-version: Two +fn main() { + match a { + _ => + // comment with => + { + println!("A") + } + } +} diff --git a/src/tools/rustfmt/tests/source/arrow_in_comments/multiple_arrows.rs b/src/tools/rustfmt/tests/source/arrow_in_comments/multiple_arrows.rs new file mode 100644 index 00000000000..fc696b309f2 --- /dev/null +++ b/src/tools/rustfmt/tests/source/arrow_in_comments/multiple_arrows.rs @@ -0,0 +1,14 @@ +// rustfmt-version: Two +fn main() { + match a { + _ => // comment with => + match b { + // one goes to => + one => { + println("1"); + } + // two goes to => + two => { println("2"); } + } + } +} diff --git a/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs b/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs new file mode 100644 index 00000000000..be03849fe10 --- /dev/null +++ b/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs @@ -0,0 +1,10 @@ +// rustfmt-format_generated_files: false +// rustfmt-generated_marker_line_search_limit: 15 + +fn main() +{ + println!("hello, world") + ; +} + +// @generated \ No newline at end of file diff --git a/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_marker_out_scope_size.rs b/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_marker_out_scope_size.rs new file mode 100644 index 00000000000..abb97e6259f --- /dev/null +++ b/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_marker_out_scope_size.rs @@ -0,0 +1,10 @@ +// rustfmt-format_generated_files: false +// rustfmt-generated_marker_line_search_limit: 1 + +fn main() +{ + println!("hello, world") + ; +} + +// @generated \ No newline at end of file diff --git a/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_zero_search_limit.rs b/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_zero_search_limit.rs new file mode 100644 index 00000000000..f6978d0f355 --- /dev/null +++ b/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_zero_search_limit.rs @@ -0,0 +1,9 @@ +// rustfmt-format_generated_files: false +// rustfmt-generated_marker_line_search_limit: 0 + +// @generated +fn main() { + println!("hello, world") + ; +} +// @generated diff --git a/src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_in_scope_size.rs b/src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_in_scope_size.rs new file mode 100644 index 00000000000..53cc116ec2b --- /dev/null +++ b/src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_in_scope_size.rs @@ -0,0 +1,10 @@ +// rustfmt-format_generated_files: true +// rustfmt-generated_marker_line_search_limit: 20 + +fn main() +{ + println!("hello, world") + ; +} + +// @generated diff --git a/src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_not_in_header.rs b/src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_not_in_header.rs new file mode 100644 index 00000000000..8eff1a3b0ee --- /dev/null +++ b/src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_not_in_header.rs @@ -0,0 +1,9 @@ +// rustfmt-format_generated_files: true + +fn main() +{ + println!("hello, world") + ; +} + +// @generated \ No newline at end of file diff --git a/src/tools/rustfmt/tests/source/issue-3805.rs b/src/tools/rustfmt/tests/source/issue-3805.rs new file mode 100644 index 00000000000..a0289b57974 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-3805.rs @@ -0,0 +1,65 @@ +// rustfmt-version: Two +// rustfmt-format_macro_matchers: true + +// From original issue example - Line length 101 +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {{ +return; +}}; +} + +// Spaces between the `{` and `}` +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => { { +return; +} }; +} + +// Multi `{}` +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {{{{ +return; +}}}}; +} + +// Multi `{}` with spaces +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => { { { { +return; +} } } }; +} + +// Line length 102 +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeiou:expr, $add:expr) => {{ +return; +}}; +} + +// Line length 103 +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeioua:expr, $add:expr) => {{ +return; +}}; +} + +// With extended macro body - Line length 101 +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {{ +let VAR = "VALUE"; return VAR; +}}; +} + +// With extended macro body - Line length 102 +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeiou:expr, $add:expr) => {{ +let VAR = "VALUE"; return VAR; +}}; +} + +// With extended macro body - Line length 103 +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeioua:expr, $add:expr) => {{ +let VAR = "VALUE"; return VAR; +}}; +} diff --git a/src/tools/rustfmt/tests/source/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs b/src/tools/rustfmt/tests/source/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs new file mode 100644 index 00000000000..59902c7bcce --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs @@ -0,0 +1,8 @@ +// rustfmt-config: issue-5801-v1.toml + +pub enum Severity { + #[something(AAAAAAAAAAAAA, BBBBBBBBBBBBBB, CCCCCCCCCCCCCCCC, DDDDDDDDDDDDD, EEEEEEEEEEEE, FFFFFFFFFFF, GGGGGGGGGGG)] + AttrsWillWrap, + #[something_else(hhhhhhhhhhhhhhhh, iiiiiiiiiiiiiiii, jjjjjjjjjjjjjjj, kkkkkkkkkkkkk, llllllllllll, mmmmmmmmmmmmmm)] + AttrsWontWrap, +} diff --git a/src/tools/rustfmt/tests/source/issue-5801/comment_unexpectedly_wraps_before_max_width.rs b/src/tools/rustfmt/tests/source/issue-5801/comment_unexpectedly_wraps_before_max_width.rs new file mode 100644 index 00000000000..5847afd9560 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-5801/comment_unexpectedly_wraps_before_max_width.rs @@ -0,0 +1,17 @@ +// rustfmt-comment_width: 120 +// rustfmt-wrap_comments: true +// rustfmt-max_width: 120 +// rustfmt-version: One + +/// This function is 120 columns wide and is left alone. This comment is 120 columns wide and the formatter is also fine +fn my_super_cool_function_name(my_very_cool_argument_name: String, my_other_very_cool_argument_name: String) -> String { + unimplemented!() +} + +pub enum Severity { + /// In version one, the below line got wrapped prematurely as we subtracted 1 to account for `,`. See issue #5801. + /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines still. + Error, + /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem. + Warning, +} diff --git a/src/tools/rustfmt/tests/source/issue-5987/two.rs b/src/tools/rustfmt/tests/source/issue-5987/two.rs new file mode 100644 index 00000000000..e20026b5565 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-5987/two.rs @@ -0,0 +1,13 @@ +// rustfmt-version: Two + +fn main() { + trace!( + "get some longer length in here yes yes {} {}", + "hello", + "world" + ); + debug!( + "get some longer length in here yes yes {} {}", + "hello", "world" + ); +} diff --git a/src/tools/rustfmt/tests/source/issue-6059/repro.rs b/src/tools/rustfmt/tests/source/issue-6059/repro.rs new file mode 100644 index 00000000000..1dc62cc8d26 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-6059/repro.rs @@ -0,0 +1,3 @@ +fn float_range_tests() { + self.coords.x -= rng.gen_range(-self.radius / 2. .. self.radius / 2.); +} diff --git a/src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v1.rs b/src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v1.rs new file mode 100644 index 00000000000..2ac2e0361c3 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v1.rs @@ -0,0 +1,20 @@ +// rustfmt-version: One + +pub fn main() { +let a = Some(12); +match a { +#![attr1] +#![attr2] +#![attr3] +_ => None, +} + +{ +match a { +#![attr1] +#![attr2] +#![attr3] +_ => None, +} +} +} diff --git a/src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v2.rs b/src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v2.rs new file mode 100644 index 00000000000..c1bf1ad4bf8 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v2.rs @@ -0,0 +1,20 @@ +// rustfmt-version: Two + +pub fn main() { +let a = Some(12); +match a { +#![attr1] +#![attr2] +#![attr3] +_ => None, +} + +{ +match a { +#![attr1] +#![attr2] +#![attr3] +_ => None, +} +} +} diff --git a/src/tools/rustfmt/tests/source/issue_5912.rs b/src/tools/rustfmt/tests/source/issue_5912.rs new file mode 100644 index 00000000000..2265fd2146c --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_5912.rs @@ -0,0 +1,15 @@ +// rustfmt-match_arm_blocks: false +// rustfmt-control_brace_style: AlwaysNextLine + +fn foo() { + match 0 { + 0 => { + aaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbb + + bbbbbbbbbbbbbbbbbbbbbbbbb + + bbbbbbbbbbbbbbbbbbbbbbbbb + + bbbbbbbbbbbbbbbbbbbbbbbbb + } + _ => 2, + } +} diff --git a/src/tools/rustfmt/tests/source/let_else.rs b/src/tools/rustfmt/tests/source/let_else.rs index cb2859e805d..c589ab75cd3 100644 --- a/src/tools/rustfmt/tests/source/let_else.rs +++ b/src/tools/rustfmt/tests/source/let_else.rs @@ -117,8 +117,8 @@ fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_n // Break after the `=` and put the initializer expr on it's own line. // Because the initializer expr is multi-lined the else is placed on it's own line. // The initializer expr has a length of 91, which when indented on the next line - // The `(indent)init` line has a lengh of 99. This is the max length that the `init` can be - // before we start running into max_width issues. I suspect this is becuase the shape is + // The `(indent)init` line has a length of 99. This is the max length that the `init` can be + // before we start running into max_width issues. I suspect this is because the shape is // accounting for the `;` at the end of the `let-else` statement. let Some(x) = some_really_really_really_really_really_really_really_really_really_really_long_name______I else {return}; @@ -127,7 +127,7 @@ fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_n // Post Formatting: // Max length issues prevent us from formatting. // The initializer expr has a length of 92, which if it would be indented on the next line - // the `(indent)init` line has a lengh of 100 which == max_width of 100. + // the `(indent)init` line has a length of 100 which == max_width of 100. // One might expect formatting to succeed, but I suspect the reason we hit max_width issues is // because the Shape is accounting for the `;` at the end of the `let-else` statement. let Some(x) = some_really_really_really_really_really_really_really_really_really_really_really_long_nameJ else {return}; diff --git a/src/tools/rustfmt/tests/source/no_arg_with_commnet.rs b/src/tools/rustfmt/tests/source/no_arg_with_commnet.rs index ea4ee0f1eee..41c3c6bea48 100644 --- a/src/tools/rustfmt/tests/source/no_arg_with_commnet.rs +++ b/src/tools/rustfmt/tests/source/no_arg_with_commnet.rs @@ -1,2 +1,2 @@ -fn foo( /* cooment */ +fn foo( /* comment */ ) {} diff --git a/src/tools/rustfmt/tests/target/arrow_in_comments/arrow_in_single_comment.rs b/src/tools/rustfmt/tests/target/arrow_in_comments/arrow_in_single_comment.rs new file mode 100644 index 00000000000..deffdbeeaaf --- /dev/null +++ b/src/tools/rustfmt/tests/target/arrow_in_comments/arrow_in_single_comment.rs @@ -0,0 +1,10 @@ +// rustfmt-version: Two +fn main() { + match a { + _ => + // comment with => + { + println!("A") + } + } +} diff --git a/src/tools/rustfmt/tests/target/arrow_in_comments/multiple_arrows.rs b/src/tools/rustfmt/tests/target/arrow_in_comments/multiple_arrows.rs new file mode 100644 index 00000000000..b0443411816 --- /dev/null +++ b/src/tools/rustfmt/tests/target/arrow_in_comments/multiple_arrows.rs @@ -0,0 +1,19 @@ +// rustfmt-version: Two +fn main() { + match a { + _ => + // comment with => + { + match b { + // one goes to => + one => { + println("1"); + } + // two goes to => + two => { + println("2"); + } + } + } + } +} diff --git a/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs b/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs new file mode 100644 index 00000000000..be03849fe10 --- /dev/null +++ b/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs @@ -0,0 +1,10 @@ +// rustfmt-format_generated_files: false +// rustfmt-generated_marker_line_search_limit: 15 + +fn main() +{ + println!("hello, world") + ; +} + +// @generated \ No newline at end of file diff --git a/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_marker_out_scope_size.rs b/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_marker_out_scope_size.rs new file mode 100644 index 00000000000..93405896a1d --- /dev/null +++ b/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_marker_out_scope_size.rs @@ -0,0 +1,8 @@ +// rustfmt-format_generated_files: false +// rustfmt-generated_marker_line_search_limit: 1 + +fn main() { + println!("hello, world"); +} + +// @generated diff --git a/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_zero_search_limit.rs b/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_zero_search_limit.rs new file mode 100644 index 00000000000..6acd46ed2eb --- /dev/null +++ b/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_zero_search_limit.rs @@ -0,0 +1,8 @@ +// rustfmt-format_generated_files: false +// rustfmt-generated_marker_line_search_limit: 0 + +// @generated +fn main() { + println!("hello, world"); +} +// @generated diff --git a/src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_in_scope_size.rs b/src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_in_scope_size.rs new file mode 100644 index 00000000000..03bfdfd1c59 --- /dev/null +++ b/src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_in_scope_size.rs @@ -0,0 +1,8 @@ +// rustfmt-format_generated_files: true +// rustfmt-generated_marker_line_search_limit: 20 + +fn main() { + println!("hello, world"); +} + +// @generated diff --git a/src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_not_in_header.rs b/src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_not_in_header.rs new file mode 100644 index 00000000000..3b6280b350e --- /dev/null +++ b/src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_not_in_header.rs @@ -0,0 +1,7 @@ +// rustfmt-format_generated_files: true + +fn main() { + println!("hello, world"); +} + +// @generated diff --git a/src/tools/rustfmt/tests/target/impl.rs b/src/tools/rustfmt/tests/target/impl.rs index f37fbcf1fcb..10de0ecde56 100644 --- a/src/tools/rustfmt/tests/target/impl.rs +++ b/src/tools/rustfmt/tests/target/impl.rs @@ -32,6 +32,11 @@ where { } +// #5941 +impl T where (): Clone // Should not add comma to comment +{ +} + // #1823 default impl Trait for X {} default unsafe impl Trait for Y {} diff --git a/src/tools/rustfmt/tests/target/issue-3805.rs b/src/tools/rustfmt/tests/target/issue-3805.rs new file mode 100644 index 00000000000..a247a43fe6d --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-3805.rs @@ -0,0 +1,94 @@ +// rustfmt-version: Two +// rustfmt-format_macro_matchers: true + +// From original issue example - Line length 101 +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr + ) => {{ + return; + }}; +} + +// Spaces between the `{` and `}` +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr + ) => {{ + return; + }}; +} + +// Multi `{}` +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr + ) => {{ + { + { + return; + } + } + }}; +} + +// Multi `{}` with spaces +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr + ) => {{ + { + { + return; + } + } + }}; +} + +// Line length 102 +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeiou:expr, $add:expr + ) => {{ + return; + }}; +} + +// Line length 103 +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeioua:expr, $add:expr + ) => {{ + return; + }}; +} + +// With extended macro body - Line length 101 +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr + ) => {{ + let VAR = "VALUE"; + return VAR; + }}; +} + +// With extended macro body - Line length 102 +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeiou:expr, $add:expr + ) => {{ + let VAR = "VALUE"; + return VAR; + }}; +} + +// With extended macro body - Line length 103 +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeioua:expr, $add:expr + ) => {{ + let VAR = "VALUE"; + return VAR; + }}; +} diff --git a/src/tools/rustfmt/tests/target/issue-5801/attribute_does_not_wrap_within_max_width.rs b/src/tools/rustfmt/tests/target/issue-5801/attribute_does_not_wrap_within_max_width.rs new file mode 100644 index 00000000000..e3b6f3b37f5 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5801/attribute_does_not_wrap_within_max_width.rs @@ -0,0 +1,8 @@ +// rustfmt-config: issue-5801-v2.toml + +pub enum Severity { + #[something(AAAAAAAAAAAAA, BBBBBBBBBBBBBB, CCCCCCCCCCCCCCCC, DDDDDDDDDDDDD, EEEEEEEEEEEE, FFFFFFFFFFF, GGGGGGGGGGG)] + AttrsWillWrap, + #[something_else(hhhhhhhhhhhhhhhh, iiiiiiiiiiiiiiii, jjjjjjjjjjjjjjj, kkkkkkkkkkkkk, llllllllllll, mmmmmmmmmmmmmm)] + AttrsWontWrap, +} diff --git a/src/tools/rustfmt/tests/target/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs b/src/tools/rustfmt/tests/target/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs new file mode 100644 index 00000000000..89676666225 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs @@ -0,0 +1,16 @@ +// rustfmt-config: issue-5801-v1.toml + +pub enum Severity { + #[something( + AAAAAAAAAAAAA, + BBBBBBBBBBBBBB, + CCCCCCCCCCCCCCCC, + DDDDDDDDDDDDD, + EEEEEEEEEEEE, + FFFFFFFFFFF, + GGGGGGGGGGG + )] + AttrsWillWrap, + #[something_else(hhhhhhhhhhhhhhhh, iiiiiiiiiiiiiiii, jjjjjjjjjjjjjjj, kkkkkkkkkkkkk, llllllllllll, mmmmmmmmmmmmmm)] + AttrsWontWrap, +} diff --git a/src/tools/rustfmt/tests/target/issue-5801/comment_does_not_wrap_within_max_width.rs b/src/tools/rustfmt/tests/target/issue-5801/comment_does_not_wrap_within_max_width.rs new file mode 100644 index 00000000000..9f294751108 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5801/comment_does_not_wrap_within_max_width.rs @@ -0,0 +1,16 @@ +// rustfmt-comment_width: 120 +// rustfmt-wrap_comments: true +// rustfmt-max_width: 120 +// rustfmt-version: Two + +/// This function is 120 columns wide and is left alone. This comment is 120 columns wide and the formatter is also fine +fn my_super_cool_function_name(my_very_cool_argument_name: String, my_other_very_cool_argument_name: String) -> String { + unimplemented!() +} + +pub enum Severity { + /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines still. + Error, + /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem. + Warning, +} diff --git a/src/tools/rustfmt/tests/target/issue-5801/comment_unexpectedly_wraps_before_max_width.rs b/src/tools/rustfmt/tests/target/issue-5801/comment_unexpectedly_wraps_before_max_width.rs new file mode 100644 index 00000000000..dd839dd4548 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5801/comment_unexpectedly_wraps_before_max_width.rs @@ -0,0 +1,18 @@ +// rustfmt-comment_width: 120 +// rustfmt-wrap_comments: true +// rustfmt-max_width: 120 +// rustfmt-version: One + +/// This function is 120 columns wide and is left alone. This comment is 120 columns wide and the formatter is also fine +fn my_super_cool_function_name(my_very_cool_argument_name: String, my_other_very_cool_argument_name: String) -> String { + unimplemented!() +} + +pub enum Severity { + /// In version one, the below line got wrapped prematurely as we subtracted 1 to account for `,`. See issue #5801. + /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines + /// still. + Error, + /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem. + Warning, +} diff --git a/src/tools/rustfmt/tests/target/issue-5885.rs b/src/tools/rustfmt/tests/target/issue-5885.rs new file mode 100644 index 00000000000..85a659cbb47 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5885.rs @@ -0,0 +1,3 @@ +fn main() { + println!("{}", builtin # offset_of(A, 0. 1.1.1)); +} diff --git a/src/tools/rustfmt/tests/target/issue-5987/one.rs b/src/tools/rustfmt/tests/target/issue-5987/one.rs new file mode 100644 index 00000000000..3c995ed28ba --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5987/one.rs @@ -0,0 +1,13 @@ +// rustfmt-version: One + +fn main() { + trace!( + "get some longer length in here yes yes {} {}", + "hello", + "world" + ); + debug!( + "get some longer length in here yes yes {} {}", + "hello", "world" + ); +} diff --git a/src/tools/rustfmt/tests/target/issue-5987/two.rs b/src/tools/rustfmt/tests/target/issue-5987/two.rs new file mode 100644 index 00000000000..8fd92fc179e --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5987/two.rs @@ -0,0 +1,12 @@ +// rustfmt-version: Two + +fn main() { + trace!( + "get some longer length in here yes yes {} {}", + "hello", "world" + ); + debug!( + "get some longer length in here yes yes {} {}", + "hello", "world" + ); +} diff --git a/src/tools/rustfmt/tests/target/issue-6059/additional.rs b/src/tools/rustfmt/tests/target/issue-6059/additional.rs new file mode 100644 index 00000000000..fe708dcbdd3 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-6059/additional.rs @@ -0,0 +1,6 @@ +fn float_range_tests() { + let _range = 3. / 2. ..4.; + let _range = 3.0 / 2. ..4.0; + let _range = 3.0 / 2.0..4.0; + let _range = 3. / 2.0..4.0; +} diff --git a/src/tools/rustfmt/tests/target/issue-6059/repro.rs b/src/tools/rustfmt/tests/target/issue-6059/repro.rs new file mode 100644 index 00000000000..e8744c9ffcf --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-6059/repro.rs @@ -0,0 +1,3 @@ +fn float_range_tests() { + self.coords.x -= rng.gen_range(-self.radius / 2. ..self.radius / 2.); +} diff --git a/src/tools/rustfmt/tests/target/issue-6105.rs b/src/tools/rustfmt/tests/target/issue-6105.rs new file mode 100644 index 00000000000..1eb0ce89f78 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-6105.rs @@ -0,0 +1 @@ +const _: () = builtin # offset_of(x, x); diff --git a/src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v1.rs b/src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v1.rs new file mode 100644 index 00000000000..75800012c63 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v1.rs @@ -0,0 +1,20 @@ +// rustfmt-version: One + +pub fn main() { + let a = Some(12); + match a { + #![attr1] + #![attr2] + #![attr3] + _ => None, + } + + { + match a { + #![attr1] + #![attr2] + #![attr3] + _ => None, + } + } +} diff --git a/src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v2.rs b/src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v2.rs new file mode 100644 index 00000000000..5e4220e7306 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v2.rs @@ -0,0 +1,20 @@ +// rustfmt-version: Two + +pub fn main() { + let a = Some(12); + match a { + #![attr1] + #![attr2] + #![attr3] + _ => None, + } + + { + match a { + #![attr1] + #![attr2] + #![attr3] + _ => None, + } + } +} diff --git a/src/tools/rustfmt/tests/target/issue_5912.rs b/src/tools/rustfmt/tests/target/issue_5912.rs new file mode 100644 index 00000000000..835f2aba971 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_5912.rs @@ -0,0 +1,15 @@ +// rustfmt-match_arm_blocks: false +// rustfmt-control_brace_style: AlwaysNextLine + +fn foo() { + match 0 + { + 0 => + aaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbb + + bbbbbbbbbbbbbbbbbbbbbbbbb + + bbbbbbbbbbbbbbbbbbbbbbbbb + + bbbbbbbbbbbbbbbbbbbbbbbbb, + _ => 2, + } +} diff --git a/src/tools/rustfmt/tests/target/issue_6069.rs b/src/tools/rustfmt/tests/target/issue_6069.rs new file mode 100644 index 00000000000..d866ce7c646 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_6069.rs @@ -0,0 +1,3 @@ +// `Foó` as written here ends with ASCII 6F `'o'` followed by `'\u{0301}'` COMBINING ACUTE ACCENT. +// The compiler normalizes that combination to NFC form, `'\u{00F3}'` LATIN SMALL LETTER O WITH ACUTE. +trait Foó: Bar {} diff --git a/src/tools/rustfmt/tests/target/issue_6158.rs b/src/tools/rustfmt/tests/target/issue_6158.rs new file mode 100644 index 00000000000..82bb7d9fa05 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_6158.rs @@ -0,0 +1,7 @@ +fn main() { + const { + #![allow(clippy::assertions_on_constants)] + + assert!(1 < 2); + } +} diff --git a/src/tools/rustfmt/tests/target/issue_6159.rs b/src/tools/rustfmt/tests/target/issue_6159.rs new file mode 100644 index 00000000000..49fd539d3ef --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_6159.rs @@ -0,0 +1,3 @@ +fn main() { + builtin # type_ascribe(10, usize) +} diff --git a/src/tools/rustfmt/tests/target/let_else.rs b/src/tools/rustfmt/tests/target/let_else.rs index f6560e85462..528d2929734 100644 --- a/src/tools/rustfmt/tests/target/let_else.rs +++ b/src/tools/rustfmt/tests/target/let_else.rs @@ -180,8 +180,8 @@ fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_n // Break after the `=` and put the initializer expr on it's own line. // Because the initializer expr is multi-lined the else is placed on it's own line. // The initializer expr has a length of 91, which when indented on the next line - // The `(indent)init` line has a lengh of 99. This is the max length that the `init` can be - // before we start running into max_width issues. I suspect this is becuase the shape is + // The `(indent)init` line has a length of 99. This is the max length that the `init` can be + // before we start running into max_width issues. I suspect this is because the shape is // accounting for the `;` at the end of the `let-else` statement. let Some(x) = some_really_really_really_really_really_really_really_really_really_really_long_name______I @@ -194,7 +194,7 @@ fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_n // Post Formatting: // Max length issues prevent us from formatting. // The initializer expr has a length of 92, which if it would be indented on the next line - // the `(indent)init` line has a lengh of 100 which == max_width of 100. + // the `(indent)init` line has a length of 100 which == max_width of 100. // One might expect formatting to succeed, but I suspect the reason we hit max_width issues is // because the Shape is accounting for the `;` at the end of the `let-else` statement. let Some(x) = some_really_really_really_really_really_really_really_really_really_really_really_long_nameJ else {return}; diff --git a/src/tools/rustfmt/tests/target/no_arg_with_commnet.rs b/src/tools/rustfmt/tests/target/no_arg_with_commnet.rs index 69f61b60f29..21802d87f47 100644 --- a/src/tools/rustfmt/tests/target/no_arg_with_commnet.rs +++ b/src/tools/rustfmt/tests/target/no_arg_with_commnet.rs @@ -1 +1 @@ -fn foo(/* cooment */) {} +fn foo(/* comment */) {} diff --git a/src/tools/rustfmt/tests/target/unsafe_attributes.rs b/src/tools/rustfmt/tests/target/unsafe_attributes.rs new file mode 100644 index 00000000000..a05bedc751a --- /dev/null +++ b/src/tools/rustfmt/tests/target/unsafe_attributes.rs @@ -0,0 +1,34 @@ +#![feature(unsafe_attributes)] +// https://github.com/rust-lang/rust/issues/123757 +// +#![simple_ident] +#![simple::path] +#![simple_ident_expr = ""] +#![simple::path::Expr = ""] +#![simple_ident_tt(a b c)] +#![simple_ident_tt[a b c]] +#![simple_ident_tt{a b c}] +#![simple::path::tt(a b c)] +#![simple::path::tt[a b c]] +#![simple::path::tt{a b c}] +#![unsafe(simple_ident)] +#![unsafe(simple::path)] +#![unsafe(simple_ident_expr = "")] +#![unsafe(simple::path::Expr = "")] +#![unsafe(simple_ident_tt(a b c))] +#![unsafe(simple_ident_tt[a b c])] +#![unsafe(simple_ident_tt{a b c})] +#![unsafe(simple::path::tt(a b c))] +#![unsafe(simple::path::tt[a b c])] +#![unsafe(simple::path::tt{a b c})] +// I don't think `safe` attributes are a thing, but adding these formatting cases here just in case +#![safe(simple_ident)] +#![safe(simple::path)] +#![safe(simple_ident_expr = "")] +#![safe(simple::path::Expr = "")] +#![safe(simple_ident_tt(a b c))] +#![safe(simple_ident_tt[a b c])] +#![safe(simple_ident_tt{a b c})] +#![safe(simple::path::tt(a b c))] +#![safe(simple::path::tt[a b c])] +#![safe(simple::path::tt{a b c})] diff --git a/src/tools/rustfmt/tests/target/unsafe_extern_blocks.rs b/src/tools/rustfmt/tests/target/unsafe_extern_blocks.rs new file mode 100644 index 00000000000..66b4e1604d8 --- /dev/null +++ b/src/tools/rustfmt/tests/target/unsafe_extern_blocks.rs @@ -0,0 +1,18 @@ +// See tracking issue for unsafe_extern_blocks +// https://github.com/rust-lang/rust/issues/123743 + +#![feature(unsafe_extern_blocks)] + +safe static TEST1: i32; + +unsafe extern "C" { + safe static TEST2: i32; + unsafe static TEST3: i32; + static TEST4: i32; + + pub safe static TEST5: i32; + pub unsafe static TEST6: i32; + pub static TEST7: i32; + + safe fn test1(i: i32); +} diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 63963b0bd1c..f39438bd9ac 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -13,6 +13,7 @@ ignore = "0.4.18" semver = "1.0" termcolor = "1.1.3" rustc-hash = "1.1.0" +fluent-syntax = "0.11.1" [[bin]] name = "rust-tidy" diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 2b273b92ec2..07073ef5d40 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -10,19 +10,15 @@ run-make/c-unwind-abi-catch-panic/Makefile run-make/cat-and-grep-sanity-check/Makefile run-make/cdylib-dylib-linkage/Makefile run-make/cdylib-fewer-symbols/Makefile -run-make/comment-section/Makefile run-make/compiler-lookup-paths-2/Makefile run-make/compiler-lookup-paths/Makefile run-make/compiler-rt-works-on-mingw/Makefile -run-make/compressed-debuginfo/Makefile run-make/crate-hash-rustc-version/Makefile -run-make/crate-name-priority/Makefile run-make/cross-lang-lto-clang/Makefile run-make/cross-lang-lto-pgo-smoketest/Makefile run-make/cross-lang-lto-upstream-rlibs/Makefile run-make/cross-lang-lto/Makefile run-make/debug-assertions/Makefile -run-make/debugger-visualizer-dep-info/Makefile run-make/dep-info-doesnt-run-much/Makefile run-make/dep-info-spaces/Makefile run-make/dep-info/Makefile @@ -34,12 +30,10 @@ run-make/emit-shared-files/Makefile run-make/emit-stack-sizes/Makefile run-make/emit-to-stdout/Makefile run-make/env-dep-info/Makefile -run-make/error-writing-dependencies/Makefile run-make/export-executable-symbols/Makefile run-make/extern-diff-internal-name/Makefile run-make/extern-flag-disambiguates/Makefile run-make/extern-flag-pathless/Makefile -run-make/extern-flag-rename-transitive/Makefile run-make/extern-fn-explicit-align/Makefile run-make/extern-fn-generic/Makefile run-make/extern-fn-mangle/Makefile @@ -50,17 +44,14 @@ run-make/extern-fn-with-packed-struct/Makefile run-make/extern-fn-with-union/Makefile run-make/extern-multiple-copies/Makefile run-make/extern-multiple-copies2/Makefile -run-make/extern-overrides-distribution/Makefile run-make/extra-filename-with-temp-outputs/Makefile run-make/fmt-write-bloat/Makefile -run-make/forced-unwind-terminate-pof/Makefile run-make/foreign-double-unwind/Makefile run-make/foreign-exceptions/Makefile run-make/foreign-rust-exceptions/Makefile run-make/include_bytes_deps/Makefile run-make/incr-add-rust-src-component/Makefile run-make/incr-foreign-head-span/Makefile -run-make/inline-always-many-cgu/Makefile run-make/interdependent-c-libraries/Makefile run-make/intrinsic-unreachable/Makefile run-make/invalid-library/Makefile @@ -97,7 +88,6 @@ run-make/libtest-json/Makefile run-make/libtest-junit/Makefile run-make/libtest-padding/Makefile run-make/libtest-thread-limit/Makefile -run-make/link-args-order/Makefile run-make/link-cfg/Makefile run-make/link-framework/Makefile run-make/link-path-order/Makefile @@ -106,19 +96,16 @@ run-make/llvm-ident/Makefile run-make/long-linker-command-lines-cmd-exe/Makefile run-make/long-linker-command-lines/Makefile run-make/longjmp-across-rust/Makefile -run-make/ls-metadata/Makefile run-make/lto-dylib-dep/Makefile run-make/lto-empty/Makefile run-make/lto-linkage-used-attr/Makefile run-make/lto-no-link-whole-rlib/Makefile -run-make/lto-readonly-lib/Makefile run-make/lto-smoke-c/Makefile run-make/macos-deployment-target/Makefile run-make/macos-fat-archive/Makefile run-make/manual-link/Makefile run-make/many-crates-but-no-match/Makefile run-make/metadata-dep-info/Makefile -run-make/metadata-flag-frobs-symbols/Makefile run-make/min-global-align/Makefile run-make/mingw-export-call-convention/Makefile run-make/mismatching-target-triples/Makefile @@ -164,8 +151,6 @@ run-make/raw-dylib-inline-cross-dylib/Makefile run-make/raw-dylib-link-ordinal/Makefile run-make/raw-dylib-stdcall-ordinal/Makefile run-make/redundant-libs/Makefile -run-make/relocation-model/Makefile -run-make/relro-levels/Makefile run-make/remap-path-prefix-dwarf/Makefile run-make/remap-path-prefix/Makefile run-make/reproducible-build-2/Makefile @@ -178,7 +163,6 @@ run-make/rlib-format-packed-bundled-libs-3/Makefile run-make/rlib-format-packed-bundled-libs/Makefile run-make/rmeta-preferred/Makefile run-make/rustc-macro-dep-files/Makefile -run-make/rustdoc-io-error/Makefile run-make/sanitizer-cdylib-link/Makefile run-make/sanitizer-dylib-link/Makefile run-make/sanitizer-staticlib-link/Makefile @@ -192,7 +176,6 @@ run-make/split-debuginfo/Makefile run-make/stable-symbol-names/Makefile run-make/static-dylib-by-default/Makefile run-make/static-extern-type/Makefile -run-make/static-pie/Makefile run-make/staticlib-blank-lib/Makefile run-make/staticlib-dylib-linkage/Makefile run-make/std-core-cycle/Makefile diff --git a/src/tools/tidy/src/fluent_period.rs b/src/tools/tidy/src/fluent_period.rs new file mode 100644 index 00000000000..3a1fb6daf48 --- /dev/null +++ b/src/tools/tidy/src/fluent_period.rs @@ -0,0 +1,84 @@ +//! Checks that no Fluent messages or attributes end in periods (except ellipses) + +use fluent_syntax::ast::{Entry, PatternElement}; + +use crate::walk::{filter_dirs, walk}; +use std::path::Path; + +fn filter_fluent(path: &Path) -> bool { + if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true } +} + +/// Messages allowed to have `.` at their end. +/// +/// These should probably be reworked eventually. +const ALLOWLIST: &[&str] = &[ + "const_eval_long_running", + "const_eval_validation_failure_note", + "driver_impl_ice", + "incremental_corrupt_file", + "mir_build_pointer_pattern", +]; + +fn check_period(filename: &str, contents: &str, bad: &mut bool) { + if filename.contains("codegen") { + // FIXME: Too many codegen messages have periods right now... + return; + } + + let (Ok(parse) | Err((parse, _))) = fluent_syntax::parser::parse(contents); + for entry in &parse.body { + if let Entry::Message(m) = entry { + if ALLOWLIST.contains(&m.id.name) { + continue; + } + + if let Some(pat) = &m.value { + if let Some(PatternElement::TextElement { value }) = pat.elements.last() { + // We don't care about ellipses. + if value.ends_with(".") && !value.ends_with("...") { + let ll = find_line(contents, *value); + let name = m.id.name; + tidy_error!(bad, "{filename}:{ll}: message `{name}` ends in a period"); + } + } + } + + for attr in &m.attributes { + // Teach notes usually have long messages. + if attr.id.name == "teach_note" { + continue; + } + + if let Some(PatternElement::TextElement { value }) = attr.value.elements.last() { + if value.ends_with(".") && !value.ends_with("...") { + let ll = find_line(contents, *value); + let name = attr.id.name; + tidy_error!(bad, "{filename}:{ll}: attr `{name}` ends in a period"); + } + } + } + } + } +} + +/// Evil cursed bad hack. Requires that `value` be a substr (in memory) of `contents`. +fn find_line(haystack: &str, needle: &str) -> usize { + for (ll, line) in haystack.lines().enumerate() { + if line.as_ptr() > needle.as_ptr() { + return ll; + } + } + + 1 +} + +pub fn check(path: &Path, bad: &mut bool) { + walk( + path, + |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)), + &mut |ent, contents| { + check_period(ent.path().to_str().unwrap(), contents, bad); + }, + ); +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index ae9d2b8b8dc..ecd32727fa0 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -72,6 +72,7 @@ pub mod ext_tool_checks; pub mod extdeps; pub mod features; pub mod fluent_alphabetical; +pub mod fluent_period; mod fluent_used; pub(crate) mod iter_header; pub mod known_bug; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 1d2b2e4d034..ec6fc1f07f1 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -115,6 +115,7 @@ fn main() { // Checks that only make sense for the compiler. check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose); check!(fluent_alphabetical, &compiler_path, bless); + check!(fluent_period, &compiler_path); check!(target_policy, &root_path); // Checks that only make sense for the std libs. diff --git a/src/tools/tidy/src/target_policy.rs b/src/tools/tidy/src/target_policy.rs index 06210c8cdb2..cb9a0c1c7f4 100644 --- a/src/tools/tidy/src/target_policy.rs +++ b/src/tools/tidy/src/target_policy.rs @@ -14,8 +14,11 @@ const EXCEPTIONS: &[&str] = &[ "csky_unknown_linux_gnuabiv2hf", // FIXME: disabled since it requires a custom LLVM until the upstream LLVM adds support for the target (https://github.com/espressif/llvm-project/issues/4) "xtensa_esp32_none_elf", + "xtensa_esp32_espidf", "xtensa_esp32s2_none_elf", + "xtensa_esp32s2_espidf", "xtensa_esp32s3_none_elf", + "xtensa_esp32s3_espidf", ]; pub fn check(root_path: &Path, bad: &mut bool) { diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index f2eeda339d8..95857502108 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -1,6 +1,7 @@ //! Tidy check to ensure below in UI test directories: //! - the number of entries in each directory must be less than `ENTRY_LIMIT` //! - there are no stray `.stderr` files + use ignore::Walk; use std::collections::{BTreeSet, HashMap}; use std::ffi::OsStr; diff --git a/tests/assembly/asm/aarch64-modifiers.rs b/tests/assembly/asm/aarch64-modifiers.rs index ffba06ae47b..b7ef1d77ea0 100644 --- a/tests/assembly/asm/aarch64-modifiers.rs +++ b/tests/assembly/asm/aarch64-modifiers.rs @@ -1,5 +1,5 @@ //@ assembly-output: emit-asm -//@ compile-flags: -O +//@ compile-flags: -O -C panic=abort //@ compile-flags: --target aarch64-unknown-linux-gnu //@ needs-llvm-components: aarch64 diff --git a/tests/assembly/asm/arm-modifiers.rs b/tests/assembly/asm/arm-modifiers.rs index fa2e75eb35b..0674e169d72 100644 --- a/tests/assembly/asm/arm-modifiers.rs +++ b/tests/assembly/asm/arm-modifiers.rs @@ -1,5 +1,5 @@ //@ assembly-output: emit-asm -//@ compile-flags: -O +//@ compile-flags: -O -C panic=abort //@ compile-flags: --target armv7-unknown-linux-gnueabihf //@ compile-flags: -C target-feature=+neon //@ needs-llvm-components: arm diff --git a/tests/assembly/asm/arm-types.rs b/tests/assembly/asm/arm-types.rs index 280b6d4a228..eeff1a070b4 100644 --- a/tests/assembly/asm/arm-types.rs +++ b/tests/assembly/asm/arm-types.rs @@ -1,10 +1,13 @@ +//@ revisions: base d32 neon //@ assembly-output: emit-asm //@ compile-flags: --target armv7-unknown-linux-gnueabihf -//@ compile-flags: -C target-feature=+neon //@ compile-flags: -C opt-level=0 +//@[d32] compile-flags: -C target-feature=+d32 +//@[neon] compile-flags: -C target-feature=+neon --cfg d32 +//@[neon] filecheck-flags: --check-prefix d32 //@ needs-llvm-components: arm -#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![feature(no_core, lang_items, rustc_attrs, repr_simd, f16)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] @@ -38,6 +41,8 @@ pub struct i32x2(i32, i32); #[repr(simd)] pub struct i64x1(i64); #[repr(simd)] +pub struct f16x4(f16, f16, f16, f16); +#[repr(simd)] pub struct f32x2(f32, f32); #[repr(simd)] pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8); @@ -48,11 +53,14 @@ pub struct i32x4(i32, i32, i32, i32); #[repr(simd)] pub struct i64x2(i64, i64); #[repr(simd)] +pub struct f16x8(f16, f16, f16, f16, f16, f16, f16, f16); +#[repr(simd)] pub struct f32x4(f32, f32, f32, f32); impl Copy for i8 {} impl Copy for i16 {} impl Copy for i32 {} +impl Copy for f16 {} impl Copy for f32 {} impl Copy for i64 {} impl Copy for f64 {} @@ -61,11 +69,13 @@ impl Copy for i8x8 {} impl Copy for i16x4 {} impl Copy for i32x2 {} impl Copy for i64x1 {} +impl Copy for f16x4 {} impl Copy for f32x2 {} impl Copy for i8x16 {} impl Copy for i16x8 {} impl Copy for i32x4 {} impl Copy for i64x2 {} +impl Copy for f16x8 {} impl Copy for f32x4 {} extern "C" { @@ -152,6 +162,12 @@ check!(reg_i16 i16 reg "mov"); // CHECK: @NO_APP check!(reg_i32 i32 reg "mov"); +// CHECK-LABEL: reg_f16: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_f16 f16 reg "mov"); + // CHECK-LABEL: reg_f32: // CHECK: @APP // CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} @@ -170,6 +186,12 @@ check!(reg_ptr ptr reg "mov"); // CHECK: @NO_APP check!(sreg_i32 i32 sreg "vmov.f32"); +// CHECK-LABEL: sreg_f16: +// CHECK: @APP +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: @NO_APP +check!(sreg_f16 f16 sreg "vmov.f32"); + // CHECK-LABEL: sreg_f32: // CHECK: @APP // CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} @@ -188,52 +210,72 @@ check!(sreg_ptr ptr sreg "vmov.f32"); // CHECK: @NO_APP check!(sreg_low16_i32 i32 sreg_low16 "vmov.f32"); -// CHECK-LABEL: sreg_low16_f32: +// CHECK-LABEL: sreg_low16_f16: // CHECK: @APP // CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} // CHECK: @NO_APP -check!(sreg_low16_f32 f32 sreg_low16 "vmov.f32"); +check!(sreg_low16_f16 f16 sreg_low16 "vmov.f32"); -// CHECK-LABEL: dreg_i64: +// CHECK-LABEL: sreg_low16_f32: // CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} // CHECK: @NO_APP +check!(sreg_low16_f32 f32 sreg_low16 "vmov.f32"); + +// d32-LABEL: dreg_i64: +// d32: @APP +// d32: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// d32: @NO_APP +#[cfg(d32)] check!(dreg_i64 i64 dreg "vmov.f64"); -// CHECK-LABEL: dreg_f64: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// d32-LABEL: dreg_f64: +// d32: @APP +// d32: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// d32: @NO_APP +#[cfg(d32)] check!(dreg_f64 f64 dreg "vmov.f64"); -// CHECK-LABEL: dreg_i8x8: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_i8x8: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_i8x8 i8x8 dreg "vmov.f64"); -// CHECK-LABEL: dreg_i16x4: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_i16x4: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_i16x4 i16x4 dreg "vmov.f64"); -// CHECK-LABEL: dreg_i32x2: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_i32x2: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_i32x2 i32x2 dreg "vmov.f64"); -// CHECK-LABEL: dreg_i64x1: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_i64x1: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_i64x1 i64x1 dreg "vmov.f64"); -// CHECK-LABEL: dreg_f32x2: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_f16x4: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_f16x4 f16x4 dreg "vmov.f64"); + +// neon-LABEL: dreg_f32x2: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_f32x2 f32x2 dreg "vmov.f64"); // CHECK-LABEL: dreg_low16_i64: @@ -248,34 +290,46 @@ check!(dreg_low16_i64 i64 dreg_low16 "vmov.f64"); // CHECK: @NO_APP check!(dreg_low16_f64 f64 dreg_low16 "vmov.f64"); -// CHECK-LABEL: dreg_low16_i8x8: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_low16_i8x8: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_low16_i8x8 i8x8 dreg_low16 "vmov.f64"); -// CHECK-LABEL: dreg_low16_i16x4: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_low16_i16x4: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_low16_i16x4 i16x4 dreg_low16 "vmov.f64"); -// CHECK-LABEL: dreg_low16_i32x2: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_low16_i32x2: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_low16_i32x2 i32x2 dreg_low16 "vmov.f64"); -// CHECK-LABEL: dreg_low16_i64x1: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_low16_i64x1: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_low16_i64x1 i64x1 dreg_low16 "vmov.f64"); -// CHECK-LABEL: dreg_low16_f32x2: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_low16_f16x4: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low16_f16x4 f16x4 dreg_low16 "vmov.f64"); + +// neon-LABEL: dreg_low16_f32x2: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_low16_f32x2 f32x2 dreg_low16 "vmov.f64"); // CHECK-LABEL: dreg_low8_i64: @@ -290,124 +344,172 @@ check!(dreg_low8_i64 i64 dreg_low8 "vmov.f64"); // CHECK: @NO_APP check!(dreg_low8_f64 f64 dreg_low8 "vmov.f64"); -// CHECK-LABEL: dreg_low8_i8x8: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_low8_i8x8: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_low8_i8x8 i8x8 dreg_low8 "vmov.f64"); -// CHECK-LABEL: dreg_low8_i16x4: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_low8_i16x4: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_low8_i16x4 i16x4 dreg_low8 "vmov.f64"); -// CHECK-LABEL: dreg_low8_i32x2: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_low8_i32x2: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_low8_i32x2 i32x2 dreg_low8 "vmov.f64"); -// CHECK-LABEL: dreg_low8_i64x1: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_low8_i64x1: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_low8_i64x1 i64x1 dreg_low8 "vmov.f64"); -// CHECK-LABEL: dreg_low8_f32x2: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: dreg_low8_f16x4: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low8_f16x4 f16x4 dreg_low8 "vmov.f64"); + +// neon-LABEL: dreg_low8_f32x2: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(dreg_low8_f32x2 f32x2 dreg_low8 "vmov.f64"); -// CHECK-LABEL: qreg_i8x16: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_i8x16: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_i8x16 i8x16 qreg "vmov"); -// CHECK-LABEL: qreg_i16x8: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_i16x8: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_i16x8 i16x8 qreg "vmov"); -// CHECK-LABEL: qreg_i32x4: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_i32x4: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_i32x4 i32x4 qreg "vmov"); -// CHECK-LABEL: qreg_i64x2: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_i64x2: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_i64x2 i64x2 qreg "vmov"); -// CHECK-LABEL: qreg_f32x4: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_f16x8: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_f16x8 f16x8 qreg "vmov"); + +// neon-LABEL: qreg_f32x4: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_f32x4 f32x4 qreg "vmov"); -// CHECK-LABEL: qreg_low8_i8x16: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_low8_i8x16: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_low8_i8x16 i8x16 qreg_low8 "vmov"); -// CHECK-LABEL: qreg_low8_i16x8: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_low8_i16x8: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_low8_i16x8 i16x8 qreg_low8 "vmov"); -// CHECK-LABEL: qreg_low8_i32x4: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_low8_i32x4: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_low8_i32x4 i32x4 qreg_low8 "vmov"); -// CHECK-LABEL: qreg_low8_i64x2: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_low8_i64x2: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_low8_i64x2 i64x2 qreg_low8 "vmov"); -// CHECK-LABEL: qreg_low8_f32x4: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_low8_f16x8: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low8_f16x8 f16x8 qreg_low8 "vmov"); + +// neon-LABEL: qreg_low8_f32x4: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_low8_f32x4 f32x4 qreg_low8 "vmov"); -// CHECK-LABEL: qreg_low4_i8x16: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_low4_i8x16: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_low4_i8x16 i8x16 qreg_low4 "vmov"); -// CHECK-LABEL: qreg_low4_i16x8: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_low4_i16x8: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_low4_i16x8 i16x8 qreg_low4 "vmov"); -// CHECK-LABEL: qreg_low4_i32x4: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_low4_i32x4: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_low4_i32x4 i32x4 qreg_low4 "vmov"); -// CHECK-LABEL: qreg_low4_i64x2: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_low4_i64x2: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_low4_i64x2 i64x2 qreg_low4 "vmov"); -// CHECK-LABEL: qreg_low4_f32x4: -// CHECK: @APP -// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// CHECK: @NO_APP +// neon-LABEL: qreg_low4_f16x8: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low4_f16x8 f16x8 qreg_low4 "vmov"); + +// neon-LABEL: qreg_low4_f32x4: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] check!(qreg_low4_f32x4 f32x4 qreg_low4 "vmov"); // CHECK-LABEL: r0_i8: @@ -428,6 +530,12 @@ check_reg!(r0_i16 i16 "r0" "mov"); // CHECK: @NO_APP check_reg!(r0_i32 i32 "r0" "mov"); +// CHECK-LABEL: r0_f16: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check_reg!(r0_f16 f16 "r0" "mov"); + // CHECK-LABEL: r0_f32: // CHECK: @APP // CHECK: mov r0, r0 @@ -446,6 +554,12 @@ check_reg!(r0_ptr ptr "r0" "mov"); // CHECK: @NO_APP check_reg!(s0_i32 i32 "s0" "vmov.f32"); +// CHECK-LABEL: s0_f16: +// CHECK: @APP +// CHECK: vmov.f32 s0, s0 +// CHECK: @NO_APP +check_reg!(s0_f16 f16 "s0" "vmov.f32"); + // CHECK-LABEL: s0_f32: // CHECK: @APP // CHECK: vmov.f32 s0, s0 @@ -458,74 +572,101 @@ check_reg!(s0_f32 f32 "s0" "vmov.f32"); // CHECK: @NO_APP check_reg!(s0_ptr ptr "s0" "vmov.f32"); -// CHECK-LABEL: d0_i64: -// CHECK: @APP -// CHECK: vmov.f64 d0, d0 -// CHECK: @NO_APP +// FIXME(#126797): "d0" should work with `i64` and `f64` even when `d32` is disabled. +// d32-LABEL: d0_i64: +// d32: @APP +// d32: vmov.f64 d0, d0 +// d32: @NO_APP +#[cfg(d32)] check_reg!(d0_i64 i64 "d0" "vmov.f64"); -// CHECK-LABEL: d0_f64: -// CHECK: @APP -// CHECK: vmov.f64 d0, d0 -// CHECK: @NO_APP +// d32-LABEL: d0_f64: +// d32: @APP +// d32: vmov.f64 d0, d0 +// d32: @NO_APP +#[cfg(d32)] check_reg!(d0_f64 f64 "d0" "vmov.f64"); -// CHECK-LABEL: d0_i8x8: -// CHECK: @APP -// CHECK: vmov.f64 d0, d0 -// CHECK: @NO_APP +// neon-LABEL: d0_i8x8: +// neon: @APP +// neon: vmov.f64 d0, d0 +// neon: @NO_APP +#[cfg(neon)] check_reg!(d0_i8x8 i8x8 "d0" "vmov.f64"); -// CHECK-LABEL: d0_i16x4: -// CHECK: @APP -// CHECK: vmov.f64 d0, d0 -// CHECK: @NO_APP +// neon-LABEL: d0_i16x4: +// neon: @APP +// neon: vmov.f64 d0, d0 +// neon: @NO_APP +#[cfg(neon)] check_reg!(d0_i16x4 i16x4 "d0" "vmov.f64"); -// CHECK-LABEL: d0_i32x2: -// CHECK: @APP -// CHECK: vmov.f64 d0, d0 -// CHECK: @NO_APP +// neon-LABEL: d0_i32x2: +// neon: @APP +// neon: vmov.f64 d0, d0 +// neon: @NO_APP +#[cfg(neon)] check_reg!(d0_i32x2 i32x2 "d0" "vmov.f64"); -// CHECK-LABEL: d0_i64x1: -// CHECK: @APP -// CHECK: vmov.f64 d0, d0 -// CHECK: @NO_APP +// neon-LABEL: d0_i64x1: +// neon: @APP +// neon: vmov.f64 d0, d0 +// neon: @NO_APP +#[cfg(neon)] check_reg!(d0_i64x1 i64x1 "d0" "vmov.f64"); -// CHECK-LABEL: d0_f32x2: -// CHECK: @APP -// CHECK: vmov.f64 d0, d0 -// CHECK: @NO_APP +// neon-LABEL: d0_f16x4: +// neon: @APP +// neon: vmov.f64 d0, d0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(d0_f16x4 f16x4 "d0" "vmov.f64"); + +// neon-LABEL: d0_f32x2: +// neon: @APP +// neon: vmov.f64 d0, d0 +// neon: @NO_APP +#[cfg(neon)] check_reg!(d0_f32x2 f32x2 "d0" "vmov.f64"); -// CHECK-LABEL: q0_i8x16: -// CHECK: @APP -// CHECK: vorr q0, q0, q0 -// CHECK: @NO_APP +// neon-LABEL: q0_i8x16: +// neon: @APP +// neon: vorr q0, q0, q0 +// neon: @NO_APP +#[cfg(neon)] check_reg!(q0_i8x16 i8x16 "q0" "vmov"); -// CHECK-LABEL: q0_i16x8: -// CHECK: @APP -// CHECK: vorr q0, q0, q0 -// CHECK: @NO_APP +// neon-LABEL: q0_i16x8: +// neon: @APP +// neon: vorr q0, q0, q0 +// neon: @NO_APP +#[cfg(neon)] check_reg!(q0_i16x8 i16x8 "q0" "vmov"); -// CHECK-LABEL: q0_i32x4: -// CHECK: @APP -// CHECK: vorr q0, q0, q0 -// CHECK: @NO_APP +// neon-LABEL: q0_i32x4: +// neon: @APP +// neon: vorr q0, q0, q0 +// neon: @NO_APP +#[cfg(neon)] check_reg!(q0_i32x4 i32x4 "q0" "vmov"); -// CHECK-LABEL: q0_i64x2: -// CHECK: @APP -// CHECK: vorr q0, q0, q0 -// CHECK: @NO_APP +// neon-LABEL: q0_i64x2: +// neon: @APP +// neon: vorr q0, q0, q0 +// neon: @NO_APP +#[cfg(neon)] check_reg!(q0_i64x2 i64x2 "q0" "vmov"); -// CHECK-LABEL: q0_f32x4: -// CHECK: @APP -// CHECK: vorr q0, q0, q0 -// CHECK: @NO_APP +// neon-LABEL: q0_f16x8: +// neon: @APP +// neon: vorr q0, q0, q0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(q0_f16x8 f16x8 "q0" "vmov"); + +// neon-LABEL: q0_f32x4: +// neon: @APP +// neon: vorr q0, q0, q0 +// neon: @NO_APP +#[cfg(neon)] check_reg!(q0_f32x4 f32x4 "q0" "vmov"); diff --git a/tests/assembly/asm/riscv-types.rs b/tests/assembly/asm/riscv-types.rs index 0d1f8305d37..51b3aaf99d9 100644 --- a/tests/assembly/asm/riscv-types.rs +++ b/tests/assembly/asm/riscv-types.rs @@ -1,12 +1,34 @@ -//@ revisions: riscv64 riscv32 +//@ revisions: riscv64 riscv32 riscv64-zfhmin riscv32-zfhmin riscv64-zfh riscv32-zfh //@ assembly-output: emit-asm + //@[riscv64] compile-flags: --target riscv64imac-unknown-none-elf //@[riscv64] needs-llvm-components: riscv + //@[riscv32] compile-flags: --target riscv32imac-unknown-none-elf //@[riscv32] needs-llvm-components: riscv + +//@[riscv64-zfhmin] compile-flags: --target riscv64imac-unknown-none-elf --cfg riscv64 +//@[riscv64-zfhmin] needs-llvm-components: riscv +//@[riscv64-zfhmin] compile-flags: -C target-feature=+zfhmin +//@[riscv64-zfhmin] filecheck-flags: --check-prefix riscv64 + +//@[riscv32-zfhmin] compile-flags: --target riscv32imac-unknown-none-elf +//@[riscv32-zfhmin] needs-llvm-components: riscv +//@[riscv32-zfhmin] compile-flags: -C target-feature=+zfhmin + +//@[riscv64-zfh] compile-flags: --target riscv64imac-unknown-none-elf --cfg riscv64 +//@[riscv64-zfh] needs-llvm-components: riscv +//@[riscv64-zfh] compile-flags: -C target-feature=+zfh +//@[riscv64-zfh] filecheck-flags: --check-prefix riscv64 --check-prefix zfhmin + +//@[riscv32-zfh] compile-flags: --target riscv32imac-unknown-none-elf +//@[riscv32-zfh] needs-llvm-components: riscv +//@[riscv32-zfh] compile-flags: -C target-feature=+zfh +//@[riscv32-zfh] filecheck-flags: --check-prefix zfhmin + //@ compile-flags: -C target-feature=+d -#![feature(no_core, lang_items, rustc_attrs)] +#![feature(no_core, lang_items, rustc_attrs, f16)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register)] @@ -33,6 +55,7 @@ type ptr = *mut u8; impl Copy for i8 {} impl Copy for i16 {} +impl Copy for f16 {} impl Copy for i32 {} impl Copy for f32 {} impl Copy for i64 {} @@ -103,6 +126,12 @@ macro_rules! check_reg { // CHECK: #NO_APP check!(reg_i8 i8 reg "mv"); +// CHECK-LABEL: reg_f16: +// CHECK: #APP +// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f16 f16 reg "mv"); + // CHECK-LABEL: reg_i16: // CHECK: #APP // CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} @@ -141,6 +170,14 @@ check!(reg_f64 f64 reg "mv"); // CHECK: #NO_APP check!(reg_ptr ptr reg "mv"); +// CHECK-LABEL: freg_f16: +// zfhmin-NOT: or +// CHECK: #APP +// CHECK: fmv.s f{{[a-z0-9]+}}, f{{[a-z0-9]+}} +// CHECK: #NO_APP +// zfhmin-NOT: or +check!(freg_f16 f16 freg "fmv.s"); + // CHECK-LABEL: freg_f32: // CHECK: #APP // CHECK: fmv.s f{{[a-z0-9]+}}, f{{[a-z0-9]+}} @@ -165,6 +202,12 @@ check_reg!(a0_i8 i8 "a0" "mv"); // CHECK: #NO_APP check_reg!(a0_i16 i16 "a0" "mv"); +// CHECK-LABEL: a0_f16: +// CHECK: #APP +// CHECK: mv a0, a0 +// CHECK: #NO_APP +check_reg!(a0_f16 f16 "a0" "mv"); + // CHECK-LABEL: a0_i32: // CHECK: #APP // CHECK: mv a0, a0 @@ -197,6 +240,14 @@ check_reg!(a0_f64 f64 "a0" "mv"); // CHECK: #NO_APP check_reg!(a0_ptr ptr "a0" "mv"); +// CHECK-LABEL: fa0_f16: +// zfhmin-NOT: or +// CHECK: #APP +// CHECK: fmv.s fa0, fa0 +// CHECK: #NO_APP +// zfhmin-NOT: or +check_reg!(fa0_f16 f16 "fa0" "fmv.s"); + // CHECK-LABEL: fa0_f32: // CHECK: #APP // CHECK: fmv.s fa0, fa0 diff --git a/tests/assembly/asm/x86-modifiers.rs b/tests/assembly/asm/x86-modifiers.rs index 1a92585298d..c5e393b1056 100644 --- a/tests/assembly/asm/x86-modifiers.rs +++ b/tests/assembly/asm/x86-modifiers.rs @@ -1,6 +1,6 @@ //@ revisions: x86_64 i686 //@ assembly-output: emit-asm -//@ compile-flags: -O +//@ compile-flags: -O -C panic=abort //@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu //@[x86_64] needs-llvm-components: x86 //@[i686] compile-flags: --target i686-unknown-linux-gnu diff --git a/tests/assembly/simd-bitmask.rs b/tests/assembly/simd-bitmask.rs index 8264a706852..cd22ca06706 100644 --- a/tests/assembly/simd-bitmask.rs +++ b/tests/assembly/simd-bitmask.rs @@ -11,7 +11,7 @@ //@ [aarch64] needs-llvm-components: aarch64 //@ [aarch64] min-llvm-version: 18.0 //@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -O +//@ compile-flags: --crate-type=lib -O -C panic=abort #![feature(no_core, lang_items, repr_simd, intrinsics)] #![no_core] diff --git a/tests/assembly/simd-intrinsic-gather.rs b/tests/assembly/simd-intrinsic-gather.rs index ef6b597c25f..83015f05ab3 100644 --- a/tests/assembly/simd-intrinsic-gather.rs +++ b/tests/assembly/simd-intrinsic-gather.rs @@ -4,7 +4,7 @@ //@ [x86-avx512] needs-llvm-components: x86 //@ [x86-avx512] min-llvm-version: 18.0 //@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -O +//@ compile-flags: --crate-type=lib -O -C panic=abort #![feature(no_core, lang_items, repr_simd, intrinsics)] #![no_core] diff --git a/tests/assembly/simd-intrinsic-mask-load.rs b/tests/assembly/simd-intrinsic-mask-load.rs index 49d231c45f8..d537c143d36 100644 --- a/tests/assembly/simd-intrinsic-mask-load.rs +++ b/tests/assembly/simd-intrinsic-mask-load.rs @@ -6,7 +6,7 @@ //@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq //@ [x86-avx512] needs-llvm-components: x86 //@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -O +//@ compile-flags: --crate-type=lib -O -C panic=abort #![feature(no_core, lang_items, repr_simd, intrinsics)] #![no_core] diff --git a/tests/assembly/simd-intrinsic-mask-reduce.rs b/tests/assembly/simd-intrinsic-mask-reduce.rs index 72c3f6376e8..dd4dbaeda76 100644 --- a/tests/assembly/simd-intrinsic-mask-reduce.rs +++ b/tests/assembly/simd-intrinsic-mask-reduce.rs @@ -8,7 +8,7 @@ //@ [aarch64] needs-llvm-components: aarch64 //@ [aarch64] min-llvm-version: 18.0 //@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -O +//@ compile-flags: --crate-type=lib -O -C panic=abort #![feature(no_core, lang_items, repr_simd, intrinsics)] #![no_core] diff --git a/tests/assembly/simd-intrinsic-mask-store.rs b/tests/assembly/simd-intrinsic-mask-store.rs index a6611e1c23d..5d4c00c3823 100644 --- a/tests/assembly/simd-intrinsic-mask-store.rs +++ b/tests/assembly/simd-intrinsic-mask-store.rs @@ -6,7 +6,7 @@ //@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq //@ [x86-avx512] needs-llvm-components: x86 //@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -O +//@ compile-flags: --crate-type=lib -O -C panic=abort #![feature(no_core, lang_items, repr_simd, intrinsics)] #![no_core] diff --git a/tests/assembly/simd-intrinsic-scatter.rs b/tests/assembly/simd-intrinsic-scatter.rs index 6ffefb0801a..55095e4cb68 100644 --- a/tests/assembly/simd-intrinsic-scatter.rs +++ b/tests/assembly/simd-intrinsic-scatter.rs @@ -4,7 +4,7 @@ //@ [x86-avx512] needs-llvm-components: x86 //@ [x86-avx512] min-llvm-version: 18.0 //@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -O +//@ compile-flags: --crate-type=lib -O -C panic=abort #![feature(no_core, lang_items, repr_simd, intrinsics)] #![no_core] diff --git a/tests/assembly/simd-intrinsic-select.rs b/tests/assembly/simd-intrinsic-select.rs index 3f36402e3d0..4dfc2f9ed1f 100644 --- a/tests/assembly/simd-intrinsic-select.rs +++ b/tests/assembly/simd-intrinsic-select.rs @@ -9,7 +9,7 @@ //@ [aarch64] needs-llvm-components: aarch64 //@ [aarch64] min-llvm-version: 18.0 //@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -O +//@ compile-flags: --crate-type=lib -O -C panic=abort #![feature(no_core, lang_items, repr_simd, intrinsics)] #![no_core] diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index b069e667bf5..32cce3839dc 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -581,12 +581,21 @@ revisions: xtensa_esp32_none_elf [xtensa_esp32_none_elf] compile-flags: --target xtensa-esp32-none-elf [xtensa_esp32_none_elf] needs-llvm-components: xtensa + revisions: xtensa_esp32_espidf + [xtensa_esp32_espidf] compile-flags: --target xtensa-esp32s2-espidf + [xtensa_esp32_espidf] needs-llvm-components: xtensa revisions: xtensa_esp32s2_none_elf [xtensa_esp32s2_none_elf] compile-flags: --target xtensa-esp32s2-none-elf [xtensa_esp32s2_none_elf] needs-llvm-components: xtensa + revisions: xtensa_esp32s2_espidf + [xtensa_esp32s2_espidf] compile-flags: --target xtensa-esp32s2-espidf + [xtensa_esp32s2_espidf] needs-llvm-components: xtensa revisions: xtensa_esp32s3_none_elf [xtensa_esp32s3_none_elf] compile-flags: --target xtensa-esp32s3-none-elf [xtensa_esp32s3_none_elf] needs-llvm-components: xtensa + revisions: xtensa_esp32s3_espidf + [xtensa_esp32s3_espidf] compile-flags: --target xtensa-esp32s3-espidf + [xtensa_esp32s3_espidf] needs-llvm-components: xtensa */ // Sanity-check that each target can produce assembly code. diff --git a/tests/assembly/wasm_exceptions.rs b/tests/assembly/wasm_exceptions.rs index 7bdf7f1287c..f05ccfadc58 100644 --- a/tests/assembly/wasm_exceptions.rs +++ b/tests/assembly/wasm_exceptions.rs @@ -6,12 +6,12 @@ #![crate_type = "lib"] #![feature(core_intrinsics)] -#![feature(rustc_attrs)] -extern "C" { +extern "C-unwind" { fn may_panic(); +} - #[rustc_nounwind] +extern "C" { fn log_number(number: usize); } diff --git a/tests/codegen/align-byval-alignment-mismatch.rs b/tests/codegen/align-byval-alignment-mismatch.rs index 71f2dd42ec2..835cc7393e5 100644 --- a/tests/codegen/align-byval-alignment-mismatch.rs +++ b/tests/codegen/align-byval-alignment-mismatch.rs @@ -1,9 +1,9 @@ // ignore-tidy-linelength //@ revisions:i686-linux x86_64-linux -//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu +//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu -C panic=abort //@[i686-linux] needs-llvm-components: x86 -//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu -C panic=abort //@[x86_64-linux] needs-llvm-components: x86 // Tests that we correctly copy arguments into allocas when the alignment of the byval argument diff --git a/tests/codegen/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs index 2d9efb52c7c..70834707564 100644 --- a/tests/codegen/avr/avr-func-addrspace.rs +++ b/tests/codegen/avr/avr-func-addrspace.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -O --target=avr-unknown-gnu-atmega328 --crate-type=rlib +//@ compile-flags: -O --target=avr-unknown-gnu-atmega328 --crate-type=rlib -C panic=abort //@ needs-llvm-components: avr // This test validates that function pointers can be stored in global variables diff --git a/tests/codegen/catch-unwind.rs b/tests/codegen/catch-unwind.rs index 4e1f9a88e95..48ad486fa03 100644 --- a/tests/codegen/catch-unwind.rs +++ b/tests/codegen/catch-unwind.rs @@ -14,7 +14,6 @@ //@ ignore-loongarch64 FIXME #![crate_type = "lib"] -#![feature(c_unwind)] extern "C" { fn bar(); diff --git a/tests/codegen/cffi/c-variadic.rs b/tests/codegen/cffi/c-variadic.rs index 914d1623ed2..140d2f37f46 100644 --- a/tests/codegen/cffi/c-variadic.rs +++ b/tests/codegen/cffi/c-variadic.rs @@ -4,7 +4,6 @@ #![crate_type = "lib"] #![feature(c_variadic)] -#![feature(c_unwind)] #![no_std] use core::ffi::VaList; diff --git a/tests/codegen/debuginfo-inline-callsite-location.rs b/tests/codegen/debuginfo-inline-callsite-location.rs index f690c9c0937..aee07b4eb8c 100644 --- a/tests/codegen/debuginfo-inline-callsite-location.rs +++ b/tests/codegen/debuginfo-inline-callsite-location.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -g -O +//@ compile-flags: -g -O -C panic=abort // Check that each inline call site for the same function uses the same "sub-program" so that LLVM // can correctly merge the debug info if it merges the inlined code (e.g., for merging of tail diff --git a/tests/codegen/force-frame-pointers.rs b/tests/codegen/force-frame-pointers.rs index 84e0bcb39ad..88c918945d6 100644 --- a/tests/codegen/force-frame-pointers.rs +++ b/tests/codegen/force-frame-pointers.rs @@ -1,6 +1,18 @@ -//@ compile-flags: -C no-prepopulate-passes -C force-frame-pointers=y -Copt-level=0 +//@ revisions: Always NonLeaf +//@ [Always] compile-flags: -Cforce-frame-pointers=yes +//@ [NonLeaf] compile-flags: -Cforce-frame-pointers=non-leaf +//@ compile-flags: -Zunstable-options +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 +//@ [NonLeaf] ignore-illumos +//@ [NonLeaf] ignore-openbsd +//@ [NonLeaf] ignore-x86 +//@ [NonLeaf] ignore-x86_64-apple-darwin +//@ [NonLeaf] ignore-windows-gnu +//@ [NonLeaf] ignore-thumb +// result is platform-dependent based on platform's frame pointer settings #![crate_type = "lib"] -// CHECK: attributes #{{.*}} "frame-pointer"="all" +// Always: attributes #{{.*}} "frame-pointer"="all" +// NonLeaf: attributes #{{.*}} "frame-pointer"="non-leaf" pub fn foo() {} diff --git a/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs b/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs index ae02c3fb79e..aee2edd8dfa 100644 --- a/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs +++ b/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs @@ -3,8 +3,12 @@ // CHECK-LABEL: @write_u8_variant_a // CHECK-NEXT: {{.*}}: -// CHECK-NEXT: getelementptr // CHECK-NEXT: icmp ugt +// CHECK-NEXT: getelementptr +// CHECK-NEXT: select i1 {{.+}} null +// CHECK-NEXT: insertvalue +// CHECK-NEXT: insertvalue +// CHECK-NEXT: ret #[no_mangle] pub fn write_u8_variant_a(bytes: &mut [u8], buf: u8, offset: usize) -> Option<&mut [u8]> { let buf = buf.to_le_bytes(); diff --git a/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs index 977749ad578..ed0af90aaaf 100644 --- a/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs +++ b/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --target riscv64gc-unknown-linux-gnu -O -C no-prepopulate-passes +//@ compile-flags: --target riscv64gc-unknown-linux-gnu -O -C no-prepopulate-passes -C panic=abort //@ needs-llvm-components: riscv #![crate_type = "lib"] diff --git a/tests/codegen/unwind-abis/aapcs-unwind-abi.rs b/tests/codegen/unwind-abis/aapcs-unwind-abi.rs index 48c7ecf7824..0d9c7757883 100644 --- a/tests/codegen/unwind-abis/aapcs-unwind-abi.rs +++ b/tests/codegen/unwind-abis/aapcs-unwind-abi.rs @@ -1,7 +1,7 @@ //@ needs-llvm-components: arm //@ compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib -Cno-prepopulate-passes #![no_core] -#![feature(no_core, lang_items, c_unwind)] +#![feature(no_core, lang_items)] #[lang = "sized"] trait Sized {} diff --git a/tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs b/tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs index 8bb2122946f..8d2745ba2f7 100644 --- a/tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs +++ b/tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs @@ -4,7 +4,6 @@ // when the code is compiled with `panic=abort`. #![crate_type = "lib"] -#![feature(c_unwind)] // CHECK: @rust_item_that_can_unwind() unnamed_addr [[ATTR0:#[0-9]+]] #[no_mangle] diff --git a/tests/codegen/unwind-abis/c-unwind-abi.rs b/tests/codegen/unwind-abis/c-unwind-abi.rs index 99763943a6a..46c08b5fc4f 100644 --- a/tests/codegen/unwind-abis/c-unwind-abi.rs +++ b/tests/codegen/unwind-abis/c-unwind-abi.rs @@ -6,7 +6,6 @@ // to prevent LLVM from inferring the attribute. #![crate_type = "lib"] -#![feature(c_unwind)] // CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { #[no_mangle] diff --git a/tests/codegen/unwind-abis/cdecl-unwind-abi.rs b/tests/codegen/unwind-abis/cdecl-unwind-abi.rs index 78dbb55b35a..8e643d6ce49 100644 --- a/tests/codegen/unwind-abis/cdecl-unwind-abi.rs +++ b/tests/codegen/unwind-abis/cdecl-unwind-abi.rs @@ -6,7 +6,6 @@ // disable optimizations above to prevent LLVM from inferring the attribute. #![crate_type = "lib"] -#![feature(c_unwind)] // CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { #[no_mangle] diff --git a/tests/codegen/unwind-abis/fastcall-unwind-abi.rs b/tests/codegen/unwind-abis/fastcall-unwind-abi.rs index 3cbeaf51d96..4c7b2856e2e 100644 --- a/tests/codegen/unwind-abis/fastcall-unwind-abi.rs +++ b/tests/codegen/unwind-abis/fastcall-unwind-abi.rs @@ -1,7 +1,7 @@ //@ needs-llvm-components: x86 //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes #![no_core] -#![feature(no_core, lang_items, c_unwind)] +#![feature(no_core, lang_items)] #[lang = "sized"] trait Sized {} diff --git a/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs b/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs deleted file mode 100644 index a7f7f2fb77f..00000000000 --- a/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -C opt-level=0 -//@ needs-unwind - -#![crate_type = "lib"] - -// We disable optimizations to prevent LLVM from inferring the attribute. - -extern "C" { - fn bar(); -} - -// CHECK-NOT: Function Attrs:{{.*}}nounwind -pub unsafe extern "C" fn foo() { - bar(); -} - -// Note that this test will get removed when `C-unwind` is fully stabilized diff --git a/tests/codegen/unwind-abis/nounwind.rs b/tests/codegen/unwind-abis/nounwind.rs index 80bf8d67091..e40ed48ca73 100644 --- a/tests/codegen/unwind-abis/nounwind.rs +++ b/tests/codegen/unwind-abis/nounwind.rs @@ -2,7 +2,6 @@ //@ needs-unwind #![crate_type = "lib"] -#![feature(c_unwind)] // We disable optimizations to prevent LLVM from inferring the attribute. diff --git a/tests/codegen/unwind-abis/stdcall-unwind-abi.rs b/tests/codegen/unwind-abis/stdcall-unwind-abi.rs index ffb235cd116..ffc11d1faef 100644 --- a/tests/codegen/unwind-abis/stdcall-unwind-abi.rs +++ b/tests/codegen/unwind-abis/stdcall-unwind-abi.rs @@ -1,7 +1,7 @@ //@ needs-llvm-components: x86 //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes #![no_core] -#![feature(no_core, lang_items, c_unwind)] +#![feature(no_core, lang_items)] #[lang = "sized"] trait Sized {} diff --git a/tests/codegen/unwind-abis/system-unwind-abi.rs b/tests/codegen/unwind-abis/system-unwind-abi.rs index 1dd0e9bbbec..5f910248346 100644 --- a/tests/codegen/unwind-abis/system-unwind-abi.rs +++ b/tests/codegen/unwind-abis/system-unwind-abi.rs @@ -6,7 +6,6 @@ // optimizations above to prevent LLVM from inferring the attribute. #![crate_type = "lib"] -#![feature(c_unwind)] // CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { #[no_mangle] diff --git a/tests/codegen/unwind-abis/sysv64-unwind-abi.rs b/tests/codegen/unwind-abis/sysv64-unwind-abi.rs index 9824009dc55..c869ca7e2b8 100644 --- a/tests/codegen/unwind-abis/sysv64-unwind-abi.rs +++ b/tests/codegen/unwind-abis/sysv64-unwind-abi.rs @@ -1,7 +1,7 @@ //@ needs-llvm-components: x86 //@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes #![no_core] -#![feature(no_core, lang_items, c_unwind)] +#![feature(no_core, lang_items)] #[lang = "sized"] trait Sized {} diff --git a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs index a96f4d5a350..19b23ee47ba 100644 --- a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs +++ b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs @@ -1,7 +1,7 @@ //@ needs-llvm-components: x86 //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes #![no_core] -#![feature(no_core, lang_items, c_unwind)] +#![feature(no_core, lang_items)] #[lang = "sized"] trait Sized {} diff --git a/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs b/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs index 9929e3e3703..b420f67ca9b 100644 --- a/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs +++ b/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs @@ -1,7 +1,7 @@ //@ needs-llvm-components: x86 //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes #![no_core] -#![feature(no_core, lang_items, c_unwind, abi_vectorcall)] +#![feature(no_core, lang_items, abi_vectorcall)] #[lang = "sized"] trait Sized {} diff --git a/tests/codegen/unwind-abis/win64-unwind-abi.rs b/tests/codegen/unwind-abis/win64-unwind-abi.rs index a45a94f628d..2697d3cbcd6 100644 --- a/tests/codegen/unwind-abis/win64-unwind-abi.rs +++ b/tests/codegen/unwind-abis/win64-unwind-abi.rs @@ -1,7 +1,7 @@ //@ needs-llvm-components: x86 //@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes #![no_core] -#![feature(no_core, lang_items, c_unwind)] +#![feature(no_core, lang_items)] #[lang = "sized"] trait Sized {} diff --git a/tests/codegen/unwind-and-panic-abort.rs b/tests/codegen/unwind-and-panic-abort.rs index 430502308cf..8efa140058a 100644 --- a/tests/codegen/unwind-and-panic-abort.rs +++ b/tests/codegen/unwind-and-panic-abort.rs @@ -1,7 +1,6 @@ //@ compile-flags: -C panic=abort #![crate_type = "lib"] -#![feature(c_unwind)] extern "C-unwind" { fn bar(); diff --git a/tests/codegen/unwind-extern-exports.rs b/tests/codegen/unwind-extern-exports.rs index ea59748b3bc..e692fd1a547 100644 --- a/tests/codegen/unwind-extern-exports.rs +++ b/tests/codegen/unwind-extern-exports.rs @@ -2,7 +2,6 @@ //@ needs-unwind #![crate_type = "lib"] -#![feature(c_unwind)] // Make sure these all do *not* get the attribute. // We disable optimizations to prevent LLVM from inferring the attribute. diff --git a/tests/codegen/unwind-extern-imports.rs b/tests/codegen/unwind-extern-imports.rs index 790e4def8b3..dfae8aae64a 100644 --- a/tests/codegen/unwind-extern-imports.rs +++ b/tests/codegen/unwind-extern-imports.rs @@ -2,7 +2,6 @@ //@ needs-unwind #![crate_type = "lib"] -#![feature(c_unwind)] extern "C" { // CHECK: Function Attrs:{{.*}}nounwind diff --git a/tests/codegen/wasm_exceptions.rs b/tests/codegen/wasm_exceptions.rs index 3910850e03a..719499dd8ea 100644 --- a/tests/codegen/wasm_exceptions.rs +++ b/tests/codegen/wasm_exceptions.rs @@ -3,12 +3,12 @@ #![crate_type = "lib"] #![feature(core_intrinsics)] -#![feature(rustc_attrs)] -extern "C" { +extern "C-unwind" { fn may_panic(); +} - #[rustc_nounwind] +extern "C" { fn log_number(number: usize); } diff --git a/tests/coverage/abort.cov-map b/tests/coverage/abort.cov-map index 5673fa98ca6..15156ec9811 100644 --- a/tests/coverage/abort.cov-map +++ b/tests/coverage/abort.cov-map @@ -1,5 +1,5 @@ Function name: abort::main -Raw bytes (89): 0x[01, 01, 0a, 01, 27, 05, 09, 03, 0d, 22, 11, 03, 0d, 03, 0d, 22, 15, 03, 0d, 03, 0d, 05, 09, 0d, 01, 0e, 01, 01, 1b, 03, 02, 0b, 00, 18, 22, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 0e, 02, 0a, 00, 0b, 22, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 1a, 00, 31, 00, 32, 22, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 27, 01, 09, 00, 17, 0d, 02, 05, 01, 02] +Raw bytes (89): 0x[01, 01, 0a, 01, 27, 05, 09, 03, 0d, 22, 11, 03, 0d, 03, 0d, 22, 15, 03, 0d, 03, 0d, 05, 09, 0d, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 22, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 0e, 02, 0a, 00, 0b, 22, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 1a, 00, 31, 00, 32, 22, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 27, 01, 09, 00, 17, 0d, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 10 @@ -14,7 +14,7 @@ Number of expressions: 10 - expression 8 operands: lhs = Expression(0, Add), rhs = Counter(3) - expression 9 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 13 -- Code(Counter(0)) at (prev + 14, 1) to (start + 1, 27) +- Code(Counter(0)) at (prev + 13, 1) to (start + 1, 27) - Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 24) = (c0 + (c1 + c2)) - Code(Expression(8, Sub)) at (prev + 1, 12) to (start + 0, 25) @@ -36,13 +36,13 @@ Number of file 0 mappings: 13 - Code(Counter(3)) at (prev + 2, 5) to (start + 1, 2) Function name: abort::might_abort -Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 01, 14, 05, 02, 09, 01, 24, 02, 02, 0c, 03, 02] +Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 03, 01, 01, 14, 05, 02, 09, 01, 24, 02, 02, 0c, 03, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20) +- Code(Counter(0)) at (prev + 3, 1) to (start + 1, 20) - Code(Counter(1)) at (prev + 2, 9) to (start + 1, 36) - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2) = (c0 - c1) diff --git a/tests/coverage/abort.coverage b/tests/coverage/abort.coverage index b658a656259..29e3ad5eda7 100644 --- a/tests/coverage/abort.coverage +++ b/tests/coverage/abort.coverage @@ -1,4 +1,3 @@ - LL| |#![feature(c_unwind)] LL| |#![allow(unused_assignments)] LL| | LL| 12|extern "C" fn might_abort(should_abort: bool) { diff --git a/tests/coverage/abort.rs b/tests/coverage/abort.rs index 649e8e52a49..6c06a3f9d87 100644 --- a/tests/coverage/abort.rs +++ b/tests/coverage/abort.rs @@ -1,4 +1,3 @@ -#![feature(c_unwind)] #![allow(unused_assignments)] extern "C" fn might_abort(should_abort: bool) { diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map index 156947f4e21..21fad22f58f 100644 --- a/tests/coverage/closure_macro.cov-map +++ b/tests/coverage/closure_macro.cov-map @@ -22,19 +22,19 @@ Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Function name: closure_macro::main::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] +Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 0d, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) -- expression 2 operands: lhs = Counter(2), rhs = Zero +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 16, 28) to (start + 3, 33) - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) - Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) = (c0 - c1) -- Code(Zero) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30) - Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10) - = (c1 + (c2 + Zero)) + = (c1 + (c2 + c3)) diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map index 0f2b4e01748..f2efd550591 100644 --- a/tests/coverage/closure_macro_async.cov-map +++ b/tests/coverage/closure_macro_async.cov-map @@ -30,19 +30,19 @@ Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Function name: closure_macro_async::test::{closure#0}::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 12, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] +Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 0d, 05, 01, 12, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) -- expression 2 operands: lhs = Counter(2), rhs = Zero +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 18, 28) to (start + 3, 33) - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) - Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) = (c0 - c1) -- Code(Zero) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30) - Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10) - = (c1 + (c2 + Zero)) + = (c1 + (c2 + c3)) diff --git a/tests/crashes/120503.rs b/tests/crashes/120503.rs deleted file mode 100644 index 28f1e3dfd94..00000000000 --- a/tests/crashes/120503.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #120503 -#![feature(effects)] - -trait MyTrait {} - -impl MyTrait for i32 { - async const fn bar(&self) { - main8().await; - } -} diff --git a/tests/crashes/121536.rs b/tests/crashes/121536.rs deleted file mode 100644 index 000e7cb15eb..00000000000 --- a/tests/crashes/121536.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: #121536 -#![feature(effects)] - -#[derive(Debug, Clone, Copy)] -pub struct Vec3 { - pub x: f32, - pub y: f32, - pub z: f32, -} - -impl std::ops::Add<Vec3> for Vec3 { - type Output = Vec3; - const fn add(self, b: Vec3) -> Self::Output { - Vec3 { - x: self.x + b.x, - y: self.y + b.y, - z: self.z + b.z, - } - } -} diff --git a/tests/crashes/122044.rs b/tests/crashes/122044.rs deleted file mode 100644 index 4c1d0de5719..00000000000 --- a/tests/crashes/122044.rs +++ /dev/null @@ -1,38 +0,0 @@ -//@ known-bug: #122044 -use std::hint::black_box; - -trait Func { - type Ret: Id; -} - -trait Id { - type Assoc; -} -impl Id for u32 {} -impl Id for u32 {} - -impl<F: FnOnce() -> R, R: Id> Func for F { - type Ret = R; -} - -fn bar() -> impl Copy + Id { - 0u32 -} - -struct Foo<T: Func> { - _func: T, - value: Option<<<T as Func>::Ret as Id>::Assoc>, -} - -fn main() { - let mut fn_def = black_box(Foo { - _func: bar, - value: None, - }); - let fn_ptr = black_box(Foo { - _func: bar as fn() -> _, - value: None, - }); - - fn_def.value = fn_ptr.value; -} diff --git a/tests/crashes/122587-1.rs b/tests/crashes/122587-1.rs deleted file mode 100644 index ea0e843a10c..00000000000 --- a/tests/crashes/122587-1.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: #122587 -const b: f16 = 0.0f16; -pub fn main() { - let b = 0.0f16; -} diff --git a/tests/crashes/123255.rs b/tests/crashes/123255.rs deleted file mode 100644 index a94a2a0422e..00000000000 --- a/tests/crashes/123255.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: rust-lang/rust#123255 -//@ edition:2021 -#![crate_type = "lib"] - -pub fn a() {} - -mod handlers { - pub struct C(&()); - pub fn c() -> impl Fn() -> C { - let a1 = (); - || C((crate::a(), a1).into()) - } -} diff --git a/tests/crashes/123893.rs b/tests/crashes/123893.rs index 137ae783511..05237d002b8 100644 --- a/tests/crashes/123893.rs +++ b/tests/crashes/123893.rs @@ -11,6 +11,7 @@ fn generic_impl<T>() { impl<T> MagicTrait for T { const IS_BIG: bool = true; } + more_cost(); if T::IS_BIG { big_impl::<i32>(); } @@ -18,3 +19,6 @@ fn generic_impl<T>() { #[inline(never)] fn big_impl<T>() {} + +#[inline(never)] +fn more_cost() {} diff --git a/tests/crashes/126521.rs b/tests/crashes/126521.rs deleted file mode 100644 index 0a025aabcf2..00000000000 --- a/tests/crashes/126521.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: rust-lang/rust#126521 -macro_rules! foo { - ($val:ident) => { - true; - }; -} - -fn main() { - #[expect(semicolon_in_expressions_from_macros)] - let _ = foo!(x); -} diff --git a/tests/incremental/const-generics/issue-64087.rs b/tests/incremental/const-generics/issue-64087.rs index 97f212b3fbb..787f2af8aa3 100644 --- a/tests/incremental/const-generics/issue-64087.rs +++ b/tests/incremental/const-generics/issue-64087.rs @@ -6,4 +6,6 @@ fn combinator<T, const S: usize>() -> [T; S] {} fn main() { combinator().into_iter(); //[cfail1]~^ ERROR type annotations needed + //[cfail1]~| ERROR type annotations needed + //[cfail1]~| ERROR type annotations needed } diff --git a/tests/incremental/unrecoverable_query.rs b/tests/incremental/unrecoverable_query.rs new file mode 100644 index 00000000000..e17236bebd2 --- /dev/null +++ b/tests/incremental/unrecoverable_query.rs @@ -0,0 +1,40 @@ +// If it is impossible to find query arguments just from the hash +// compiler should treat the node as red + +// In this test prior to fixing compiler was having problems figuring out +// drop impl for T inside of m + +//@ revisions:cfail1 cfail2 +//@ compile-flags: --crate-type=lib +//@ build-pass + +pub trait P { + type A; +} + +struct S; + +impl P for S { + type A = C; +} + +struct T<D: P>(D::A, Z<D>); + +struct Z<D: P>(D::A, String); + +impl<D: P> T<D> { + pub fn i() -> Self { + loop {} + } +} + +enum C { + #[cfg(cfail1)] + Up(()), + #[cfg(cfail2)] + Lorry(()), +} + +pub fn m() { + T::<S>::i(); +} diff --git a/tests/mir-opt/gvn.array_len.GVN.panic-abort.diff b/tests/mir-opt/gvn.array_len.GVN.panic-abort.diff new file mode 100644 index 00000000000..90654e05662 --- /dev/null +++ b/tests/mir-opt/gvn.array_len.GVN.panic-abort.diff @@ -0,0 +1,31 @@ +- // MIR for `array_len` before GVN ++ // MIR for `array_len` after GVN + + fn array_len(_1: &mut [i32; 42]) -> usize { + debug x => _1; + let mut _0: usize; + let _2: &[i32]; + let mut _3: &[i32; 42]; + let mut _4: *const [i32]; + scope 1 { + debug x => _2; + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = &(*_1); + _2 = move _3 as &[i32] (PointerCoercion(Unsize)); + StorageDead(_3); + StorageLive(_4); + _4 = &raw const (*_2); +- _0 = PtrMetadata(move _4); ++ _0 = const 42_usize; + StorageDead(_4); +- StorageDead(_2); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.array_len.GVN.panic-unwind.diff b/tests/mir-opt/gvn.array_len.GVN.panic-unwind.diff new file mode 100644 index 00000000000..90654e05662 --- /dev/null +++ b/tests/mir-opt/gvn.array_len.GVN.panic-unwind.diff @@ -0,0 +1,31 @@ +- // MIR for `array_len` before GVN ++ // MIR for `array_len` after GVN + + fn array_len(_1: &mut [i32; 42]) -> usize { + debug x => _1; + let mut _0: usize; + let _2: &[i32]; + let mut _3: &[i32; 42]; + let mut _4: *const [i32]; + scope 1 { + debug x => _2; + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = &(*_1); + _2 = move _3 as &[i32] (PointerCoercion(Unsize)); + StorageDead(_3); + StorageLive(_4); + _4 = &raw const (*_2); +- _0 = PtrMetadata(move _4); ++ _0 = const 42_usize; + StorageDead(_4); +- StorageDead(_2); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff index 25d0e5ccf49..0c49e706c9e 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:612:19: 612:21}; + let mut _9: {closure@$DIR/gvn.rs:614:19: 614:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:612:19: 612:21}; + let mut _13: {closure@$DIR/gvn.rs:614:19: 614:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:612:19: 612:21}; + let _7: {closure@$DIR/gvn.rs:614:19: 614:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:612:19: 612:21}; +- _7 = {closure@$DIR/gvn.rs:614:19: 614:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff index 3c5fd944d6b..e5f865b74b9 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:612:19: 612:21}; + let mut _9: {closure@$DIR/gvn.rs:614:19: 614:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:612:19: 612:21}; + let mut _13: {closure@$DIR/gvn.rs:614:19: 614:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:612:19: 612:21}; + let _7: {closure@$DIR/gvn.rs:614:19: 614:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:612:19: 612:21}; +- _7 = {closure@$DIR/gvn.rs:614:19: 614:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-abort.diff b/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-abort.diff new file mode 100644 index 00000000000..1d462a8a23c --- /dev/null +++ b/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-abort.diff @@ -0,0 +1,38 @@ +- // MIR for `generic_cast_metadata` before GVN ++ // MIR for `generic_cast_metadata` after GVN + + fn generic_cast_metadata(_1: *const [T], _2: *const A, _3: *const B) -> () { + let mut _0: (); + let mut _4: *const T; + let mut _5: (); + let mut _6: *const (&A, [T]); + let mut _7: usize; + let mut _8: *const (T, B); + let mut _9: <B as std::ptr::Pointee>::Metadata; + let mut _10: *const (T, A); + let mut _11: <A as std::ptr::Pointee>::Metadata; + let mut _12: *mut A; + let mut _13: <A as std::ptr::Pointee>::Metadata; + let mut _14: *mut B; + let mut _15: <B as std::ptr::Pointee>::Metadata; + + bb0: { + _4 = _1 as *const T (PtrToPtr); + _5 = PtrMetadata(_4); + _6 = _1 as *const (&A, [T]) (PtrToPtr); +- _7 = PtrMetadata(_6); ++ _7 = PtrMetadata(_1); + _8 = _2 as *const (T, B) (PtrToPtr); + _9 = PtrMetadata(_8); + _10 = _2 as *const (T, A) (PtrToPtr); +- _11 = PtrMetadata(_10); ++ _11 = PtrMetadata(_2); + _12 = _3 as *mut A (PtrToPtr); + _13 = PtrMetadata(_12); + _14 = _3 as *mut B (PtrToPtr); +- _15 = PtrMetadata(_14); ++ _15 = PtrMetadata(_3); + return; + } + } + diff --git a/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-unwind.diff b/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-unwind.diff new file mode 100644 index 00000000000..1d462a8a23c --- /dev/null +++ b/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-unwind.diff @@ -0,0 +1,38 @@ +- // MIR for `generic_cast_metadata` before GVN ++ // MIR for `generic_cast_metadata` after GVN + + fn generic_cast_metadata(_1: *const [T], _2: *const A, _3: *const B) -> () { + let mut _0: (); + let mut _4: *const T; + let mut _5: (); + let mut _6: *const (&A, [T]); + let mut _7: usize; + let mut _8: *const (T, B); + let mut _9: <B as std::ptr::Pointee>::Metadata; + let mut _10: *const (T, A); + let mut _11: <A as std::ptr::Pointee>::Metadata; + let mut _12: *mut A; + let mut _13: <A as std::ptr::Pointee>::Metadata; + let mut _14: *mut B; + let mut _15: <B as std::ptr::Pointee>::Metadata; + + bb0: { + _4 = _1 as *const T (PtrToPtr); + _5 = PtrMetadata(_4); + _6 = _1 as *const (&A, [T]) (PtrToPtr); +- _7 = PtrMetadata(_6); ++ _7 = PtrMetadata(_1); + _8 = _2 as *const (T, B) (PtrToPtr); + _9 = PtrMetadata(_8); + _10 = _2 as *const (T, A) (PtrToPtr); +- _11 = PtrMetadata(_10); ++ _11 = PtrMetadata(_2); + _12 = _3 as *mut A (PtrToPtr); + _13 = PtrMetadata(_12); + _14 = _3 as *mut B (PtrToPtr); +- _15 = PtrMetadata(_14); ++ _15 = PtrMetadata(_3); + return; + } + } + diff --git a/tests/mir-opt/gvn.manual_slice_mut_len.GVN.panic-abort.diff b/tests/mir-opt/gvn.manual_slice_mut_len.GVN.panic-abort.diff new file mode 100644 index 00000000000..c877d8a3c0e --- /dev/null +++ b/tests/mir-opt/gvn.manual_slice_mut_len.GVN.panic-abort.diff @@ -0,0 +1,41 @@ +- // MIR for `manual_slice_mut_len` before GVN ++ // MIR for `manual_slice_mut_len` after GVN + + fn manual_slice_mut_len(_1: &mut [i32]) -> usize { + debug x => _1; + let mut _0: usize; + let _2: *mut [i32]; + let mut _4: *mut [i32]; + let mut _5: *const [i32]; + scope 1 { + debug x => _2; + let _3: *const [i32]; + scope 2 { + debug x => _3; + } + } + + bb0: { +- StorageLive(_2); ++ nop; + _2 = &raw mut (*_1); +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = _2; +- _3 = move _4 as *const [i32] (PtrToPtr); ++ _3 = _2 as *const [i32] (PtrToPtr); + StorageDead(_4); + StorageLive(_5); + _5 = _3; +- _0 = PtrMetadata(move _5); ++ _0 = PtrMetadata(_1); + StorageDead(_5); +- StorageDead(_3); +- StorageDead(_2); ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.manual_slice_mut_len.GVN.panic-unwind.diff b/tests/mir-opt/gvn.manual_slice_mut_len.GVN.panic-unwind.diff new file mode 100644 index 00000000000..c877d8a3c0e --- /dev/null +++ b/tests/mir-opt/gvn.manual_slice_mut_len.GVN.panic-unwind.diff @@ -0,0 +1,41 @@ +- // MIR for `manual_slice_mut_len` before GVN ++ // MIR for `manual_slice_mut_len` after GVN + + fn manual_slice_mut_len(_1: &mut [i32]) -> usize { + debug x => _1; + let mut _0: usize; + let _2: *mut [i32]; + let mut _4: *mut [i32]; + let mut _5: *const [i32]; + scope 1 { + debug x => _2; + let _3: *const [i32]; + scope 2 { + debug x => _3; + } + } + + bb0: { +- StorageLive(_2); ++ nop; + _2 = &raw mut (*_1); +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = _2; +- _3 = move _4 as *const [i32] (PtrToPtr); ++ _3 = _2 as *const [i32] (PtrToPtr); + StorageDead(_4); + StorageLive(_5); + _5 = _3; +- _0 = PtrMetadata(move _5); ++ _0 = PtrMetadata(_1); + StorageDead(_5); +- StorageDead(_3); +- StorageDead(_2); ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 720018f112e..8bc2550b8f5 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -7,7 +7,9 @@ #![feature(custom_mir)] #![feature(core_intrinsics)] #![feature(freeze)] +#![allow(ambiguous_wide_pointer_comparisons)] #![allow(unconditional_panic)] +#![allow(unused)] use std::intrinsics::mir::*; use std::marker::Freeze; @@ -816,6 +818,71 @@ fn casts_before_aggregate_raw_ptr(x: *const u32) -> *const [u8] { std::intrinsics::aggregate_raw_ptr(x, 4) } +fn manual_slice_mut_len(x: &mut [i32]) -> usize { + // CHECK-LABEL: fn manual_slice_mut_len + // CHECK: _0 = PtrMetadata(_1); + let x: *mut [i32] = x; + let x: *const [i32] = x; + std::intrinsics::ptr_metadata(x) +} + +// `.len()` on arrays ends up being something like this +fn array_len(x: &mut [i32; 42]) -> usize { + // CHECK-LABEL: fn array_len + // CHECK: _0 = const 42_usize; + let x: &[i32] = x; + std::intrinsics::ptr_metadata(x) +} + +#[custom_mir(dialect = "runtime")] +fn generic_cast_metadata<T, A: ?Sized, B: ?Sized>(ps: *const [T], pa: *const A, pb: *const B) { + // CHECK-LABEL: fn generic_cast_metadata + mir! { + { + // These tests check that we correctly do or don't elide casts + // when the pointee metadata do or don't match, respectively. + + // Metadata usize -> (), do not optimize. + // CHECK: [[T:_.+]] = _1 as + // CHECK-NEXT: PtrMetadata([[T]]) + let t1 = CastPtrToPtr::<_, *const T>(ps); + let m1 = PtrMetadata(t1); + + // `(&A, [T])` has `usize` metadata, same as `[T]`, yes optimize. + // CHECK: [[T:_.+]] = _1 as + // CHECK-NEXT: PtrMetadata(_1) + let t2 = CastPtrToPtr::<_, *const (&A, [T])>(ps); + let m2 = PtrMetadata(t2); + + // Tail `A` and tail `B`, do not optimize. + // CHECK: [[T:_.+]] = _2 as + // CHECK-NEXT: PtrMetadata([[T]]) + let t3 = CastPtrToPtr::<_, *const (T, B)>(pa); + let m3 = PtrMetadata(t3); + + // Both have tail `A`, yes optimize. + // CHECK: [[T:_.+]] = _2 as + // CHECK-NEXT: PtrMetadata(_2) + let t4 = CastPtrToPtr::<_, *const (T, A)>(pa); + let m4 = PtrMetadata(t4); + + // Tail `B` and tail `A`, do not optimize. + // CHECK: [[T:_.+]] = _3 as + // CHECK-NEXT: PtrMetadata([[T]]) + let t5 = CastPtrToPtr::<_, *mut A>(pb); + let m5 = PtrMetadata(t5); + + // Both have tail `B`, yes optimize. + // CHECK: [[T:_.+]] = _3 as + // CHECK-NEXT: PtrMetadata(_3) + let t6 = CastPtrToPtr::<_, *mut B>(pb); + let m6 = PtrMetadata(t6); + + Return() + } + } +} + fn main() { subexpression_elimination(2, 4, 5); wrap_unwrap(5); @@ -880,3 +947,6 @@ fn identity<T>(x: T) -> T { // EMIT_MIR gvn.meta_of_ref_to_slice.GVN.diff // EMIT_MIR gvn.slice_from_raw_parts_as_ptr.GVN.diff // EMIT_MIR gvn.casts_before_aggregate_raw_ptr.GVN.diff +// EMIT_MIR gvn.manual_slice_mut_len.GVN.diff +// EMIT_MIR gvn.array_len.GVN.diff +// EMIT_MIR gvn.generic_cast_metadata.GVN.diff diff --git a/tests/mir-opt/issue_76432.rs b/tests/mir-opt/issue_76432.rs index be5ccbd49e2..6d884063caa 100644 --- a/tests/mir-opt/issue_76432.rs +++ b/tests/mir-opt/issue_76432.rs @@ -1,11 +1,10 @@ // skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -//@ compile-flags: -Zmir-enable-passes=-NormalizeArrayLen // Check that we do not insert StorageDead at each target if StorageDead was never seen -// EMIT_MIR issue_76432.test.SimplifyComparisonIntegral.diff use std::fmt::Debug; +// EMIT_MIR issue_76432.test.SimplifyComparisonIntegral.diff fn test<T: Copy + Debug + PartialEq>(x: T) { let v: &[T] = &[x, x, x]; match v { diff --git a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff index 5242c5f6afd..6c0c7a1d438 100644 --- a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff @@ -1,5 +1,5 @@ -- // MIR for `array_bound` before NormalizeArrayLen -+ // MIR for `array_bound` after NormalizeArrayLen +- // MIR for `array_bound` before GVN ++ // MIR for `array_bound` after GVN fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { debug index => _1; @@ -24,14 +24,15 @@ _7 = &(*_2); _6 = move _7 as &[u8] (PointerCoercion(Unsize)); StorageDead(_7); -- _5 = Len((*_6)); +- _5 = PtrMetadata(move _6); + _5 = const N; goto -> bb1; } bb1: { StorageDead(_6); - _3 = Lt(move _4, move _5); +- _3 = Lt(move _4, move _5); ++ _3 = Lt(_1, move _5); switchInt(move _3) -> [0: bb4, otherwise: bb2]; } @@ -40,13 +41,17 @@ StorageDead(_4); StorageLive(_8); _8 = _1; - _9 = Len((*_2)); - _10 = Lt(_8, _9); - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind unreachable]; +- _9 = Len((*_2)); +- _10 = Lt(_8, _9); +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind unreachable]; ++ _9 = const N; ++ _10 = Lt(_1, const N); ++ assert(move _10, "index out of bounds: the length is {} but the index is {}", const N, _1) -> [success: bb3, unwind unreachable]; } bb3: { - _0 = (*_2)[_8]; +- _0 = (*_2)[_8]; ++ _0 = (*_2)[_1]; StorageDead(_8); goto -> bb5; } diff --git a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff index a9e99933b12..ed41703c873 100644 --- a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff @@ -1,5 +1,5 @@ -- // MIR for `array_bound` before NormalizeArrayLen -+ // MIR for `array_bound` after NormalizeArrayLen +- // MIR for `array_bound` before GVN ++ // MIR for `array_bound` after GVN fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { debug index => _1; @@ -24,14 +24,15 @@ _7 = &(*_2); _6 = move _7 as &[u8] (PointerCoercion(Unsize)); StorageDead(_7); -- _5 = Len((*_6)); +- _5 = PtrMetadata(move _6); + _5 = const N; goto -> bb1; } bb1: { StorageDead(_6); - _3 = Lt(move _4, move _5); +- _3 = Lt(move _4, move _5); ++ _3 = Lt(_1, move _5); switchInt(move _3) -> [0: bb4, otherwise: bb2]; } @@ -40,13 +41,17 @@ StorageDead(_4); StorageLive(_8); _8 = _1; - _9 = Len((*_2)); - _10 = Lt(_8, _9); - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind continue]; +- _9 = Len((*_2)); +- _10 = Lt(_8, _9); +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind continue]; ++ _9 = const N; ++ _10 = Lt(_1, const N); ++ assert(move _10, "index out of bounds: the length is {} but the index is {}", const N, _1) -> [success: bb3, unwind continue]; } bb3: { - _0 = (*_2)[_8]; +- _0 = (*_2)[_8]; ++ _0 = (*_2)[_1]; StorageDead(_8); goto -> bb5; } diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff index 7749ba6beca..80e8ea37f41 100644 --- a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff @@ -1,5 +1,5 @@ -- // MIR for `array_bound_mut` before NormalizeArrayLen -+ // MIR for `array_bound_mut` after NormalizeArrayLen +- // MIR for `array_bound_mut` before GVN ++ // MIR for `array_bound_mut` after GVN fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { debug index => _1; @@ -27,14 +27,15 @@ _7 = &(*_2); _6 = move _7 as &[u8] (PointerCoercion(Unsize)); StorageDead(_7); -- _5 = Len((*_6)); +- _5 = PtrMetadata(move _6); + _5 = const N; goto -> bb1; } bb1: { StorageDead(_6); - _3 = Lt(move _4, move _5); +- _3 = Lt(move _4, move _5); ++ _3 = Lt(_1, move _5); switchInt(move _3) -> [0: bb4, otherwise: bb2]; } @@ -43,13 +44,17 @@ StorageDead(_4); StorageLive(_8); _8 = _1; - _9 = Len((*_2)); - _10 = Lt(_8, _9); - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind unreachable]; +- _9 = Len((*_2)); +- _10 = Lt(_8, _9); +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind unreachable]; ++ _9 = const N; ++ _10 = Lt(_1, const N); ++ assert(move _10, "index out of bounds: the length is {} but the index is {}", const N, _1) -> [success: bb3, unwind unreachable]; } bb3: { - _0 = (*_2)[_8]; +- _0 = (*_2)[_8]; ++ _0 = (*_2)[_1]; StorageDead(_8); goto -> bb6; } @@ -59,13 +64,17 @@ StorageDead(_4); StorageLive(_11); _11 = const 0_usize; - _12 = Len((*_2)); - _13 = Lt(_11, _12); - assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb5, unwind unreachable]; +- _12 = Len((*_2)); +- _13 = Lt(_11, _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb5, unwind unreachable]; ++ _12 = const N; ++ _13 = Lt(const 0_usize, const N); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind unreachable]; } bb5: { - (*_2)[_11] = const 42_u8; +- (*_2)[_11] = const 42_u8; ++ (*_2)[0 of 1] = const 42_u8; StorageDead(_11); _0 = const 42_u8; goto -> bb6; diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff index fcc2c1653dc..6e67a6c17ef 100644 --- a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff @@ -1,5 +1,5 @@ -- // MIR for `array_bound_mut` before NormalizeArrayLen -+ // MIR for `array_bound_mut` after NormalizeArrayLen +- // MIR for `array_bound_mut` before GVN ++ // MIR for `array_bound_mut` after GVN fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { debug index => _1; @@ -27,14 +27,15 @@ _7 = &(*_2); _6 = move _7 as &[u8] (PointerCoercion(Unsize)); StorageDead(_7); -- _5 = Len((*_6)); +- _5 = PtrMetadata(move _6); + _5 = const N; goto -> bb1; } bb1: { StorageDead(_6); - _3 = Lt(move _4, move _5); +- _3 = Lt(move _4, move _5); ++ _3 = Lt(_1, move _5); switchInt(move _3) -> [0: bb4, otherwise: bb2]; } @@ -43,13 +44,17 @@ StorageDead(_4); StorageLive(_8); _8 = _1; - _9 = Len((*_2)); - _10 = Lt(_8, _9); - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind continue]; +- _9 = Len((*_2)); +- _10 = Lt(_8, _9); +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind continue]; ++ _9 = const N; ++ _10 = Lt(_1, const N); ++ assert(move _10, "index out of bounds: the length is {} but the index is {}", const N, _1) -> [success: bb3, unwind continue]; } bb3: { - _0 = (*_2)[_8]; +- _0 = (*_2)[_8]; ++ _0 = (*_2)[_1]; StorageDead(_8); goto -> bb6; } @@ -59,13 +64,17 @@ StorageDead(_4); StorageLive(_11); _11 = const 0_usize; - _12 = Len((*_2)); - _13 = Lt(_11, _12); - assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb5, unwind continue]; +- _12 = Len((*_2)); +- _13 = Lt(_11, _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb5, unwind continue]; ++ _12 = const N; ++ _13 = Lt(const 0_usize, const N); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind continue]; } bb5: { - (*_2)[_11] = const 42_u8; +- (*_2)[_11] = const 42_u8; ++ (*_2)[0 of 1] = const 42_u8; StorageDead(_11); _0 = const 42_u8; goto -> bb6; diff --git a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len.GVN.panic-abort.diff index 1bdc62183c3..9c1b9a708c5 100644 --- a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_len.GVN.panic-abort.diff @@ -1,5 +1,5 @@ -- // MIR for `array_len` before NormalizeArrayLen -+ // MIR for `array_len` after NormalizeArrayLen +- // MIR for `array_len` before GVN ++ // MIR for `array_len` after GVN fn array_len(_1: &[u8; N]) -> usize { debug arr => _1; @@ -13,7 +13,7 @@ _3 = &(*_1); _2 = move _3 as &[u8] (PointerCoercion(Unsize)); StorageDead(_3); -- _0 = Len((*_2)); +- _0 = PtrMetadata(move _2); + _0 = const N; goto -> bb1; } diff --git a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len.GVN.panic-unwind.diff index 1bdc62183c3..9c1b9a708c5 100644 --- a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_len.GVN.panic-unwind.diff @@ -1,5 +1,5 @@ -- // MIR for `array_len` before NormalizeArrayLen -+ // MIR for `array_len` after NormalizeArrayLen +- // MIR for `array_len` before GVN ++ // MIR for `array_len` after GVN fn array_len(_1: &[u8; N]) -> usize { debug arr => _1; @@ -13,7 +13,7 @@ _3 = &(*_1); _2 = move _3 as &[u8] (PointerCoercion(Unsize)); StorageDead(_3); -- _0 = Len((*_2)); +- _0 = PtrMetadata(move _2); + _0 = const N; goto -> bb1; } diff --git a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-abort.diff index 9862b2fad8e..97fa503ac2e 100644 --- a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-abort.diff @@ -1,5 +1,5 @@ -- // MIR for `array_len_by_value` before NormalizeArrayLen -+ // MIR for `array_len_by_value` after NormalizeArrayLen +- // MIR for `array_len_by_value` before GVN ++ // MIR for `array_len_by_value` after GVN fn array_len_by_value(_1: [u8; N]) -> usize { debug arr => _1; @@ -13,7 +13,7 @@ _3 = &_1; _2 = move _3 as &[u8] (PointerCoercion(Unsize)); StorageDead(_3); -- _0 = Len((*_2)); +- _0 = PtrMetadata(move _2); + _0 = const N; goto -> bb1; } diff --git a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-unwind.diff index 9862b2fad8e..97fa503ac2e 100644 --- a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-unwind.diff @@ -1,5 +1,5 @@ -- // MIR for `array_len_by_value` before NormalizeArrayLen -+ // MIR for `array_len_by_value` after NormalizeArrayLen +- // MIR for `array_len_by_value` before GVN ++ // MIR for `array_len_by_value` after GVN fn array_len_by_value(_1: [u8; N]) -> usize { debug arr => _1; @@ -13,7 +13,7 @@ _3 = &_1; _2 = move _3 as &[u8] (PointerCoercion(Unsize)); StorageDead(_3); -- _0 = Len((*_2)); +- _0 = PtrMetadata(move _2); + _0 = const N; goto -> bb1; } diff --git a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-abort.diff index 633a344a2ed..b5e8b66813a 100644 --- a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-abort.diff @@ -1,5 +1,5 @@ -- // MIR for `array_len_raw` before NormalizeArrayLen -+ // MIR for `array_len_raw` after NormalizeArrayLen +- // MIR for `array_len_raw` before GVN ++ // MIR for `array_len_raw` after GVN fn array_len_raw(_1: [u8; N]) -> usize { debug arr => _1; @@ -18,7 +18,8 @@ } bb0: { - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); StorageLive(_4); _4 = &_1; @@ -32,7 +33,7 @@ StorageLive(_7); _7 = &(*_5); _6 = &(*_7); -- _0 = Len((*_6)); +- _0 = PtrMetadata(move _6); + _0 = const N; goto -> bb1; } @@ -40,7 +41,8 @@ bb1: { StorageDead(_6); StorageDead(_5); - StorageDead(_2); +- StorageDead(_2); ++ nop; StorageDead(_7); return; } diff --git a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-unwind.diff index 633a344a2ed..b5e8b66813a 100644 --- a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-unwind.diff @@ -1,5 +1,5 @@ -- // MIR for `array_len_raw` before NormalizeArrayLen -+ // MIR for `array_len_raw` after NormalizeArrayLen +- // MIR for `array_len_raw` before GVN ++ // MIR for `array_len_raw` after GVN fn array_len_raw(_1: [u8; N]) -> usize { debug arr => _1; @@ -18,7 +18,8 @@ } bb0: { - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); StorageLive(_4); _4 = &_1; @@ -32,7 +33,7 @@ StorageLive(_7); _7 = &(*_5); _6 = &(*_7); -- _0 = Len((*_6)); +- _0 = PtrMetadata(move _6); + _0 = const N; goto -> bb1; } @@ -40,7 +41,8 @@ bb1: { StorageDead(_6); StorageDead(_5); - StorageDead(_2); +- StorageDead(_2); ++ nop; StorageDead(_7); return; } diff --git a/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-abort.diff index ecba06a2e4d..0299c6acd80 100644 --- a/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-abort.diff @@ -1,5 +1,5 @@ -- // MIR for `array_len_reborrow` before NormalizeArrayLen -+ // MIR for `array_len_reborrow` after NormalizeArrayLen +- // MIR for `array_len_reborrow` before GVN ++ // MIR for `array_len_reborrow` after GVN fn array_len_reborrow(_1: [u8; N]) -> usize { debug arr => _1; @@ -17,7 +17,8 @@ } bb0: { - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); StorageLive(_4); _4 = &mut _1; @@ -29,7 +30,7 @@ _5 = &(*_2); StorageLive(_6); _6 = &(*_5); -- _0 = Len((*_6)); +- _0 = PtrMetadata(move _6); + _0 = const N; goto -> bb1; } @@ -37,7 +38,8 @@ bb1: { StorageDead(_6); StorageDead(_5); - StorageDead(_2); +- StorageDead(_2); ++ nop; return; } } diff --git a/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-unwind.diff index ecba06a2e4d..0299c6acd80 100644 --- a/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-unwind.diff @@ -1,5 +1,5 @@ -- // MIR for `array_len_reborrow` before NormalizeArrayLen -+ // MIR for `array_len_reborrow` after NormalizeArrayLen +- // MIR for `array_len_reborrow` before GVN ++ // MIR for `array_len_reborrow` after GVN fn array_len_reborrow(_1: [u8; N]) -> usize { debug arr => _1; @@ -17,7 +17,8 @@ } bb0: { - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); StorageLive(_4); _4 = &mut _1; @@ -29,7 +30,7 @@ _5 = &(*_2); StorageLive(_6); _6 = &(*_5); -- _0 = Len((*_6)); +- _0 = PtrMetadata(move _6); + _0 = const N; goto -> bb1; } @@ -37,7 +38,8 @@ bb1: { StorageDead(_6); StorageDead(_5); - StorageDead(_2); +- StorageDead(_2); ++ nop; return; } } diff --git a/tests/mir-opt/lower_array_len.rs b/tests/mir-opt/lower_array_len.rs index 62fc9ef67d6..caa598d067a 100644 --- a/tests/mir-opt/lower_array_len.rs +++ b/tests/mir-opt/lower_array_len.rs @@ -1,20 +1,20 @@ // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -//@ test-mir-pass: NormalizeArrayLen +//@ test-mir-pass: GVN //@ compile-flags: -Zmir-enable-passes=+LowerSliceLenCalls -// EMIT_MIR lower_array_len.array_bound.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_bound.GVN.diff pub fn array_bound<const N: usize>(index: usize, slice: &[u8; N]) -> u8 { // CHECK-LABEL: fn array_bound( // CHECK: [[len:_.*]] = const N; - // CHECK: Lt(move {{_.*}}, move [[len]]); + // CHECK: Lt(_1, move [[len]]); if index < slice.len() { slice[index] } else { 42 } } -// EMIT_MIR lower_array_len.array_bound_mut.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_bound_mut.GVN.diff pub fn array_bound_mut<const N: usize>(index: usize, slice: &mut [u8; N]) -> u8 { // CHECK-LABEL: fn array_bound_mut( // CHECK: [[len:_.*]] = const N; - // CHECK: Lt(move {{_.*}}, move [[len]]); + // CHECK: Lt(_1, move [[len]]); if index < slice.len() { slice[index] } else { @@ -24,21 +24,21 @@ pub fn array_bound_mut<const N: usize>(index: usize, slice: &mut [u8; N]) -> u8 } } -// EMIT_MIR lower_array_len.array_len.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_len.GVN.diff pub fn array_len<const N: usize>(arr: &[u8; N]) -> usize { // CHECK-LABEL: fn array_len( // CHECK: _0 = const N; arr.len() } -// EMIT_MIR lower_array_len.array_len_by_value.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_len_by_value.GVN.diff pub fn array_len_by_value<const N: usize>(arr: [u8; N]) -> usize { // CHECK-LABEL: fn array_len_by_value( // CHECK: _0 = const N; arr.len() } -// EMIT_MIR lower_array_len.array_len_reborrow.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_len_reborrow.GVN.diff pub fn array_len_reborrow<const N: usize>(mut arr: [u8; N]) -> usize { // CHECK-LABEL: fn array_len_reborrow( // CHECK: _0 = const N; @@ -47,7 +47,7 @@ pub fn array_len_reborrow<const N: usize>(mut arr: [u8; N]) -> usize { arr.len() } -// EMIT_MIR lower_array_len.array_len_raw.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_len_raw.GVN.diff pub fn array_len_raw<const N: usize>(arr: [u8; N]) -> usize { // CHECK-LABEL: fn array_len_raw( // CHECK: _0 = const N; diff --git a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff index 7f752ca0f5a..a212ee67881 100644 --- a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff +++ b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff @@ -21,7 +21,7 @@ StorageLive(_6); _6 = &(*_2); - _5 = core::slice::<impl [u8]>::len(move _6) -> [return: bb1, unwind unreachable]; -+ _5 = Len((*_6)); ++ _5 = PtrMetadata(move _6); + goto -> bb1; } diff --git a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff index d73b563a0e5..38ec8a5b0c7 100644 --- a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff +++ b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff @@ -21,7 +21,7 @@ StorageLive(_6); _6 = &(*_2); - _5 = core::slice::<impl [u8]>::len(move _6) -> [return: bb1, unwind continue]; -+ _5 = Len((*_6)); ++ _5 = PtrMetadata(move _6); + goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir index cfb9134a1f1..e31a8cb6937 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir @@ -4,12 +4,87 @@ fn step_forward(_1: u16, _2: usize) -> u16 { debug x => _1; debug n => _2; let mut _0: u16; + scope 1 (inlined <u16 as Step>::forward) { + let mut _8: u16; + scope 2 { + } + scope 3 (inlined <u16 as Step>::forward_checked) { + scope 4 { + scope 6 (inlined core::num::<impl u16>::checked_add) { + let mut _7: bool; + scope 7 { + } + scope 8 (inlined core::num::<impl u16>::overflowing_add) { + let mut _5: (u16, bool); + let _6: bool; + scope 9 { + } + } + } + } + scope 5 (inlined convert::num::ptr_try_from_impls::<impl TryFrom<usize> for u16>::try_from) { + let mut _3: bool; + let mut _4: u16; + } + } + scope 10 (inlined Option::<u16>::is_none) { + scope 11 (inlined Option::<u16>::is_some) { + } + } + scope 12 (inlined core::num::<impl u16>::wrapping_add) { + } + } bb0: { - _0 = <u16 as Step>::forward(move _1, move _2) -> [return: bb1, unwind unreachable]; + StorageLive(_4); + StorageLive(_3); + _3 = Gt(_2, const 65535_usize); + switchInt(move _3) -> [0: bb1, otherwise: bb5]; } bb1: { + _4 = _2 as u16 (IntToInt); + StorageDead(_3); + StorageLive(_6); + StorageLive(_5); + _5 = AddWithOverflow(_1, _4); + _6 = (_5.1: bool); + StorageDead(_5); + StorageLive(_7); + _7 = unlikely(move _6) -> [return: bb2, unwind unreachable]; + } + + bb2: { + switchInt(move _7) -> [0: bb3, otherwise: bb4]; + } + + bb3: { + StorageDead(_7); + StorageDead(_6); + goto -> bb7; + } + + bb4: { + StorageDead(_7); + StorageDead(_6); + goto -> bb6; + } + + bb5: { + StorageDead(_3); + goto -> bb6; + } + + bb6: { + assert(!const true, "attempt to compute `{} + {}`, which would overflow", const core::num::<impl u16>::MAX, const 1_u16) -> [success: bb7, unwind unreachable]; + } + + bb7: { + StorageLive(_8); + _8 = _2 as u16 (IntToInt); + _0 = Add(_1, _8); + StorageDead(_8); + StorageDead(_4); return; } } diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir index cacc1224aba..8cc9be27e21 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir @@ -4,12 +4,87 @@ fn step_forward(_1: u16, _2: usize) -> u16 { debug x => _1; debug n => _2; let mut _0: u16; + scope 1 (inlined <u16 as Step>::forward) { + let mut _8: u16; + scope 2 { + } + scope 3 (inlined <u16 as Step>::forward_checked) { + scope 4 { + scope 6 (inlined core::num::<impl u16>::checked_add) { + let mut _7: bool; + scope 7 { + } + scope 8 (inlined core::num::<impl u16>::overflowing_add) { + let mut _5: (u16, bool); + let _6: bool; + scope 9 { + } + } + } + } + scope 5 (inlined convert::num::ptr_try_from_impls::<impl TryFrom<usize> for u16>::try_from) { + let mut _3: bool; + let mut _4: u16; + } + } + scope 10 (inlined Option::<u16>::is_none) { + scope 11 (inlined Option::<u16>::is_some) { + } + } + scope 12 (inlined core::num::<impl u16>::wrapping_add) { + } + } bb0: { - _0 = <u16 as Step>::forward(move _1, move _2) -> [return: bb1, unwind continue]; + StorageLive(_4); + StorageLive(_3); + _3 = Gt(_2, const 65535_usize); + switchInt(move _3) -> [0: bb1, otherwise: bb5]; } bb1: { + _4 = _2 as u16 (IntToInt); + StorageDead(_3); + StorageLive(_6); + StorageLive(_5); + _5 = AddWithOverflow(_1, _4); + _6 = (_5.1: bool); + StorageDead(_5); + StorageLive(_7); + _7 = unlikely(move _6) -> [return: bb2, unwind unreachable]; + } + + bb2: { + switchInt(move _7) -> [0: bb3, otherwise: bb4]; + } + + bb3: { + StorageDead(_7); + StorageDead(_6); + goto -> bb7; + } + + bb4: { + StorageDead(_7); + StorageDead(_6); + goto -> bb6; + } + + bb5: { + StorageDead(_3); + goto -> bb6; + } + + bb6: { + assert(!const true, "attempt to compute `{} + {}`, which would overflow", const core::num::<impl u16>::MAX, const 1_u16) -> [success: bb7, unwind continue]; + } + + bb7: { + StorageLive(_8); + _8 = _2 as u16 (IntToInt); + _0 = Add(_1, _8); + StorageDead(_8); + StorageDead(_4); return; } } diff --git a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir index b800a1be22b..51d41e9ff05 100644 --- a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir @@ -7,14 +7,30 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () { let mut _3: std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>; let mut _4: std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>; let mut _5: &mut std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>; - let mut _6: std::option::Option<U>; - let mut _7: isize; - let _9: (); + let mut _13: std::option::Option<U>; + let _15: (); scope 1 { debug iter => _4; - let _8: U; + let _14: U; scope 2 { - debug x => _8; + debug x => _14; + } + scope 4 (inlined <Map<impl Iterator<Item = T>, impl Fn(T) -> U> as Iterator>::next) { + debug self => _5; + let mut _6: &mut impl Iterator<Item = T>; + let mut _7: std::option::Option<T>; + let mut _8: &mut impl Fn(T) -> U; + scope 5 (inlined Option::<T>::map::<U, &mut impl Fn(T) -> U>) { + debug self => _7; + debug f => _8; + let mut _9: isize; + let _10: T; + let mut _11: (T,); + let mut _12: U; + scope 6 { + debug x => _10; + } + } } } scope 3 (inlined <Map<impl Iterator<Item = T>, impl Fn(T) -> U> as IntoIterator>::into_iter) { @@ -32,20 +48,30 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () { } bb2: { - StorageLive(_6); - StorageLive(_5); + StorageLive(_13); _5 = &mut _4; - _6 = <Map<impl Iterator<Item = T>, impl Fn(T) -> U> as Iterator>::next(move _5) -> [return: bb3, unwind: bb9]; + StorageLive(_8); + StorageLive(_7); + StorageLive(_6); + _6 = &mut (_4.0: impl Iterator<Item = T>); + _7 = <impl Iterator<Item = T> as Iterator>::next(move _6) -> [return: bb3, unwind: bb10]; } bb3: { - StorageDead(_5); - _7 = discriminant(_6); - switchInt(move _7) -> [0: bb4, 1: bb6, otherwise: bb8]; + StorageDead(_6); + _8 = &mut (_4.1: impl Fn(T) -> U); + StorageLive(_9); + StorageLive(_10); + _9 = discriminant(_7); + switchInt(move _9) -> [0: bb4, 1: bb6, otherwise: bb9]; } bb4: { - StorageDead(_6); + StorageDead(_10); + StorageDead(_9); + StorageDead(_7); + StorageDead(_8); + StorageDead(_13); drop(_4) -> [return: bb5, unwind continue]; } @@ -55,24 +81,39 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () { } bb6: { - _8 = move ((_6 as Some).0: U); - _9 = opaque::<U>(move _8) -> [return: bb7, unwind: bb9]; + _10 = move ((_7 as Some).0: T); + StorageLive(_12); + StorageLive(_11); + _11 = (_10,); + _12 = <&mut impl Fn(T) -> U as FnOnce<(T,)>>::call_once(move _8, move _11) -> [return: bb7, unwind: bb10]; } bb7: { - StorageDead(_6); - goto -> bb2; + StorageDead(_11); + _13 = Option::<U>::Some(move _12); + StorageDead(_12); + StorageDead(_10); + StorageDead(_9); + StorageDead(_7); + StorageDead(_8); + _14 = move ((_13 as Some).0: U); + _15 = opaque::<U>(move _14) -> [return: bb8, unwind: bb10]; } bb8: { - unreachable; + StorageDead(_13); + goto -> bb2; } - bb9 (cleanup): { - drop(_4) -> [return: bb10, unwind terminate(cleanup)]; + bb9: { + unreachable; } bb10 (cleanup): { + drop(_4) -> [return: bb11, unwind terminate(cleanup)]; + } + + bb11 (cleanup): { resume; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.rs b/tests/mir-opt/pre-codegen/slice_index.rs index 886e57a3380..6ddc4ad0220 100644 --- a/tests/mir-opt/pre-codegen/slice_index.rs +++ b/tests/mir-opt/pre-codegen/slice_index.rs @@ -19,7 +19,7 @@ pub fn slice_index_usize(slice: &[u32], index: usize) -> u32 { // EMIT_MIR slice_index.slice_get_mut_usize.PreCodegen.after.mir pub fn slice_get_mut_usize(slice: &mut [u32], index: usize) -> Option<&mut u32> { // CHECK-LABEL: slice_get_mut_usize - // CHECK: [[LEN:_[0-9]+]] = Len((*_1)) + // CHECK: [[LEN:_[0-9]+]] = PtrMetadata(_1) // CHECK: Lt(_2, move [[LEN]]) // CHECK-NOT: precondition_check slice.get_mut(index) diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir index f2ef2b0cc3c..d7f09fafeeb 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir @@ -23,7 +23,7 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { StorageLive(_7); StorageLive(_4); StorageLive(_3); - _3 = Len((*_1)); + _3 = PtrMetadata(_1); _4 = Lt(_2, move _3); switchInt(move _4) -> [0: bb1, otherwise: bb2]; } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir index f2ef2b0cc3c..d7f09fafeeb 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir @@ -23,7 +23,7 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { StorageLive(_7); StorageLive(_4); StorageLive(_3); - _3 = Len((*_1)); + _3 = PtrMetadata(_1); _4 = Lt(_2, move _3); switchInt(move _4) -> [0: bb1, otherwise: bb2]; } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 41cca811922..2f13cfa4dab 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -8,25 +8,24 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> let mut _4: usize; scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) { let mut _5: *mut [u32]; - let mut _12: *mut [u32]; + let mut _11: *mut [u32]; scope 2 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) { - let mut _7: usize; - let _8: (); - let _9: usize; + let mut _6: usize; + let _7: (); + let _8: usize; scope 3 { scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) { - let _11: *mut u32; + let _10: *mut u32; scope 7 { } scope 8 (inlined core::slice::index::get_mut_noubcheck::<u32>) { - let _10: *mut u32; + let _9: *mut u32; scope 9 { } } } } scope 4 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) { - let mut _6: *const [u32]; scope 5 (inlined std::ptr::metadata::<[u32]>) { } } @@ -38,28 +37,25 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> _4 = move (_2.1: usize); StorageLive(_5); _5 = &raw mut (*_1); - StorageLive(_9); - StorageLive(_7); + StorageLive(_8); StorageLive(_6); - _6 = _5 as *const [u32] (PtrToPtr); - _7 = PtrMetadata(_6); - StorageDead(_6); - _8 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(_3, _4, move _7) -> [return: bb1, unwind unreachable]; + _6 = PtrMetadata(_1); + _7 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(_3, _4, move _6) -> [return: bb1, unwind unreachable]; } bb1: { - StorageDead(_7); - _9 = SubUnchecked(_4, _3); - StorageLive(_11); + StorageDead(_6); + _8 = SubUnchecked(_4, _3); StorageLive(_10); - _10 = _5 as *mut u32 (PtrToPtr); - _11 = Offset(_10, _3); - StorageDead(_10); - _12 = *mut [u32] from (_11, _9); - StorageDead(_11); + StorageLive(_9); + _9 = _5 as *mut u32 (PtrToPtr); + _10 = Offset(_9, _3); StorageDead(_9); + _11 = *mut [u32] from (_10, _8); + StorageDead(_10); + StorageDead(_8); StorageDead(_5); - _0 = &mut (*_12); + _0 = &mut (*_11); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 41cca811922..2f13cfa4dab 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -8,25 +8,24 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> let mut _4: usize; scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) { let mut _5: *mut [u32]; - let mut _12: *mut [u32]; + let mut _11: *mut [u32]; scope 2 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) { - let mut _7: usize; - let _8: (); - let _9: usize; + let mut _6: usize; + let _7: (); + let _8: usize; scope 3 { scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::<u32>) { - let _11: *mut u32; + let _10: *mut u32; scope 7 { } scope 8 (inlined core::slice::index::get_mut_noubcheck::<u32>) { - let _10: *mut u32; + let _9: *mut u32; scope 9 { } } } } scope 4 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) { - let mut _6: *const [u32]; scope 5 (inlined std::ptr::metadata::<[u32]>) { } } @@ -38,28 +37,25 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> _4 = move (_2.1: usize); StorageLive(_5); _5 = &raw mut (*_1); - StorageLive(_9); - StorageLive(_7); + StorageLive(_8); StorageLive(_6); - _6 = _5 as *const [u32] (PtrToPtr); - _7 = PtrMetadata(_6); - StorageDead(_6); - _8 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(_3, _4, move _7) -> [return: bb1, unwind unreachable]; + _6 = PtrMetadata(_1); + _7 = <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(_3, _4, move _6) -> [return: bb1, unwind unreachable]; } bb1: { - StorageDead(_7); - _9 = SubUnchecked(_4, _3); - StorageLive(_11); + StorageDead(_6); + _8 = SubUnchecked(_4, _3); StorageLive(_10); - _10 = _5 as *mut u32 (PtrToPtr); - _11 = Offset(_10, _3); - StorageDead(_10); - _12 = *mut [u32] from (_11, _9); - StorageDead(_11); + StorageLive(_9); + _9 = _5 as *mut u32 (PtrToPtr); + _10 = Offset(_9, _3); StorageDead(_9); + _11 = *mut [u32] from (_10, _8); + StorageDead(_10); + StorageDead(_8); StorageDead(_5); - _0 = &mut (*_12); + _0 = &mut (*_11); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index 8eb102e68f3..953e7550479 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -7,19 +7,44 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { let mut _11: std::slice::Iter<'_, T>; let mut _12: std::iter::Enumerate<std::slice::Iter<'_, T>>; let mut _13: std::iter::Enumerate<std::slice::Iter<'_, T>>; - let mut _14: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>; - let mut _15: std::option::Option<(usize, &T)>; - let mut _16: isize; - let mut _19: &impl Fn(usize, &T); - let mut _20: (usize, &T); - let _21: (); + let mut _21: std::option::Option<(usize, &T)>; + let mut _24: &impl Fn(usize, &T); + let mut _25: (usize, &T); + let _26: (); scope 1 { debug iter => _13; - let _17: usize; - let _18: &T; + let _22: usize; + let _23: &T; scope 2 { - debug i => _17; - debug x => _18; + debug i => _22; + debug x => _23; + } + scope 17 (inlined <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next) { + let mut _14: &mut std::slice::Iter<'_, T>; + let mut _15: std::option::Option<&T>; + let mut _19: (usize, bool); + let mut _20: (usize, &T); + scope 18 { + let _18: usize; + scope 23 { + } + } + scope 19 { + scope 20 { + scope 26 (inlined <Option<(usize, &T)> as FromResidual>::from_residual) { + } + } + } + scope 21 { + scope 22 { + } + } + scope 24 (inlined <Option<&T> as Try>::branch) { + let mut _16: isize; + let _17: &T; + scope 25 { + } + } } } scope 3 (inlined core::slice::<impl [T]>::iter) { @@ -65,7 +90,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageLive(_6); StorageLive(_4); StorageLive(_5); - _3 = Len((*_1)); + _3 = PtrMetadata(_1); _4 = &raw const (*_1); _5 = _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: _5 }; @@ -107,20 +132,28 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb4: { + StorageLive(_21); + StorageLive(_18); + StorageLive(_19); StorageLive(_15); StorageLive(_14); - _14 = &mut _13; - _15 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _14) -> [return: bb5, unwind unreachable]; + _14 = &mut (_13.0: std::slice::Iter<'_, T>); + _15 = <std::slice::Iter<'_, T> as Iterator>::next(move _14) -> [return: bb5, unwind unreachable]; } bb5: { StorageDead(_14); + StorageLive(_16); _16 = discriminant(_15); - switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; + switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb11]; } bb6: { + StorageDead(_16); StorageDead(_15); + StorageDead(_19); + StorageDead(_18); + StorageDead(_21); StorageDead(_13); drop(_2) -> [return: bb7, unwind unreachable]; } @@ -130,23 +163,39 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb8: { - _17 = (((_15 as Some).0: (usize, &T)).0: usize); - _18 = (((_15 as Some).0: (usize, &T)).1: &T); - StorageLive(_19); - _19 = &_2; - StorageLive(_20); - _20 = (_17, _18); - _21 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _19, move _20) -> [return: bb9, unwind unreachable]; + _17 = move ((_15 as Some).0: &T); + StorageDead(_16); + StorageDead(_15); + _18 = (_13.1: usize); + _19 = AddWithOverflow((_13.1: usize), const 1_usize); + assert(!move (_19.1: bool), "attempt to compute `{} + {}`, which would overflow", (_13.1: usize), const 1_usize) -> [success: bb9, unwind unreachable]; } bb9: { + (_13.1: usize) = move (_19.0: usize); + StorageLive(_20); + _20 = (_18, _17); + _21 = Option::<(usize, &T)>::Some(move _20); StorageDead(_20); StorageDead(_19); - StorageDead(_15); - goto -> bb4; + StorageDead(_18); + _22 = (((_21 as Some).0: (usize, &T)).0: usize); + _23 = (((_21 as Some).0: (usize, &T)).1: &T); + StorageLive(_24); + _24 = &_2; + StorageLive(_25); + _25 = (_22, _23); + _26 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _24, move _25) -> [return: bb10, unwind unreachable]; } bb10: { + StorageDead(_25); + StorageDead(_24); + StorageDead(_21); + goto -> bb4; + } + + bb11: { unreachable; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index f805967d64f..d5fdb2e08cc 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -65,7 +65,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageLive(_6); StorageLive(_4); StorageLive(_5); - _3 = Len((*_1)); + _3 = PtrMetadata(_1); _4 = &raw const (*_1); _5 = _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: _5 }; diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index 6ae64200f4e..cc2beac06f2 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -57,7 +57,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageLive(_6); StorageLive(_4); StorageLive(_5); - _3 = Len((*_1)); + _3 = PtrMetadata(_1); _4 = &raw const (*_1); _5 = _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: _5 }; diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index ac72329fcd6..d66edb28570 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -57,7 +57,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageLive(_6); StorageLive(_4); StorageLive(_5); - _3 = Len((*_1)); + _3 = PtrMetadata(_1); _4 = &raw const (*_1); _5 = _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: _5 }; diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir index dbe6f39548c..cea2fcbcdc0 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir @@ -40,7 +40,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb0: { - _3 = Len((*_1)); + _3 = PtrMetadata(_1); StorageLive(_4); _4 = const 0_usize; goto -> bb1; diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir index 5b6441cfb3b..bd658a770ea 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir @@ -40,7 +40,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb0: { - _3 = Len((*_1)); + _3 = PtrMetadata(_1); StorageLive(_4); _4 = const 0_usize; goto -> bb1; diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index 8008336e268..fbb887fe76a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -65,7 +65,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageLive(_6); StorageLive(_4); StorageLive(_5); - _3 = Len((*_1)); + _3 = PtrMetadata(_1); _4 = &raw const (*_1); _5 = _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: _5 }; diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index 47253bf7a0d..db9409f72ab 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -65,7 +65,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageLive(_6); StorageLive(_4); StorageLive(_5); - _3 = Len((*_1)); + _3 = PtrMetadata(_1); _4 = &raw const (*_1); _5 = _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: _5 }; diff --git a/tests/run-make/branch-protection-check-IBT/Makefile b/tests/run-make/branch-protection-check-IBT/Makefile index cabe951e1c5..ee0e034627f 100644 --- a/tests/run-make/branch-protection-check-IBT/Makefile +++ b/tests/run-make/branch-protection-check-IBT/Makefile @@ -7,6 +7,12 @@ include ../tools.mk # only-x86_64 +# ignore-test +# FIXME(jieyouxu): This test never runs because the `ifeq` check on line 17 +# compares `x86` to `x86_64`, which always evaluates to false. +# When the test does run, the compilation does not include `.note.gnu.property`. +# See https://github.com/rust-lang/rust/pull/126720 for more information. + all: ifeq ($(filter x86,$(LLVM_COMPONENTS)),x86_64) $(RUSTC) --target x86_64-unknown-linux-gnu -Z cf-protection=branch -L$(TMPDIR) -C link-args='-nostartfiles' -C save-temps ./main.rs -o $(TMPDIR)/rsmain diff --git a/tests/run-make/branch-protection-check-IBT/_rmake.rs b/tests/run-make/branch-protection-check-IBT/_rmake.rs new file mode 100644 index 00000000000..d66ecf9c005 --- /dev/null +++ b/tests/run-make/branch-protection-check-IBT/_rmake.rs @@ -0,0 +1,31 @@ +// Check for GNU Property Note + +// How to run this +// python3 x.py test --target x86_64-unknown-linux-gnu tests/run-make/branch-protection-check-IBT/ + +//@ only-x86_64 + +//@ ignore-test +// FIXME(jieyouxu): see the FIXME in the Makefile + +use run_make_support::llvm_readobj; +use run_make_support::rustc; +use run_make_support::{cwd, env_var}; + +fn main() { + let llvm_components = env_var("LLVM_COMPONENTS"); + if !format!(" {llvm_components} ").contains(" x86 ") { + return; + } + + rustc() + .input("main.rs") + .target("x86_64-unknown-linux-gnu") + .arg("-Zcf-protection=branch") + .arg(format!("-L{}", cwd().display())) + .arg("-Clink-args=-nostartfiles") + .arg("-Csave-temps") + .run(); + + llvm_readobj().arg("-nW").input("main").run().assert_stdout_contains(".note.gnu.property"); +} diff --git a/tests/run-make/comment-section/Makefile b/tests/run-make/comment-section/Makefile deleted file mode 100644 index d0b98176ffe..00000000000 --- a/tests/run-make/comment-section/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# Both GCC and Clang write by default a `.comment` section with compiler information. Rustc received a similar .comment section, so this tests checks that this section properly appears. -# See https://github.com/rust-lang/rust/commit/74b8d324eb77a8f337b35dc68ac91b0c2c06debc - -include ../tools.mk - -# only-linux - -all: - echo 'fn main(){}' | $(RUSTC) - --emit=link,obj -Csave-temps --target=$(TARGET) - - # Check linked output has a `.comment` section with the expected content. - readelf -p '.comment' $(TMPDIR)/rust_out | $(CGREP) -F 'rustc version 1.' - - # Check all object files (including temporary outputs) have a `.comment` - # section with the expected content. - set -e; for f in $(TMPDIR)/*.o; do \ - readelf -p '.comment' $$f | $(CGREP) -F 'rustc version 1.'; \ - done diff --git a/tests/run-make/comment-section/rmake.rs b/tests/run-make/comment-section/rmake.rs new file mode 100644 index 00000000000..41df04da7a5 --- /dev/null +++ b/tests/run-make/comment-section/rmake.rs @@ -0,0 +1,47 @@ +// Both GCC and Clang write by default a `.comment` section with compiler information. +// Rustc received a similar .comment section, so this tests checks that this section +// properly appears. +// See https://github.com/rust-lang/rust/commit/74b8d324eb77a8f337b35dc68ac91b0c2c06debc + +//@ only-linux +// FIXME(jieyouxu): check cross-compile setup +//@ ignore-cross-compile + +use std::path::PathBuf; + +use run_make_support::llvm_readobj; +use run_make_support::rustc; +use run_make_support::{cwd, env_var, read_dir, run_in_tmpdir}; + +fn main() { + let target = env_var("TARGET"); + + rustc() + .arg("-") + .stdin("fn main() {}") + .emit("link,obj") + .arg("-Csave-temps") + .target(&target) + .run(); + + // Check linked output has a `.comment` section with the expected content. + llvm_readobj() + .section(".comment") + .input("rust_out") + .run() + .assert_stdout_contains("rustc version 1."); + + // Check all object files (including temporary outputs) have a `.comment` + // section with the expected content. + read_dir(cwd(), |f| { + if !f.extension().is_some_and(|ext| ext == "o") { + return; + } + + llvm_readobj() + .section(".comment") + .input(&f) + .run() + .assert_stdout_contains("rustc version 1."); + }); +} diff --git a/tests/run-make/compressed-debuginfo/Makefile b/tests/run-make/compressed-debuginfo/Makefile deleted file mode 100644 index d2f24dde00d..00000000000 --- a/tests/run-make/compressed-debuginfo/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# only-linux -# -# This tests debuginfo-compression. - -all: zlib zstandard - -zlib: - test "`$(RUSTC) --crate-name=foo --crate-type=lib --emit=obj -C debuginfo=full -Z debuginfo-compression=zlib foo.rs 2>&1 | sed 's/.*unknown.*zlib.*/missing/' | head -n 1`" = missing || readelf -t $(TMPDIR)/foo.o | grep -q ZLIB - -zstandard: - test "`$(RUSTC) --crate-name=foo --crate-type=lib --emit=obj -C debuginfo=full -Z debuginfo-compression=zstd foo.rs 2>&1 | sed 's/.*unknown.*zstd.*/missing/' | head -n 1`" = missing || readelf -t $(TMPDIR)/foo.o | grep -q ZST diff --git a/tests/run-make/compressed-debuginfo/rmake.rs b/tests/run-make/compressed-debuginfo/rmake.rs new file mode 100644 index 00000000000..9c6d50ab243 --- /dev/null +++ b/tests/run-make/compressed-debuginfo/rmake.rs @@ -0,0 +1,36 @@ +// Checks the `debuginfo-compression` option. + +//@ only-linux +//@ ignore-cross-compile + +// FIXME: This test isn't comprehensive and isn't covering all possible combinations. + +use run_make_support::{assert_contains, cmd, run_in_tmpdir, rustc}; + +fn check_compression(compression: &str, to_find: &str) { + run_in_tmpdir(|| { + let out = rustc() + .crate_name("foo") + .crate_type("lib") + .emit("obj") + .arg("-Cdebuginfo=full") + .arg(&format!("-Zdebuginfo-compression={compression}")) + .input("foo.rs") + .run(); + let stderr = out.stderr_utf8(); + if stderr.is_empty() { + // FIXME: `readelf` might need to be replaced with `llvm-readelf`. + cmd("readelf").arg("-t").arg("foo.o").run().assert_stdout_contains(to_find); + } else { + assert_contains( + &stderr, + &format!("unknown debuginfo compression algorithm {compression}"), + ); + } + }); +} + +fn main() { + check_compression("zlib", "ZLIB"); + check_compression("zstd", "ZSTD"); +} diff --git a/tests/run-make/crate-name-priority/Makefile b/tests/run-make/crate-name-priority/Makefile deleted file mode 100644 index 4adaa75a71c..00000000000 --- a/tests/run-make/crate-name-priority/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) foo.rs - rm $(TMPDIR)/$(call BIN,foo) - $(RUSTC) foo.rs --crate-name bar - rm $(TMPDIR)/$(call BIN,bar) - $(RUSTC) foo1.rs - rm $(TMPDIR)/$(call BIN,foo) - $(RUSTC) foo1.rs -o $(TMPDIR)/$(call BIN,bar1) - rm $(TMPDIR)/$(call BIN,bar1) diff --git a/tests/run-make/crate-name-priority/rmake.rs b/tests/run-make/crate-name-priority/rmake.rs new file mode 100644 index 00000000000..b7cb2c99711 --- /dev/null +++ b/tests/run-make/crate-name-priority/rmake.rs @@ -0,0 +1,18 @@ +// The `crate_name` rustc flag should have higher priority +// over `#![crate_name = "foo"]` defined inside the source code. +// This test has a conflict between crate_names defined in the .rs files +// and the compiler flags, and checks that the flag is favoured each time. +// See https://github.com/rust-lang/rust/pull/15518 + +use run_make_support::{bin_name, fs_wrapper, rustc}; + +fn main() { + rustc().input("foo.rs").run(); + fs_wrapper::remove_file(bin_name("foo")); + rustc().input("foo.rs").crate_name("bar").run(); + fs_wrapper::remove_file(bin_name("bar")); + rustc().input("foo1.rs").run(); + fs_wrapper::remove_file(bin_name("foo")); + rustc().input("foo1.rs").output(bin_name("bar1")).run(); + fs_wrapper::remove_file(bin_name("bar1")); +} diff --git a/tests/run-make/debugger-visualizer-dep-info/Makefile b/tests/run-make/debugger-visualizer-dep-info/Makefile deleted file mode 100644 index 0877998a74f..00000000000 --- a/tests/run-make/debugger-visualizer-dep-info/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include ../tools.mk - -# This test makes sure that files referenced via #[debugger_visualizer] are -# included in `--emit dep-info` output. - -all: - $(RUSTC) --emit dep-info main.rs - $(CGREP) "foo.py" < $(TMPDIR)/main.d - $(CGREP) "my_visualizers/bar.natvis" < $(TMPDIR)/main.d diff --git a/tests/run-make/debugger-visualizer-dep-info/rmake.rs b/tests/run-make/debugger-visualizer-dep-info/rmake.rs new file mode 100644 index 00000000000..65ffb2373e7 --- /dev/null +++ b/tests/run-make/debugger-visualizer-dep-info/rmake.rs @@ -0,0 +1,11 @@ +// This test checks that files referenced via #[debugger_visualizer] are +// included in `--emit dep-info` output. +// See https://github.com/rust-lang/rust/pull/111641 + +use run_make_support::{invalid_utf8_contains, rustc}; + +fn main() { + rustc().emit("dep-info").input("main.rs").run(); + invalid_utf8_contains("main.d", "foo.py"); + invalid_utf8_contains("main.d", "my_visualizers/bar.natvis"); +} diff --git a/tests/run-make/error-writing-dependencies/Makefile b/tests/run-make/error-writing-dependencies/Makefile deleted file mode 100644 index a5d30a647f8..00000000000 --- a/tests/run-make/error-writing-dependencies/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -include ../tools.mk - -all: - # Let's get a nice error message - $(BARE_RUSTC) foo.rs --emit dep-info --out-dir foo/bar/baz 2>&1 | \ - $(CGREP) "error writing dependencies" - # Make sure the filename shows up - $(BARE_RUSTC) foo.rs --emit dep-info --out-dir foo/bar/baz 2>&1 | $(CGREP) "baz" diff --git a/tests/run-make/error-writing-dependencies/rmake.rs b/tests/run-make/error-writing-dependencies/rmake.rs new file mode 100644 index 00000000000..2227f0a1a7f --- /dev/null +++ b/tests/run-make/error-writing-dependencies/rmake.rs @@ -0,0 +1,17 @@ +// Invalid paths passed to rustc used to cause internal compilation errors +// alongside an obscure error message. This was turned into a standard error, +// and this test checks that the cleaner error message is printed instead. +// See https://github.com/rust-lang/rust/issues/13517 + +use run_make_support::rustc; + +// NOTE: This cannot be a UI test due to the --out-dir flag, which is +// already present by default in UI testing. + +fn main() { + let out = rustc().input("foo.rs").emit("dep-info").out_dir("foo/bar/baz").run_fail(); + // The error message should be informative. + out.assert_stderr_contains("error writing dependencies"); + // The filename should appear. + out.assert_stderr_contains("baz"); +} diff --git a/tests/run-make/extern-flag-rename-transitive/Makefile b/tests/run-make/extern-flag-rename-transitive/Makefile deleted file mode 100644 index d16a8e20868..00000000000 --- a/tests/run-make/extern-flag-rename-transitive/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) foo.rs - $(RUSTC) bar.rs - $(RUSTC) baz.rs --extern a=$(TMPDIR)/libfoo.rlib - diff --git a/tests/run-make/extern-flag-rename-transitive/rmake.rs b/tests/run-make/extern-flag-rename-transitive/rmake.rs new file mode 100644 index 00000000000..0090d487f03 --- /dev/null +++ b/tests/run-make/extern-flag-rename-transitive/rmake.rs @@ -0,0 +1,14 @@ +// In this test, baz.rs is looking for an extern crate "a" which +// does not exist, and can only run through the --extern rustc flag +// defining that the "a" crate is in fact just "foo". This test +// checks that the --extern flag takes precedence over the extern +// crate statement in the code. +// See https://github.com/rust-lang/rust/pull/52723 + +use run_make_support::{rust_lib_name, rustc}; + +fn main() { + rustc().input("foo.rs").run(); + rustc().input("bar.rs").run(); + rustc().input("baz.rs").extern_("a", rust_lib_name("foo")).run(); +} diff --git a/tests/run-make/extern-overrides-distribution/Makefile b/tests/run-make/extern-overrides-distribution/Makefile deleted file mode 100644 index bfd0dd6991b..00000000000 --- a/tests/run-make/extern-overrides-distribution/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) libc.rs -Cmetadata=foo - $(RUSTC) main.rs --extern libc=$(TMPDIR)/liblibc.rlib diff --git a/tests/run-make/extern-overrides-distribution/rmake.rs b/tests/run-make/extern-overrides-distribution/rmake.rs new file mode 100644 index 00000000000..bd2553d4134 --- /dev/null +++ b/tests/run-make/extern-overrides-distribution/rmake.rs @@ -0,0 +1,14 @@ +// The --extern flag should override any "crate_type" declarations in the +// Rust files themselves. In this test, libc is compiled as "lib", but +// main.rs will only run with an rlib, which checks if the --extern flag +// is successfully overriding the default behaviour. +// See https://github.com/rust-lang/rust/pull/21782 + +//@ ignore-cross-compile + +use run_make_support::{rust_lib_name, rustc}; + +fn main() { + rustc().input("libc.rs").metadata("foo").run(); + rustc().input("main.rs").extern_("libc", rust_lib_name("libc")).run(); +} diff --git a/tests/run-make/forced-unwind-terminate-pof/Makefile b/tests/run-make/forced-unwind-terminate-pof/Makefile deleted file mode 100644 index 871621520b9..00000000000 --- a/tests/run-make/forced-unwind-terminate-pof/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# ignore-cross-compile -# only-linux -include ../tools.mk - -all: foo - $(call RUN,foo) | $(CGREP) -v "cannot unwind" - -foo: foo.rs - $(RUSTC) $< diff --git a/tests/run-make/forced-unwind-terminate-pof/foo.rs b/tests/run-make/forced-unwind-terminate-pof/foo.rs index 0a51287313f..3a847846217 100644 --- a/tests/run-make/forced-unwind-terminate-pof/foo.rs +++ b/tests/run-make/forced-unwind-terminate-pof/foo.rs @@ -1,6 +1,5 @@ // Tests that forced unwind through POF Rust frames wouldn't trigger our terminating guards. -#![feature(c_unwind)] #![no_main] extern "C-unwind" { diff --git a/tests/run-make/forced-unwind-terminate-pof/rmake.rs b/tests/run-make/forced-unwind-terminate-pof/rmake.rs new file mode 100644 index 00000000000..320ddb172b6 --- /dev/null +++ b/tests/run-make/forced-unwind-terminate-pof/rmake.rs @@ -0,0 +1,16 @@ +// During a forced unwind, crossing the non-Plain Old Frame +// would define the forced unwind as undefined behaviour, and +// immediately abort the unwinding process. This test checks +// that the forced unwinding takes precedence. +// See https://github.com/rust-lang/rust/issues/101469 + +//@ ignore-cross-compile +//@ ignore-windows +//Reason: pthread (POSIX threads) is not available on Windows + +use run_make_support::{run, rustc}; + +fn main() { + rustc().input("foo.rs").run(); + run("foo").assert_stdout_not_contains("cannot unwind"); +} diff --git a/tests/run-make/inaccessible-temp-dir/rmake.rs b/tests/run-make/inaccessible-temp-dir/rmake.rs index be24e47b6de..c6bfae4cc01 100644 --- a/tests/run-make/inaccessible-temp-dir/rmake.rs +++ b/tests/run-make/inaccessible-temp-dir/rmake.rs @@ -19,7 +19,7 @@ // Reason: `set_readonly` has no effect on directories // and does not prevent modification. -use run_make_support::{fs_wrapper, rustc, test_while_readonly}; +use run_make_support::{fs_wrapper, rustc, target, test_while_readonly}; fn main() { // Create an inaccessible directory. @@ -28,6 +28,7 @@ fn main() { // Run rustc with `-Z temps-dir` set to a directory *inside* the inaccessible one, // so that it can't create `tmp`. rustc() + .target(&target()) .input("program.rs") .arg("-Ztemps-dir=inaccessible/tmp") .run_fail() diff --git a/tests/run-make/inline-always-many-cgu/Makefile b/tests/run-make/inline-always-many-cgu/Makefile deleted file mode 100644 index 9945821db28..00000000000 --- a/tests/run-make/inline-always-many-cgu/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) foo.rs --emit llvm-ir -C codegen-units=2 - if cat $(TMPDIR)/*.ll | $(CGREP) -e '\bcall\b'; then \ - echo "found call instruction when one wasn't expected"; \ - exit 1; \ - fi diff --git a/tests/run-make/inline-always-many-cgu/rmake.rs b/tests/run-make/inline-always-many-cgu/rmake.rs new file mode 100644 index 00000000000..c55ea69f3b9 --- /dev/null +++ b/tests/run-make/inline-always-many-cgu/rmake.rs @@ -0,0 +1,18 @@ +use run_make_support::fs_wrapper::read_to_string; +use run_make_support::regex::Regex; +use run_make_support::{read_dir, rustc}; + +use std::ffi::OsStr; + +fn main() { + rustc().input("foo.rs").emit("llvm-ir").codegen_units(2).run(); + let re = Regex::new(r"\bcall\b").unwrap(); + let mut nb_ll = 0; + read_dir(".", |path| { + if path.is_file() && path.extension().is_some_and(|ext| ext == OsStr::new("ll")) { + assert!(!re.is_match(&read_to_string(path))); + nb_ll += 1; + } + }); + assert!(nb_ll > 0); +} diff --git a/tests/run-make/link-args-order/Makefile b/tests/run-make/link-args-order/Makefile deleted file mode 100644 index c562cc1b396..00000000000 --- a/tests/run-make/link-args-order/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# ignore-msvc - -include ../tools.mk - -RUSTC_FLAGS = -C linker-flavor=ld -C link-arg=a -C link-args="b c" -C link-args="d e" -C link-arg=f -RUSTC_FLAGS_PRE = -C linker-flavor=ld -Z pre-link-arg=a -Z pre-link-args="b c" -Z pre-link-args="d e" -Z pre-link-arg=f - -all: - $(RUSTC) $(RUSTC_FLAGS) empty.rs 2>&1 | $(CGREP) '"a" "b" "c" "d" "e" "f"' - $(RUSTC) $(RUSTC_FLAGS_PRE) empty.rs 2>&1 | $(CGREP) '"a" "b" "c" "d" "e" "f"' diff --git a/tests/run-make/link-args-order/rmake.rs b/tests/run-make/link-args-order/rmake.rs new file mode 100644 index 00000000000..d238ad23f27 --- /dev/null +++ b/tests/run-make/link-args-order/rmake.rs @@ -0,0 +1,30 @@ +// Passing linker arguments to the compiler used to be lost or reordered in a messy way +// as they were passed further to the linker. This was fixed in #70665, and this test +// checks that linker arguments remain intact and in the order they were originally passed in. +// See https://github.com/rust-lang/rust/pull/70665 + +//@ ignore-msvc +// Reason: the ld linker does not exist on Windows. + +use run_make_support::rustc; + +fn main() { + rustc() + .input("empty.rs") + .linker_flavor("ld") + .link_arg("a") + .link_args("b c") + .link_args("d e") + .link_arg("f") + .run_fail() + .assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#); + rustc() + .input("empty.rs") + .linker_flavor("ld") + .arg("-Zpre-link-arg=a") + .arg("-Zpre-link-args=b c") + .arg("-Zpre-link-args=d e") + .arg("-Zpre-link-arg=f") + .run_fail() + .assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#); +} diff --git a/tests/run-make/ls-metadata/Makefile b/tests/run-make/ls-metadata/Makefile deleted file mode 100644 index f03569baef7..00000000000 --- a/tests/run-make/ls-metadata/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) foo.rs - $(RUSTC) -Z ls=root $(TMPDIR)/foo - touch $(TMPDIR)/bar - $(RUSTC) -Z ls=root $(TMPDIR)/bar diff --git a/tests/run-make/ls-metadata/rmake.rs b/tests/run-make/ls-metadata/rmake.rs new file mode 100644 index 00000000000..0e60f2c4678 --- /dev/null +++ b/tests/run-make/ls-metadata/rmake.rs @@ -0,0 +1,17 @@ +// Passing invalid files to -Z ls (which lists the symbols +// defined by a library crate) used to cause a segmentation fault. +// As this was fixed in #11262, this test checks that no segfault +// occurs when passing the invalid file `bar` to -Z ls. +// See https://github.com/rust-lang/rust/issues/11259 + +//@ ignore-cross-compile + +use run_make_support::fs_wrapper; +use run_make_support::rustc; + +fn main() { + rustc().input("foo.rs").run(); + rustc().arg("-Zls=root").input("foo").run(); + fs_wrapper::create_file("bar"); + rustc().arg("-Zls=root").input("bar").run(); +} diff --git a/tests/run-make/lto-readonly-lib/Makefile b/tests/run-make/lto-readonly-lib/Makefile deleted file mode 100644 index 11d944e3e3d..00000000000 --- a/tests/run-make/lto-readonly-lib/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) lib.rs - - # the compiler needs to copy and modify the rlib file when performing - # LTO, so we should ensure that it can cope with the original rlib - # being read-only. - chmod 444 $(TMPDIR)/*.rlib - - $(RUSTC) main.rs -C lto - $(call RUN,main) diff --git a/tests/run-make/lto-readonly-lib/rmake.rs b/tests/run-make/lto-readonly-lib/rmake.rs new file mode 100644 index 00000000000..9eb135addd9 --- /dev/null +++ b/tests/run-make/lto-readonly-lib/rmake.rs @@ -0,0 +1,19 @@ +// When the compiler is performing link time optimization, it will +// need to copy the original rlib file, set the copy's permissions to read/write, +// and modify that copy - even if the original +// file is read-only. This test creates a read-only rlib, and checks that +// compilation with LTO succeeds. +// See https://github.com/rust-lang/rust/pull/17619 + +//@ ignore-cross-compile + +use run_make_support::fs_wrapper; +use run_make_support::{run, rust_lib_name, rustc, test_while_readonly}; + +fn main() { + rustc().input("lib.rs").run(); + test_while_readonly(rust_lib_name("lib"), || { + rustc().input("main.rs").arg("-Clto").run(); + run("main"); + }); +} diff --git a/tests/run-make/metadata-flag-frobs-symbols/Makefile b/tests/run-make/metadata-flag-frobs-symbols/Makefile deleted file mode 100644 index 53d7d065769..00000000000 --- a/tests/run-make/metadata-flag-frobs-symbols/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) foo.rs -C metadata=a -C extra-filename=-a - $(RUSTC) foo.rs -C metadata=b -C extra-filename=-b - $(RUSTC) bar.rs \ - --extern foo1=$(TMPDIR)/libfoo-a.rlib \ - --extern foo2=$(TMPDIR)/libfoo-b.rlib \ - --print link-args - $(call RUN,bar) diff --git a/tests/run-make/metadata-flag-frobs-symbols/rmake.rs b/tests/run-make/metadata-flag-frobs-symbols/rmake.rs new file mode 100644 index 00000000000..938886957fb --- /dev/null +++ b/tests/run-make/metadata-flag-frobs-symbols/rmake.rs @@ -0,0 +1,20 @@ +// In this test, foo.rs is compiled twice with different hashes tied to its +// symbols thanks to the metadata flag. bar.rs then ensures that the memory locations +// of foo's symbols are different even though they came from the same original source code. +// This checks that the metadata flag is doing its job. +// See https://github.com/rust-lang/rust/issues/14471 + +//@ ignore-cross-compile + +use run_make_support::{run, rust_lib_name, rustc}; + +fn main() { + rustc().input("foo.rs").metadata("a").extra_filename("-a").run(); + rustc().input("foo.rs").metadata("b").extra_filename("-b").run(); + rustc() + .input("bar.rs") + .extern_("foo1", rust_lib_name("foo-a")) + .extern_("foo2", rust_lib_name("foo-b")) + .run(); + run("bar"); +} diff --git a/tests/run-make/relocation-model/Makefile b/tests/run-make/relocation-model/Makefile deleted file mode 100644 index 8cc5205ed51..00000000000 --- a/tests/run-make/relocation-model/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: others - $(RUSTC) -C relocation-model=dynamic-no-pic foo.rs - $(call RUN,foo) - - $(RUSTC) -C relocation-model=default foo.rs - $(call RUN,foo) - - $(RUSTC) -C relocation-model=dynamic-no-pic --crate-type=dylib foo.rs --emit=link,obj - -ifdef IS_MSVC -# FIXME(#28026) -others: -else -others: - $(RUSTC) -C relocation-model=static foo.rs - $(call RUN,foo) -endif diff --git a/tests/run-make/relocation-model/rmake.rs b/tests/run-make/relocation-model/rmake.rs new file mode 100644 index 00000000000..9cf85d6d730 --- /dev/null +++ b/tests/run-make/relocation-model/rmake.rs @@ -0,0 +1,24 @@ +// Generation of position-independent code (PIC) can be altered +// through use of the -C relocation-model rustc flag. This test +// uses varied values with this flag and checks that compilation +// succeeds. +// See https://github.com/rust-lang/rust/pull/13340 + +//@ ignore-cross-compile + +use run_make_support::{run, rustc}; + +fn main() { + rustc().arg("-Crelocation-model=static").input("foo.rs").run(); + run("foo"); + rustc().arg("-Crelocation-model=dynamic-no-pic").input("foo.rs").run(); + run("foo"); + rustc().arg("-Crelocation-model=default").input("foo.rs").run(); + run("foo"); + rustc() + .arg("-Crelocation-model=dynamic-no-pic") + .crate_type("dylib") + .emit("link,obj") + .input("foo.rs") + .run(); +} diff --git a/tests/run-make/relro-levels/Makefile b/tests/run-make/relro-levels/Makefile deleted file mode 100644 index 94f08bcb494..00000000000 --- a/tests/run-make/relro-levels/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# only-linux -# -# This tests the different -Crelro-level values, and makes sure that they work properly. - -all: - # Ensure that binaries built with the full relro level links them with both - # RELRO and BIND_NOW for doing eager symbol resolving. - $(RUSTC) -Crelro-level=full hello.rs - readelf -l $(TMPDIR)/hello | grep -q GNU_RELRO - readelf -d $(TMPDIR)/hello | grep -q BIND_NOW - - $(RUSTC) -Crelro-level=partial hello.rs - readelf -l $(TMPDIR)/hello | grep -q GNU_RELRO - - # Ensure that we're *not* built with RELRO when setting it to off. We do - # not want to check for BIND_NOW however, as the linker might have that - # enabled by default. - $(RUSTC) -Crelro-level=off hello.rs - ! readelf -l $(TMPDIR)/hello | grep -q GNU_RELRO diff --git a/tests/run-make/relro-levels/rmake.rs b/tests/run-make/relro-levels/rmake.rs new file mode 100644 index 00000000000..56545ebc5aa --- /dev/null +++ b/tests/run-make/relro-levels/rmake.rs @@ -0,0 +1,28 @@ +// This tests the different -Crelro-level values, and makes sure that they work properly. + +//@ only-linux + +use run_make_support::llvm_readobj; +use run_make_support::rustc; + +fn compile(relro_level: &str) { + rustc().arg(format!("-Crelro-level={relro_level}")).input("hello.rs").run(); +} + +fn main() { + // Ensure that binaries built with the full relro level links them with both + // RELRO and BIND_NOW for doing eager symbol resolving. + + compile("full"); + llvm_readobj().program_headers().input("hello").run().assert_stdout_contains("GNU_RELRO"); + llvm_readobj().dynamic_table().input("hello").run().assert_stdout_contains("BIND_NOW"); + + compile("partial"); + llvm_readobj().program_headers().input("hello").run().assert_stdout_contains("GNU_RELRO"); + + // Ensure that we're *not* built with RELRO when setting it to off. We do + // not want to check for BIND_NOW however, as the linker might have that + // enabled by default. + compile("off"); + llvm_readobj().program_headers().input("hello").run().assert_stdout_not_contains("GNU_RELRO"); +} diff --git a/tests/run-make/rustdoc-io-error/Makefile b/tests/run-make/rustdoc-io-error/Makefile deleted file mode 100644 index 27f5ecf94ab..00000000000 --- a/tests/run-make/rustdoc-io-error/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -include ../tools.mk - -# This test verifies that rustdoc doesn't ICE when it encounters an IO error -# while generating files. Ideally this would be a rustdoc-ui test, so we could -# verify the error message as well. - -# ignore-windows -# The test uses `chmod`. - -OUTPUT_DIR := "$(TMPDIR)/rustdoc-io-error" - -# This test operates by creating a temporary directory and modifying its -# permissions so that it is not writable. We have to take special care to set -# the permissions back to normal so that it's able to be deleted later. -all: - mkdir -p $(OUTPUT_DIR) - chmod u-w $(OUTPUT_DIR) - -$(shell $(RUSTDOC) -o $(OUTPUT_DIR) foo.rs) - chmod u+w $(OUTPUT_DIR) - exit $($(.SHELLSTATUS) -eq 1) diff --git a/tests/run-make/rustdoc-io-error/rmake.rs b/tests/run-make/rustdoc-io-error/rmake.rs new file mode 100644 index 00000000000..d60e4438e6f --- /dev/null +++ b/tests/run-make/rustdoc-io-error/rmake.rs @@ -0,0 +1,31 @@ +// This test verifies that rustdoc doesn't ICE when it encounters an IO error +// while generating files. Ideally this would be a rustdoc-ui test, so we could +// verify the error message as well. +// +// It operates by creating a temporary directory and modifying its +// permissions so that it is not writable. We have to take special care to set +// the permissions back to normal so that it's able to be deleted later. + +//@ ignore-windows - the `set_readonly` functions doesn't work on folders. +//@ ignore-arm - weird file perms on armhf-gnu + +use run_make_support::{path, rustdoc}; +use std::fs; + +fn main() { + let out_dir = path("rustdoc-io-error"); + let output = fs::create_dir(&out_dir).unwrap(); + let mut permissions = fs::metadata(&out_dir).unwrap().permissions(); + let original_permissions = permissions.clone(); + + permissions.set_readonly(true); + fs::set_permissions(&out_dir, permissions).unwrap(); + + let output = rustdoc().input("foo.rs").output(&out_dir).env("RUST_BACKTRACE", "1").run_fail(); + + fs::set_permissions(&out_dir, original_permissions).unwrap(); + + output + .assert_exit_code(1) + .assert_stderr_contains("error: couldn't generate documentation: Permission denied"); +} diff --git a/tests/run-make/static-pie/Makefile b/tests/run-make/static-pie/Makefile deleted file mode 100644 index 8379730cc3d..00000000000 --- a/tests/run-make/static-pie/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -include ../tools.mk - -# only-x86_64 -# only-linux -# ignore-32bit - -# How to manually run this -# $ ./x.py test --target x86_64-unknown-linux-[musl,gnu] tests/run-make/static-pie - -all: test-clang test-gcc - -test-%: - if ./check_$*_version.sh; then\ - ${RUSTC} -Clinker=$* -Clinker-flavor=gcc --target ${TARGET} -C target-feature=+crt-static test-aslr.rs; \ - ! readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) INTERP; \ - readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) DYNAMIC; \ - $(call RUN,test-aslr) --test-aslr; \ - fi diff --git a/tests/run-make/static-pie/check_clang_version.sh b/tests/run-make/static-pie/check_clang_version.sh deleted file mode 100755 index b8e97c3da7d..00000000000 --- a/tests/run-make/static-pie/check_clang_version.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -if command -v clang > /dev/null -then - CLANG_VERSION=$(echo __clang_major__ | clang -E -x c - | grep -v -e '^#' ) - echo "clang version $CLANG_VERSION detected" - if (( $CLANG_VERSION >= 9 )) - then - echo "clang supports -static-pie" - exit 0 - else - echo "clang too old to support -static-pie, skipping test" - exit 1 - fi -else - echo "No clang version detected" - exit 2 -fi diff --git a/tests/run-make/static-pie/check_gcc_version.sh b/tests/run-make/static-pie/check_gcc_version.sh deleted file mode 100755 index d07e1d151df..00000000000 --- a/tests/run-make/static-pie/check_gcc_version.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -if command -v gcc > /dev/null -then - GCC_VERSION=$(echo __GNUC__ | gcc -E -x c - | grep -v -e '^#' ) - echo "gcc version $GCC_VERSION detected" - if (( $GCC_VERSION >= 8 )) - then - echo "gcc supports -static-pie" - exit 0 - else - echo "gcc too old to support -static-pie, skipping test" - exit 1 - fi -else - echo "No gcc version detected" - exit 2 -fi diff --git a/tests/run-make/static-pie/rmake.rs b/tests/run-make/static-pie/rmake.rs new file mode 100644 index 00000000000..77c5e253bc0 --- /dev/null +++ b/tests/run-make/static-pie/rmake.rs @@ -0,0 +1,73 @@ +// How to manually run this +// $ ./x.py test --target x86_64-unknown-linux-[musl,gnu] tests/run-make/static-pie + +//@ only-x86_64 +//@ only-linux +//@ ignore-32bit + +use std::process::Command; + +use run_make_support::llvm_readobj; +use run_make_support::regex::Regex; +use run_make_support::rustc; +use run_make_support::{cmd, run_with_args, target}; + +// Minimum major versions supporting -static-pie +const GCC_VERSION: u32 = 8; +const CLANG_VERSION: u32 = 9; + +// Return `true` if the `compiler` version supports `-static-pie`. +fn ok_compiler_version(compiler: &str) -> bool { + let (trigger, version_threshold) = match compiler { + "clang" => ("__clang_major__", CLANG_VERSION), + "gcc" => ("__GNUC__", GCC_VERSION), + other => panic!("unexpected compiler '{other}', expected 'clang' or 'gcc'"), + }; + + if Command::new(compiler).spawn().is_err() { + eprintln!("No {compiler} version detected"); + return false; + } + + let compiler_output = + cmd(compiler).stdin(trigger).arg("-").arg("-E").arg("-x").arg("c").run().stdout_utf8(); + let re = Regex::new(r"(?m)^(\d+)").unwrap(); + let version: u32 = + re.captures(&compiler_output).unwrap().get(1).unwrap().as_str().parse().unwrap(); + + if version >= version_threshold { + eprintln!("{compiler} supports -static-pie"); + true + } else { + eprintln!("{compiler} too old to support -static-pie, skipping test"); + false + } +} + +fn test(compiler: &str) { + if !ok_compiler_version(compiler) { + return; + } + + rustc() + .input("test-aslr.rs") + .target(&target()) + .linker(compiler) + .arg("-Clinker-flavor=gcc") + .arg("-Ctarget-feature=+crt-static") + .run(); + + llvm_readobj() + .symbols() + .input("test-aslr") + .run() + .assert_stdout_not_contains("INTERP") + .assert_stdout_contains("DYNAMIC"); + + run_with_args("test-aslr", &["--test-aslr"]); +} + +fn main() { + test("clang"); + test("gcc"); +} diff --git a/tests/run-make/symlinked-libraries/rmake.rs b/tests/run-make/symlinked-libraries/rmake.rs index eaf0c44206a..3f02f19ccd5 100644 --- a/tests/run-make/symlinked-libraries/rmake.rs +++ b/tests/run-make/symlinked-libraries/rmake.rs @@ -6,6 +6,7 @@ // See https://github.com/rust-lang/rust/issues/12459 //@ ignore-cross-compile + use run_make_support::{create_symlink, dynamic_lib_name, fs_wrapper, rustc}; fn main() { diff --git a/tests/rustdoc/const-effect-param.rs b/tests/rustdoc/const-effect-param.rs index b6379c05a85..f3f1fcfda65 100644 --- a/tests/rustdoc/const-effect-param.rs +++ b/tests/rustdoc/const-effect-param.rs @@ -2,6 +2,7 @@ #![crate_name = "foo"] #![feature(effects, const_trait_impl)] +#![allow(incomplete_features)] #[const_trait] pub trait Tr { diff --git a/tests/rustdoc/const-fn-effects.rs b/tests/rustdoc/const-fn-effects.rs index 7c19b4b2c0c..c495a4faa87 100644 --- a/tests/rustdoc/const-fn-effects.rs +++ b/tests/rustdoc/const-fn-effects.rs @@ -1,5 +1,6 @@ #![crate_name = "foo"] #![feature(effects)] +#![allow(incomplete_features)] // @has foo/fn.bar.html // @has - '//pre[@class="rust item-decl"]' 'pub const fn bar() -> ' diff --git a/tests/rustdoc/rfc-2632-const-trait-impl.rs b/tests/rustdoc/rfc-2632-const-trait-impl.rs index 6f264969e54..d165a406f56 100644 --- a/tests/rustdoc/rfc-2632-const-trait-impl.rs +++ b/tests/rustdoc/rfc-2632-const-trait-impl.rs @@ -7,6 +7,7 @@ // not remove this test. // // FIXME(effects) add `const_trait` to `Fn` so we use `~const` +// FIXME(effects) restore `const_trait` to `Destruct` #![feature(const_trait_impl)] #![crate_name = "foo"] @@ -24,9 +25,9 @@ pub trait Tr<T> { // @has - '//section[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Fn' // @!has - '//section[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const' // @has - '//section[@id="method.a"]/h4[@class="code-header"]/div[@class="where"]' ': Fn' - fn a<A: /* ~const */ Fn() + ~const Destruct>() + fn a<A: /* ~const */ Fn() /* + ~const Destruct */>() where - Option<A>: /* ~const */ Fn() + ~const Destruct, + Option<A>: /* ~const */ Fn() /* + ~const Destruct */, { } } @@ -36,13 +37,13 @@ pub trait Tr<T> { // @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/a[@class="trait"]' 'Fn' // @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/span[@class="where"]' '~const' // @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/div[@class="where"]' ': Fn' -impl<T: /* ~const */ Fn() + ~const Destruct> const Tr<T> for T +impl<T: /* ~const */ Fn() /* + ~const Destruct */> const Tr<T> for T where - Option<T>: /* ~const */ Fn() + ~const Destruct, + Option<T>: /* ~const */ Fn() /* + ~const Destruct */, { - fn a<A: /* ~const */ Fn() + ~const Destruct>() + fn a<A: /* ~const */ Fn() /* + ~const Destruct */>() where - Option<A>: /* ~const */ Fn() + ~const Destruct, + Option<A>: /* ~const */ Fn() /* + ~const Destruct */, { } } @@ -51,9 +52,9 @@ where // @has - '//pre[@class="rust item-decl"]/code/a[@class="trait"]' 'Fn' // @!has - '//pre[@class="rust item-decl"]/code/div[@class="where"]' '~const' // @has - '//pre[@class="rust item-decl"]/code/div[@class="where"]' ': Fn' -pub const fn foo<F: /* ~const */ Fn() + ~const Destruct>() +pub const fn foo<F: /* ~const */ Fn() /* + ~const Destruct */>() where - Option<F>: /* ~const */ Fn() + ~const Destruct, + Option<F>: /* ~const */ Fn() /* + ~const Destruct */, { F::a() } @@ -63,9 +64,9 @@ impl<T> S<T> { // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Fn' // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const' // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/div[@class="where"]' ': Fn' - pub const fn foo<B, C: /* ~const */ Fn() + ~const Destruct>() + pub const fn foo<B, C: /* ~const */ Fn() /* + ~const Destruct */>() where - B: /* ~const */ Fn() + ~const Destruct, + B: /* ~const */ Fn() /* + ~const Destruct */, { B::a() } diff --git a/tests/rustdoc/unsafe-extern-blocks.rs b/tests/rustdoc/unsafe-extern-blocks.rs new file mode 100644 index 00000000000..22d3beea6c3 --- /dev/null +++ b/tests/rustdoc/unsafe-extern-blocks.rs @@ -0,0 +1,30 @@ +// Test to ensure the feature is working as expected. + +#![feature(unsafe_extern_blocks)] +#![crate_name = "foo"] + +// @has 'foo/index.html' + +// First we check that both the static and the function have a "sup" element +// to tell they're unsafe. + +// @count - '//ul[@class="item-table"]//sup[@title="unsafe static"]' 1 +// @has - '//ul[@class="item-table"]//sup[@title="unsafe static"]' '⚠' +// @count - '//ul[@class="item-table"]//sup[@title="unsafe function"]' 1 +// @has - '//ul[@class="item-table"]//sup[@title="unsafe function"]' '⚠' + +unsafe extern { + // @has 'foo/static.FOO.html' + // @has - '//pre[@class="rust item-decl"]' 'pub static FOO: i32' + pub safe static FOO: i32; + // @has 'foo/static.BAR.html' + // @has - '//pre[@class="rust item-decl"]' 'pub unsafe static BAR: i32' + pub static BAR: i32; + + // @has 'foo/fn.foo.html' + // @has - '//pre[@class="rust item-decl"]' 'pub extern "C" fn foo()' + pub safe fn foo(); + // @has 'foo/fn.bar.html' + // @has - '//pre[@class="rust item-decl"]' 'pub unsafe extern "C" fn bar()' + pub fn bar(); +} diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index 359dd4146ba..7518ea902ec 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -54,6 +54,21 @@ fn test_stable_mir() -> ControlFlow<()> { let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap(); check_variadic(variadic_fn); + // Extract function pointers. + let fn_ptr_holder = *get_item(&items, (ItemKind::Fn, "fn_ptr_holder")).unwrap(); + let fn_ptr_holder_instance = Instance::try_from(fn_ptr_holder).unwrap(); + let body = fn_ptr_holder_instance.body().unwrap(); + let args = body.arg_locals(); + + // Test fn_abi of function pointer version. + let ptr_fn_abi = args[0].ty.kind().fn_sig().unwrap().fn_ptr_abi().unwrap(); + assert_eq!(ptr_fn_abi, fn_abi); + + // Test variadic_fn of function pointer version. + let ptr_variadic_fn_abi = args[1].ty.kind().fn_sig().unwrap().fn_ptr_abi().unwrap(); + assert!(ptr_variadic_fn_abi.c_variadic); + assert_eq!(ptr_variadic_fn_abi.args.len(), 1); + ControlFlow::Continue(()) } @@ -164,6 +179,14 @@ fn generate_input(path: &str) -> std::io::Result<()> { pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{ 0 }} + + pub type ComplexFn = fn([u8; 0], char, NonZero<u8>) -> Result<usize, &'static str>; + pub type VariadicFn = unsafe extern "C" fn(usize, ...) -> usize; + + pub fn fn_ptr_holder(complex_fn: ComplexFn, variadic_fn: VariadicFn) {{ + // We only care about the signature. + todo!() + }} "# )?; Ok(()) diff --git a/tests/ui/abi/abi-typo-unstable.stderr b/tests/ui/abi/abi-typo-unstable.stderr index d31cc2a896f..9ba67ad7dbe 100644 --- a/tests/ui/abi/abi-typo-unstable.stderr +++ b/tests/ui/abi/abi-typo-unstable.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `rust-intrinsec` LL | extern "rust-intrinsec" fn rust_intrinsic() {} | ^^^^^^^^^^^^^^^^ invalid ABI | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions error: aborting due to 1 previous error diff --git a/tests/ui/abi/riscv-discoverability-guidance.riscv32.stderr b/tests/ui/abi/riscv-discoverability-guidance.riscv32.stderr index 02082c13f91..e80411fda34 100644 --- a/tests/ui/abi/riscv-discoverability-guidance.riscv32.stderr +++ b/tests/ui/abi/riscv-discoverability-guidance.riscv32.stderr @@ -7,7 +7,7 @@ LL | extern "riscv-interrupt" fn isr() {} | invalid ABI | help: did you mean: `"riscv-interrupt-m"` | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions = note: please use one of riscv-interrupt-m or riscv-interrupt-s for machine- or supervisor-level interrupts, respectively error[E0703]: invalid ABI: found `riscv-interrupt-u` @@ -19,7 +19,7 @@ LL | extern "riscv-interrupt-u" fn isr_U() {} | invalid ABI | help: did you mean: `"riscv-interrupt-m"` | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions = note: user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314 error: aborting due to 2 previous errors diff --git a/tests/ui/abi/riscv-discoverability-guidance.riscv64.stderr b/tests/ui/abi/riscv-discoverability-guidance.riscv64.stderr index 02082c13f91..e80411fda34 100644 --- a/tests/ui/abi/riscv-discoverability-guidance.riscv64.stderr +++ b/tests/ui/abi/riscv-discoverability-guidance.riscv64.stderr @@ -7,7 +7,7 @@ LL | extern "riscv-interrupt" fn isr() {} | invalid ABI | help: did you mean: `"riscv-interrupt-m"` | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions = note: please use one of riscv-interrupt-m or riscv-interrupt-s for machine- or supervisor-level interrupts, respectively error[E0703]: invalid ABI: found `riscv-interrupt-u` @@ -19,7 +19,7 @@ LL | extern "riscv-interrupt-u" fn isr_U() {} | invalid ABI | help: did you mean: `"riscv-interrupt-m"` | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions = note: user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314 error: aborting due to 2 previous errors diff --git a/tests/ui/abi/variadic-ffi.rs b/tests/ui/abi/variadic-ffi.rs index de4844ac860..6cfae0f2a32 100644 --- a/tests/ui/abi/variadic-ffi.rs +++ b/tests/ui/abi/variadic-ffi.rs @@ -14,6 +14,10 @@ pub unsafe extern "C" fn test_valist_forward(n: u64, mut ap: ...) -> f64 { rust_valist_interesting_average(n, ap.as_va_list()) } +pub unsafe extern "C-unwind" fn c_unwind_can_forward(n: u64, mut ap: ...) -> f64 { + rust_valist_interesting_average(n, ap.as_va_list()) +} + pub unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) { let mut ap2 = ap.clone(); assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 30); @@ -73,6 +77,10 @@ pub fn main() { } unsafe { + assert_eq!(c_unwind_can_forward(2, 10i64, 10f64, 20i64, 20f64) as i64, 30); + } + + unsafe { test_va_copy(4, 10i64, 10f64, 20i64, 20f64, 30i64, 30f64, 40i64, 40f64); } } diff --git a/tests/ui/asm/aarch64/may_unwind.rs b/tests/ui/asm/aarch64/may_unwind.rs index a483008c364..01d52f9022d 100644 --- a/tests/ui/asm/aarch64/may_unwind.rs +++ b/tests/ui/asm/aarch64/may_unwind.rs @@ -16,7 +16,7 @@ impl Drop for Foo<'_> { } } -extern "C" fn panicky() { +extern "C-unwind" fn panicky() { resume_unwind(Box::new(())); } diff --git a/tests/ui/asm/x86_64/may_unwind.rs b/tests/ui/asm/x86_64/may_unwind.rs index 3b2c1edcd47..d3a2916df9d 100644 --- a/tests/ui/asm/x86_64/may_unwind.rs +++ b/tests/ui/asm/x86_64/may_unwind.rs @@ -16,7 +16,7 @@ impl Drop for Foo<'_> { } } -extern "C" fn panicky() { +extern "C-unwind" fn panicky() { resume_unwind(Box::new(())); } diff --git a/tests/ui/attributes/dump-preds.rs b/tests/ui/attributes/dump-preds.rs new file mode 100644 index 00000000000..1e15ff2f9bd --- /dev/null +++ b/tests/ui/attributes/dump-preds.rs @@ -0,0 +1,20 @@ +//@ normalize-stderr-test "DefId\(.+?\)" -> "DefId(..)" + +#![feature(rustc_attrs)] + +#[rustc_dump_predicates] +trait Trait<T>: Iterator<Item: Copy> +//~^ ERROR rustc_dump_predicates +where + String: From<T> +{ + #[rustc_dump_predicates] + #[rustc_dump_item_bounds] + type Assoc<P: Eq>: std::ops::Deref<Target = ()> + //~^ ERROR rustc_dump_predicates + //~| ERROR rustc_dump_item_bounds + where + Self::Assoc<()>: Copy; +} + +fn main() {} diff --git a/tests/ui/attributes/dump-preds.stderr b/tests/ui/attributes/dump-preds.stderr new file mode 100644 index 00000000000..26834376e76 --- /dev/null +++ b/tests/ui/attributes/dump-preds.stderr @@ -0,0 +1,39 @@ +error: rustc_dump_predicates + --> $DIR/dump-preds.rs:6:1 + | +LL | trait Trait<T>: Iterator<Item: Copy> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: Binder { value: TraitPredicate(<Self as std::iter::Iterator>, polarity:Positive), bound_vars: [] } + = note: Binder { value: TraitPredicate(<<Self as std::iter::Iterator>::Item as std::marker::Copy>, polarity:Positive), bound_vars: [] } + = note: Binder { value: TraitPredicate(<T as std::marker::Sized>, polarity:Positive), bound_vars: [] } + = note: Binder { value: TraitPredicate(<std::string::String as std::convert::From<T>>, polarity:Positive), bound_vars: [] } + = note: Binder { value: TraitPredicate(<Self as Trait<T>>, polarity:Positive), bound_vars: [] } + +error: rustc_dump_predicates + --> $DIR/dump-preds.rs:13:5 + | +LL | type Assoc<P: Eq>: std::ops::Deref<Target = ()> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: Binder { value: TraitPredicate(<Self as std::iter::Iterator>, polarity:Positive), bound_vars: [] } + = note: Binder { value: TraitPredicate(<<Self as std::iter::Iterator>::Item as std::marker::Copy>, polarity:Positive), bound_vars: [] } + = note: Binder { value: TraitPredicate(<T as std::marker::Sized>, polarity:Positive), bound_vars: [] } + = note: Binder { value: TraitPredicate(<std::string::String as std::convert::From<T>>, polarity:Positive), bound_vars: [] } + = note: Binder { value: TraitPredicate(<Self as Trait<T>>, polarity:Positive), bound_vars: [] } + = note: Binder { value: TraitPredicate(<P as std::marker::Sized>, polarity:Positive), bound_vars: [] } + = note: Binder { value: TraitPredicate(<P as std::cmp::Eq>, polarity:Positive), bound_vars: [] } + = note: Binder { value: TraitPredicate(<<Self as Trait<T>>::Assoc<()> as std::marker::Copy>, polarity:Positive), bound_vars: [] } + +error: rustc_dump_item_bounds + --> $DIR/dump-preds.rs:13:5 + | +LL | type Assoc<P: Eq>: std::ops::Deref<Target = ()> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: Binder { value: ProjectionPredicate(AliasTerm { args: [Alias(Projection, AliasTy { args: [Self/#0, T/#1, P/#2], def_id: DefId(..) })], def_id: DefId(..) }, Term::Ty(())), bound_vars: [] } + = note: Binder { value: TraitPredicate(<<Self as Trait<T>>::Assoc<P> as std::ops::Deref>, polarity:Positive), bound_vars: [] } + = note: Binder { value: TraitPredicate(<<Self as Trait<T>>::Assoc<P> as std::marker::Sized>, polarity:Positive), bound_vars: [] } + +error: aborting due to 3 previous errors + diff --git a/tests/ui/c-variadic/issue-86053-1.stderr b/tests/ui/c-variadic/issue-86053-1.stderr index 69e19e1d4d2..67a619e46d5 100644 --- a/tests/ui/c-variadic/issue-86053-1.stderr +++ b/tests/ui/c-variadic/issue-86053-1.stderr @@ -46,7 +46,7 @@ error: `...` must be the last argument of a C-variadic function LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) { | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/issue-86053-1.rs:11:12 | LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) { diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index b3d0046fc17..cc63466585a 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra` LL | cfg!(target_feature = "zebra"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, and `bulk-memory` and 186 more + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, and `avxvnniint8` and 191 more = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index d2026a68450..8a99ace75d8 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -165,7 +165,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index 856ec4a5b9e..fdcada468e0 100644 --- a/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -17,7 +17,7 @@ help: add a dummy let to cause `fptr` to be fully captured | LL ~ thread::spawn(move || { let _ = &fptr; unsafe { LL | - ... +... LL | LL ~ } }).join().unwrap(); | @@ -39,7 +39,7 @@ help: add a dummy let to cause `fptr` to be fully captured | LL ~ thread::spawn(move || { let _ = &fptr; unsafe { LL | - ... +... LL | LL ~ } }).join().unwrap(); | diff --git a/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr index 344bc662ee7..138778ff5d7 100644 --- a/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr +++ b/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr @@ -109,7 +109,7 @@ help: add a dummy let to cause `fptr1`, `fptr2` to be fully captured | LL ~ thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe { LL | - ... +... LL | LL ~ } }).join().unwrap(); | diff --git a/tests/ui/codemap_tests/unicode.normal.stderr b/tests/ui/codemap_tests/unicode.normal.stderr index a6e22e1c38f..0f254e0246f 100644 --- a/tests/ui/codemap_tests/unicode.normal.stderr +++ b/tests/ui/codemap_tests/unicode.normal.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `路濫狼á́́` LL | extern "路濫狼á́́" fn foo() {} | ^^^^^^^^^ invalid ABI | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/const_trait_fn-issue-88433.rs b/tests/ui/const-generics/const_trait_fn-issue-88433.rs index 89bcd54c461..cd008aa2c9f 100644 --- a/tests/ui/const-generics/const_trait_fn-issue-88433.rs +++ b/tests/ui/const-generics/const_trait_fn-issue-88433.rs @@ -1,6 +1,6 @@ //@ build-pass -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] trait Func<T> { diff --git a/tests/ui/const-generics/const_trait_fn-issue-88433.stderr b/tests/ui/const-generics/const_trait_fn-issue-88433.stderr new file mode 100644 index 00000000000..4e0d6370fbd --- /dev/null +++ b/tests/ui/const-generics/const_trait_fn-issue-88433.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const_trait_fn-issue-88433.rs:3:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/const-generics/defaults/doesnt_infer.rs b/tests/ui/const-generics/defaults/doesnt_infer.rs index 016685eee9d..f62088210fe 100644 --- a/tests/ui/const-generics/defaults/doesnt_infer.rs +++ b/tests/ui/const-generics/defaults/doesnt_infer.rs @@ -12,4 +12,5 @@ fn main() { let foo = Foo::<1>::foo(); let foo = Foo::foo(); //~^ ERROR type annotations needed for `Foo<_>` + //~| ERROR type annotations needed } diff --git a/tests/ui/const-generics/defaults/doesnt_infer.stderr b/tests/ui/const-generics/defaults/doesnt_infer.stderr index 1e779f75ce0..c17f57f36bc 100644 --- a/tests/ui/const-generics/defaults/doesnt_infer.stderr +++ b/tests/ui/const-generics/defaults/doesnt_infer.stderr @@ -1,14 +1,37 @@ -error[E0282]: type annotations needed for `Foo<_>` +error[E0284]: type annotations needed for `Foo<_>` --> $DIR/doesnt_infer.rs:13:9 | LL | let foo = Foo::foo(); - | ^^^ + | ^^^ ---------- type must be known at this point | +note: required by a const generic parameter in `Foo::<N>::foo` + --> $DIR/doesnt_infer.rs:5:6 + | +LL | impl<const N: u32> Foo<N> { + | ^^^^^^^^^^^^ required by this const generic parameter in `Foo::<N>::foo` +LL | fn foo() -> Self { + | --- required by a bound in this associated function +help: consider giving `foo` an explicit type, where the value of const parameter `N` is specified + | +LL | let foo: Foo<N> = Foo::foo(); + | ++++++++ + +error[E0284]: type annotations needed for `Foo<_>` + --> $DIR/doesnt_infer.rs:13:9 + | +LL | let foo = Foo::foo(); + | ^^^ --- type must be known at this point + | +note: required by a const generic parameter in `Foo` + --> $DIR/doesnt_infer.rs:3:12 + | +LL | struct Foo<const N: u32 = 2>; + | ^^^^^^^^^^^^^^^^ required by this const generic parameter in `Foo` help: consider giving `foo` an explicit type, where the value of const parameter `N` is specified | LL | let foo: Foo<N> = Foo::foo(); | ++++++++ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/defaults/rp_impl_trait_fail.stderr b/tests/ui/const-generics/defaults/rp_impl_trait_fail.stderr index 4ed1c0ded9f..45be3126e3b 100644 --- a/tests/ui/const-generics/defaults/rp_impl_trait_fail.stderr +++ b/tests/ui/const-generics/defaults/rp_impl_trait_fail.stderr @@ -31,12 +31,17 @@ LL | 1_u64 | = help: the trait `Traitor<1, 2>` is implemented for `u64` -error[E0282]: type annotations needed +error[E0284]: type annotations needed --> $DIR/rp_impl_trait_fail.rs:28:5 | LL | uwu(); | ^^^ cannot infer the value of the const parameter `N` declared on the function `uwu` | +note: required by a const generic parameter in `uwu` + --> $DIR/rp_impl_trait_fail.rs:16:8 + | +LL | fn uwu<const N: u8>() -> impl Traitor<N> { + | ^^^^^^^^^^^ required by this const generic parameter in `uwu` help: consider specifying the generic argument | LL | uwu::<N>(); @@ -44,5 +49,5 @@ LL | uwu::<N>(); error: aborting due to 4 previous errors -Some errors have detailed explanations: E0277, E0282. +Some errors have detailed explanations: E0277, E0284. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/generic_arg_infer/issue-91614.rs b/tests/ui/const-generics/generic_arg_infer/issue-91614.rs index cfbc5faecd9..a386b1e5c2b 100644 --- a/tests/ui/const-generics/generic_arg_infer/issue-91614.rs +++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.rs @@ -5,4 +5,5 @@ use std::simd::Mask; fn main() { let y = Mask::<_, _>::splat(false); //~^ ERROR: type annotations needed + //~| ERROR type annotations needed } diff --git a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr index 563406ad5ea..217f609459e 100644 --- a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -1,23 +1,29 @@ -error[E0283]: type annotations needed for `Mask<_, _>` +error[E0284]: type annotations needed for `Mask<_, _>` --> $DIR/issue-91614.rs:6:9 | LL | let y = Mask::<_, _>::splat(false); | ^ -------------------------- type must be known at this point | - = note: cannot satisfy `_: MaskElement` - = help: the following types implement trait `MaskElement`: - i16 - i32 - i64 - i8 - isize -note: required by a bound in `Mask::<T, N>::splat` +note: required by a const generic parameter in `Mask::<T, N>::splat` --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL -help: consider giving `y` an explicit type, where the type for type parameter `T` is specified +help: consider giving `y` an explicit type, where the value of const parameter `N` is specified | LL | let y: Mask<T, N> = Mask::<_, _>::splat(false); | ++++++++++++ -error: aborting due to 1 previous error +error[E0284]: type annotations needed for `Mask<_, _>` + --> $DIR/issue-91614.rs:6:9 + | +LL | let y = Mask::<_, _>::splat(false); + | ^ ------------ type must be known at this point + | +note: required by a const generic parameter in `Mask` + --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL +help: consider giving `y` an explicit type, where the value of const parameter `N` is specified + | +LL | let y: Mask<T, N> = Mask::<_, _>::splat(false); + | ++++++++++++ + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr b/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr index 5cda4681b5c..3739637c279 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr @@ -18,18 +18,41 @@ help: try adding a `where` bound LL | pub const fn new() -> Self where [(); Self::SIZE]: { | +++++++++++++++++++++++ -error[E0282]: type annotations needed for `ArrayHolder<_>` +error[E0284]: type annotations needed for `ArrayHolder<_>` --> $DIR/issue-62504.rs:26:9 | LL | let mut array = ArrayHolder::new(); - | ^^^^^^^^^ + | ^^^^^^^^^ ------------------ type must be known at this point | +note: required by a const generic parameter in `ArrayHolder::<X>::new` + --> $DIR/issue-62504.rs:16:6 + | +LL | impl<const X: usize> ArrayHolder<X> { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `ArrayHolder::<X>::new` +LL | pub const fn new() -> Self { + | --- required by a bound in this associated function +help: consider giving `array` an explicit type, where the value of const parameter `X` is specified + | +LL | let mut array: ArrayHolder<X> = ArrayHolder::new(); + | ++++++++++++++++ + +error[E0284]: type annotations needed for `ArrayHolder<_>` + --> $DIR/issue-62504.rs:26:9 + | +LL | let mut array = ArrayHolder::new(); + | ^^^^^^^^^ ----------- type must be known at this point + | +note: required by a const generic parameter in `ArrayHolder` + --> $DIR/issue-62504.rs:14:20 + | +LL | struct ArrayHolder<const X: usize>([u32; X]); + | ^^^^^^^^^^^^^^ required by this const generic parameter in `ArrayHolder` help: consider giving `array` an explicit type, where the value of const parameter `X` is specified | LL | let mut array: ArrayHolder<X> = ArrayHolder::new(); | ++++++++++++++++ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0282, E0308. -For more information about an error, try `rustc --explain E0282`. +Some errors have detailed explanations: E0284, E0308. +For more information about an error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr index beb159779ff..14c67e2528a 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr @@ -22,18 +22,41 @@ note: tuple struct defined here LL | struct ArrayHolder<const X: usize>([u32; X]); | ^^^^^^^^^^^ -error[E0282]: type annotations needed for `ArrayHolder<_>` +error[E0284]: type annotations needed for `ArrayHolder<_>` --> $DIR/issue-62504.rs:26:9 | LL | let mut array = ArrayHolder::new(); - | ^^^^^^^^^ + | ^^^^^^^^^ ------------------ type must be known at this point | +note: required by a const generic parameter in `ArrayHolder::<X>::new` + --> $DIR/issue-62504.rs:16:6 + | +LL | impl<const X: usize> ArrayHolder<X> { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `ArrayHolder::<X>::new` +LL | pub const fn new() -> Self { + | --- required by a bound in this associated function +help: consider giving `array` an explicit type, where the value of const parameter `X` is specified + | +LL | let mut array: ArrayHolder<X> = ArrayHolder::new(); + | ++++++++++++++++ + +error[E0284]: type annotations needed for `ArrayHolder<_>` + --> $DIR/issue-62504.rs:26:9 + | +LL | let mut array = ArrayHolder::new(); + | ^^^^^^^^^ ----------- type must be known at this point + | +note: required by a const generic parameter in `ArrayHolder` + --> $DIR/issue-62504.rs:14:20 + | +LL | struct ArrayHolder<const X: usize>([u32; X]); + | ^^^^^^^^^^^^^^ required by this const generic parameter in `ArrayHolder` help: consider giving `array` an explicit type, where the value of const parameter `X` is specified | LL | let mut array: ArrayHolder<X> = ArrayHolder::new(); | ++++++++++++++++ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0282, E0308. -For more information about an error, try `rustc --explain E0282`. +Some errors have detailed explanations: E0284, E0308. +For more information about an error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/generic_const_exprs/issue-62504.rs b/tests/ui/const-generics/generic_const_exprs/issue-62504.rs index b6a6a277843..f021e103614 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-62504.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-62504.rs @@ -25,4 +25,5 @@ impl<const X: usize> ArrayHolder<X> { fn main() { let mut array = ArrayHolder::new(); //~^ ERROR: type annotations needed + //~| ERROR type annotations needed } diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs b/tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs index 79e9834b54e..298cfb512e4 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs +++ b/tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs @@ -18,4 +18,5 @@ fn use_dyn<const N: usize>(v: &dyn Foo<N>) where [u8; N + 1]: Sized { fn main() { use_dyn(&()); //~^ ERROR type annotations needed + //~| ERROR type annotations needed } diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr b/tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr index e800c5d059f..d1e1c976da6 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr +++ b/tests/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr @@ -4,16 +4,37 @@ error[E0284]: type annotations needed LL | use_dyn(&()); | ^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `use_dyn` | -note: required by a bound in `use_dyn` - --> $DIR/object-safety-ok-infer-err.rs:14:55 +note: required by a const generic parameter in `use_dyn` + --> $DIR/object-safety-ok-infer-err.rs:14:12 | LL | fn use_dyn<const N: usize>(v: &dyn Foo<N>) where [u8; N + 1]: Sized { - | ^^^^^ required by this bound in `use_dyn` + | ^^^^^^^^^^^^^^ required by this const generic parameter in `use_dyn` help: consider specifying the generic argument | LL | use_dyn::<N>(&()); | +++++ -error: aborting due to 1 previous error +error[E0284]: type annotations needed + --> $DIR/object-safety-ok-infer-err.rs:19:5 + | +LL | use_dyn(&()); + | ^^^^^^^ --- type must be known at this point + | | + | cannot infer the value of the const parameter `N` declared on the function `use_dyn` + | +note: required for `()` to implement `Foo<_>` + --> $DIR/object-safety-ok-infer-err.rs:8:22 + | +LL | impl<const N: usize> Foo<N> for () { + | -------------- ^^^^^^ ^^ + | | + | unsatisfied trait bound introduced here + = note: required for the cast from `&()` to `&dyn Foo<_>` +help: consider specifying the generic argument + | +LL | use_dyn::<N>(&()); + | +++++ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/infer/cannot-infer-const-args.stderr b/tests/ui/const-generics/infer/cannot-infer-const-args.stderr index e3caefef10f..c349a50a83f 100644 --- a/tests/ui/const-generics/infer/cannot-infer-const-args.stderr +++ b/tests/ui/const-generics/infer/cannot-infer-const-args.stderr @@ -1,9 +1,14 @@ -error[E0282]: type annotations needed +error[E0284]: type annotations needed --> $DIR/cannot-infer-const-args.rs:6:5 | LL | foo(); | ^^^ cannot infer the value of the const parameter `X` declared on the function `foo` | +note: required by a const generic parameter in `foo` + --> $DIR/cannot-infer-const-args.rs:1:8 + | +LL | fn foo<const X: usize>() -> usize { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `foo` help: consider specifying the generic argument | LL | foo::<X>(); @@ -11,4 +16,4 @@ LL | foo::<X>(); error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/infer/issue-77092.rs b/tests/ui/const-generics/infer/issue-77092.rs index fcf7d3282b4..47c594e5b11 100644 --- a/tests/ui/const-generics/infer/issue-77092.rs +++ b/tests/ui/const-generics/infer/issue-77092.rs @@ -1,14 +1,15 @@ use std::convert::TryInto; fn take_array_from_mut<T, const N: usize>(data: &mut [T], start: usize) -> &mut [T; N] { - (&mut data[start .. start + N]).try_into().unwrap() + (&mut data[start..start + N]).try_into().unwrap() } fn main() { let mut arr = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - for i in 1 .. 4 { + for i in 1..4 { println!("{:?}", take_array_from_mut(&mut arr, i)); //~^ ERROR type annotations needed + //~| ERROR type annotations needed } } diff --git a/tests/ui/const-generics/infer/issue-77092.stderr b/tests/ui/const-generics/infer/issue-77092.stderr index 5b411269862..9a6374a2adc 100644 --- a/tests/ui/const-generics/infer/issue-77092.stderr +++ b/tests/ui/const-generics/infer/issue-77092.stderr @@ -1,14 +1,37 @@ -error[E0282]: type annotations needed +error[E0284]: type annotations needed --> $DIR/issue-77092.rs:11:26 | LL | println!("{:?}", take_array_from_mut(&mut arr, i)); | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `take_array_from_mut` | +note: required by a const generic parameter in `take_array_from_mut` + --> $DIR/issue-77092.rs:3:27 + | +LL | fn take_array_from_mut<T, const N: usize>(data: &mut [T], start: usize) -> &mut [T; N] { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `take_array_from_mut` +help: consider specifying the generic arguments + | +LL | println!("{:?}", take_array_from_mut::<i32, N>(&mut arr, i)); + | ++++++++++ + +error[E0284]: type annotations needed + --> $DIR/issue-77092.rs:11:26 + | +LL | println!("{:?}", take_array_from_mut(&mut arr, i)); + | ---- ^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `take_array_from_mut` + | | + | type must be known at this point + | + = note: required for `[i32; _]` to implement `Debug` + = note: 1 redundant requirement hidden + = note: required for `&mut [i32; _]` to implement `Debug` +note: required by a bound in `core::fmt::rt::Argument::<'a>::new_debug` + --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL help: consider specifying the generic arguments | LL | println!("{:?}", take_array_from_mut::<i32, N>(&mut arr, i)); | ++++++++++ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/infer/method-chain.stderr b/tests/ui/const-generics/infer/method-chain.stderr index 2def9e85ab7..95044bb5203 100644 --- a/tests/ui/const-generics/infer/method-chain.stderr +++ b/tests/ui/const-generics/infer/method-chain.stderr @@ -1,9 +1,14 @@ -error[E0282]: type annotations needed +error[E0284]: type annotations needed --> $DIR/method-chain.rs:15:33 | LL | Foo.bar().bar().bar().bar().baz(); | ^^^ cannot infer the value of the const parameter `N` declared on the method `baz` | +note: required by a const generic parameter in `Foo::baz` + --> $DIR/method-chain.rs:8:12 + | +LL | fn baz<const N: usize>(self) -> Foo { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `Foo::baz` help: consider specifying the generic argument | LL | Foo.bar().bar().bar().bar().baz::<N>(); @@ -11,4 +16,4 @@ LL | Foo.bar().bar().bar().bar().baz::<N>(); error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/infer/one-param-uninferred.stderr b/tests/ui/const-generics/infer/one-param-uninferred.stderr index 3e33fec9cef..f3aa7973e67 100644 --- a/tests/ui/const-generics/infer/one-param-uninferred.stderr +++ b/tests/ui/const-generics/infer/one-param-uninferred.stderr @@ -1,9 +1,14 @@ -error[E0282]: type annotations needed +error[E0284]: type annotations needed --> $DIR/one-param-uninferred.rs:9:23 | LL | let _: [u8; 17] = foo(); | ^^^ cannot infer the value of the const parameter `M` declared on the function `foo` | +note: required by a const generic parameter in `foo` + --> $DIR/one-param-uninferred.rs:2:24 + | +LL | fn foo<const N: usize, const M: usize>() -> [u8; N] { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `foo` help: consider specifying the generic arguments | LL | let _: [u8; 17] = foo::<17, M>(); @@ -11,4 +16,4 @@ LL | let _: [u8; 17] = foo::<17, M>(); error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/infer/uninferred-consts.rs b/tests/ui/const-generics/infer/uninferred-consts.rs index 657f4b51304..552e2a15c23 100644 --- a/tests/ui/const-generics/infer/uninferred-consts.rs +++ b/tests/ui/const-generics/infer/uninferred-consts.rs @@ -8,4 +8,5 @@ impl Foo { fn main() { Foo.foo(); //~^ ERROR type annotations needed + //~| ERROR type annotations needed } diff --git a/tests/ui/const-generics/infer/uninferred-consts.stderr b/tests/ui/const-generics/infer/uninferred-consts.stderr index 0ec6ac9c22e..839fb25c4e1 100644 --- a/tests/ui/const-generics/infer/uninferred-consts.stderr +++ b/tests/ui/const-generics/infer/uninferred-consts.stderr @@ -1,14 +1,35 @@ -error[E0282]: type annotations needed +error[E0284]: type annotations needed --> $DIR/uninferred-consts.rs:9:9 | LL | Foo.foo(); | ^^^ cannot infer the value of the const parameter `A` declared on the method `foo` | +note: required by a const generic parameter in `Foo::foo` + --> $DIR/uninferred-consts.rs:6:12 + | +LL | fn foo<const A: usize, const B: usize>(self) {} + | ^^^^^^^^^^^^^^ required by this const generic parameter in `Foo::foo` +help: consider specifying the generic arguments + | +LL | Foo.foo::<A, B>(); + | ++++++++ + +error[E0284]: type annotations needed + --> $DIR/uninferred-consts.rs:9:9 + | +LL | Foo.foo(); + | ^^^ cannot infer the value of the const parameter `B` declared on the method `foo` + | +note: required by a const generic parameter in `Foo::foo` + --> $DIR/uninferred-consts.rs:6:28 + | +LL | fn foo<const A: usize, const B: usize>(self) {} + | ^^^^^^^^^^^^^^ required by this const generic parameter in `Foo::foo` help: consider specifying the generic arguments | LL | Foo.foo::<A, B>(); | ++++++++ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/crashes/125799.rs b/tests/ui/const-generics/mistyped_const_in_pat.rs index 62d5438b4e4..6f1dd52872f 100644 --- a/tests/crashes/125799.rs +++ b/tests/ui/const-generics/mistyped_const_in_pat.rs @@ -1,4 +1,5 @@ -//@ known-bug: rust-lang/rust#125799 +//! Used to ICE rust-lang/rust#125799 due to `isize` != `()` +//! not being detected early due to the conflicting impls. //@ only-x86_64 trait Trait<T> { @@ -10,6 +11,7 @@ impl<T> Trait<T> for Vec<T> { } impl Trait<u8> for Vec<u8> {} +//~^ ERROR: conflicting implementations const BAR: <Vec<u8> as Trait<u8>>::Assoc = 3; diff --git a/tests/ui/const-generics/mistyped_const_in_pat.stderr b/tests/ui/const-generics/mistyped_const_in_pat.stderr new file mode 100644 index 00000000000..de7516fa37f --- /dev/null +++ b/tests/ui/const-generics/mistyped_const_in_pat.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait<u8>` for type `Vec<u8>` + --> $DIR/mistyped_const_in_pat.rs:13:1 + | +LL | impl<T> Trait<T> for Vec<T> { + | --------------------------- first implementation here +... +LL | impl Trait<u8> for Vec<u8> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Vec<u8>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr b/tests/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr index 5bef6f3c795..4809f7d37dd 100644 --- a/tests/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr +++ b/tests/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr @@ -4,11 +4,11 @@ error[E0284]: type annotations needed LL | generics_of_parent_impl_trait::foo([()]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `foo` | -note: required by a bound in `foo` - --> $DIR/auxiliary/generics_of_parent_impl_trait.rs:5:48 +note: required by a const generic parameter in `foo` + --> $DIR/auxiliary/generics_of_parent_impl_trait.rs:5:12 | LL | pub fn foo<const N: usize>(foo: impl Into<[(); N + 1]>) { - | ^^^^^ required by this bound in `foo` + | ^^^^^^^^^^^^^^ required by this const generic parameter in `foo` error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/type_mismatch.stderr b/tests/ui/const-generics/type_mismatch.stderr index 07476ae76c6..026999827c0 100644 --- a/tests/ui/const-generics/type_mismatch.stderr +++ b/tests/ui/const-generics/type_mismatch.stderr @@ -4,11 +4,11 @@ error: the constant `N` is not of type `u8` LL | bar::<N>() | ^ expected `u8`, found `usize` | -note: required by a bound in `bar` +note: required by a const generic parameter in `bar` --> $DIR/type_mismatch.rs:6:8 | LL | fn bar<const N: u8>() -> [u8; N] {} - | ^^^^^^^^^^^ required by this bound in `bar` + | ^^^^^^^^^^^ required by this const generic parameter in `bar` error[E0308]: mismatched types --> $DIR/type_mismatch.rs:6:26 diff --git a/tests/ui/const-generics/unify_with_nested_expr.stderr b/tests/ui/const-generics/unify_with_nested_expr.stderr index e050254a3e9..b1aecdb3cb5 100644 --- a/tests/ui/const-generics/unify_with_nested_expr.stderr +++ b/tests/ui/const-generics/unify_with_nested_expr.stderr @@ -4,14 +4,11 @@ error[E0284]: type annotations needed LL | bar(); | ^^^ cannot infer the value of the const parameter `N` declared on the function `bar` | -note: required by a bound in `bar` - --> $DIR/unify_with_nested_expr.rs:14:10 +note: required by a const generic parameter in `bar` + --> $DIR/unify_with_nested_expr.rs:12:8 | LL | fn bar<const N: usize>() - | --- required by a bound in this function -LL | where -LL | [(); N + 1]:, - | ^^^^^ required by this bound in `bar` + | ^^^^^^^^^^^^^^ required by this const generic parameter in `bar` help: consider specifying the generic argument | LL | bar::<N>(); diff --git a/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs b/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs index 8adf3ba433d..eb58233d1b1 100644 --- a/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs +++ b/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs @@ -1,5 +1,5 @@ #![crate_type = "lib"] -#![feature(const_closures, const_trait_impl, effects)] +#![feature(const_closures, const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete pub const fn test() { let cl = const || {}; diff --git a/tests/ui/consts/const-block-const-bound.stderr b/tests/ui/consts/const-block-const-bound.stderr index 81790a62f61..42a42ae3938 100644 --- a/tests/ui/consts/const-block-const-bound.stderr +++ b/tests/ui/consts/const-block-const-bound.stderr @@ -1,3 +1,9 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-block-const-bound.rs:8:22 + | +LL | const fn f<T: ~const Destruct>(x: T) {} + | ^^^^^^^^ + error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-block-const-bound.rs:8:32 | @@ -6,6 +12,6 @@ LL | const fn f<T: ~const Destruct>(x: T) {} | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/const-eval/unwind-abort.rs b/tests/ui/consts/const-eval/unwind-abort.rs index 57959e7db6a..26113e23888 100644 --- a/tests/ui/consts/const-eval/unwind-abort.rs +++ b/tests/ui/consts/const-eval/unwind-abort.rs @@ -1,4 +1,4 @@ -#![feature(c_unwind, const_extern_fn)] +#![feature(const_extern_fn)] const extern "C" fn foo() { panic!() //~ ERROR evaluation of constant value failed diff --git a/tests/ui/consts/const-float-classify.rs b/tests/ui/consts/const-float-classify.rs index 44772fb7313..ae094003c89 100644 --- a/tests/ui/consts/const-float-classify.rs +++ b/tests/ui/consts/const-float-classify.rs @@ -1,5 +1,6 @@ //@ compile-flags: -Zmir-opt-level=0 -//@ run-pass +//@ known-bug: #110395 +// FIXME(effects) run-pass #![feature(const_float_bits_conv)] #![feature(const_float_classify)] diff --git a/tests/ui/consts/const-float-classify.stderr b/tests/ui/consts/const-float-classify.stderr new file mode 100644 index 00000000000..1de27a072cf --- /dev/null +++ b/tests/ui/consts/const-float-classify.stderr @@ -0,0 +1,223 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-float-classify.rs:7:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/const-float-classify.rs:12:12 + | +LL | impl const PartialEq<NonDet> for bool { + | ^^^^^^^^^^^^^^^^^ + | + = 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[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates + --> $DIR/const-float-classify.rs:12:6 + | +LL | impl const PartialEq<NonDet> for bool { + | ^^^^^ 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[E0284]: type annotations needed + --> $DIR/const-float-classify.rs:21:35 + | +LL | const _: () = assert!($a == $b); + | ^^ cannot infer the value of the constant `_` +... +LL | / suite! { +LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] +LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +... | +LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] +LL | | } + | |_- in this macro invocation + | +note: required for `bool` to implement `PartialEq<NonDet>` + --> $DIR/const-float-classify.rs:12:12 + | +LL | impl const PartialEq<NonDet> for bool { + | ----- ^^^^^^^^^^^^^^^^^ ^^^^ + | | + | unsatisfied trait bound introduced here + = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0284]: type annotations needed + --> $DIR/const-float-classify.rs:21:35 + | +LL | const _: () = assert!($a == $b); + | ^^ cannot infer the value of the constant `_` +... +LL | / suite! { +LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] +LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +... | +LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] +LL | | } + | |_- in this macro invocation + | +note: required for `bool` to implement `PartialEq<NonDet>` + --> $DIR/const-float-classify.rs:12:12 + | +LL | impl const PartialEq<NonDet> for bool { + | ----- ^^^^^^^^^^^^^^^^^ ^^^^ + | | + | unsatisfied trait bound introduced here + = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0284]: type annotations needed + --> $DIR/const-float-classify.rs:21:35 + | +LL | const _: () = assert!($a == $b); + | ^^ cannot infer the value of the constant `_` +... +LL | / suite! { +LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] +LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +... | +LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] +LL | | } + | |_- in this macro invocation + | +note: required for `bool` to implement `PartialEq<NonDet>` + --> $DIR/const-float-classify.rs:12:12 + | +LL | impl const PartialEq<NonDet> for bool { + | ----- ^^^^^^^^^^^^^^^^^ ^^^^ + | | + | unsatisfied trait bound introduced here + = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0284]: type annotations needed + --> $DIR/const-float-classify.rs:21:35 + | +LL | const _: () = assert!($a == $b); + | ^^ cannot infer the value of the constant `_` +... +LL | / suite! { +LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] +LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +... | +LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] +LL | | } + | |_- in this macro invocation + | +note: required for `bool` to implement `PartialEq<NonDet>` + --> $DIR/const-float-classify.rs:12:12 + | +LL | impl const PartialEq<NonDet> for bool { + | ----- ^^^^^^^^^^^^^^^^^ ^^^^ + | | + | unsatisfied trait bound introduced here + = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0284]: type annotations needed + --> $DIR/const-float-classify.rs:21:35 + | +LL | const _: () = assert!($a == $b); + | ^^ cannot infer the value of the constant `_` +... +LL | / suite! { +LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] +LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +... | +LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] +LL | | } + | |_- in this macro invocation + | +note: required for `bool` to implement `PartialEq<NonDet>` + --> $DIR/const-float-classify.rs:12:12 + | +LL | impl const PartialEq<NonDet> for bool { + | ----- ^^^^^^^^^^^^^^^^^ ^^^^ + | | + | unsatisfied trait bound introduced here + = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0284]: type annotations needed + --> $DIR/const-float-classify.rs:21:35 + | +LL | const _: () = assert!($a == $b); + | ^^ cannot infer the value of the constant `_` +... +LL | / suite! { +LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] +LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +... | +LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] +LL | | } + | |_- in this macro invocation + | +note: required for `bool` to implement `PartialEq<NonDet>` + --> $DIR/const-float-classify.rs:12:12 + | +LL | impl const PartialEq<NonDet> for bool { + | ----- ^^^^^^^^^^^^^^^^^ ^^^^ + | | + | unsatisfied trait bound introduced here + = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0284]: type annotations needed + --> $DIR/const-float-classify.rs:21:35 + | +LL | const _: () = assert!($a == $b); + | ^^ cannot infer the value of the constant `_` +... +LL | / suite! { +LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] +LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +... | +LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] +LL | | } + | |_- in this macro invocation + | +note: required for `bool` to implement `PartialEq<NonDet>` + --> $DIR/const-float-classify.rs:12:12 + | +LL | impl const PartialEq<NonDet> for bool { + | ----- ^^^^^^^^^^^^^^^^^ ^^^^ + | | + | unsatisfied trait bound introduced here + = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0284]: type annotations needed + --> $DIR/const-float-classify.rs:21:35 + | +LL | const _: () = assert!($a == $b); + | ^^ cannot infer the value of the constant `_` +... +LL | / suite! { +LL | | [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] +LL | | -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +LL | | 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] +... | +LL | | -1.0 / 0.0 => [ false, true, false, false, false, true] +LL | | } + | |_- in this macro invocation + | +note: required for `bool` to implement `PartialEq<NonDet>` + --> $DIR/const-float-classify.rs:12:12 + | +LL | impl const PartialEq<NonDet> for bool { + | ----- ^^^^^^^^^^^^^^^^^ ^^^^ + | | + | unsatisfied trait bound introduced here + = note: this error originates in the macro `const_assert` which comes from the expansion of the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0207, E0284. +For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr index 98f5b3a5e90..e0e673d5fbd 100644 --- a/tests/ui/consts/const_cmp_type_id.stderr +++ b/tests/ui/consts/const_cmp_type_id.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const_cmp_type_id.rs:3:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0131]: `main` function is not allowed to have generic parameters --> $DIR/const_cmp_type_id.rs:7:14 | @@ -10,25 +19,7 @@ error[E0080]: evaluation of constant value failed LL | const _A: bool = TypeId::of::<u8>() < TypeId::of::<u16>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling non-const function `<TypeId as PartialOrd>::lt` -error[E0308]: mismatched types - --> $DIR/const_cmp_type_id.rs:8:13 - | -LL | assert!(TypeId::of::<u8>() == TypeId::of::<u8>()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `host`, found `true` - | - = note: expected constant `host` - found constant `true` - -error[E0308]: mismatched types - --> $DIR/const_cmp_type_id.rs:9:13 - | -LL | assert!(TypeId::of::<()>() != TypeId::of::<u8>()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `host`, found `true` - | - = note: expected constant `host` - found constant `true` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors; 1 warning emitted -Some errors have detailed explanations: E0080, E0131, E0308. +Some errors have detailed explanations: E0080, E0131. For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const_in_pattern/f16-f128-const-reassign.rs b/tests/ui/consts/const_in_pattern/f16-f128-const-reassign.rs new file mode 100644 index 00000000000..99d0e472485 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/f16-f128-const-reassign.rs @@ -0,0 +1,14 @@ +//@ check-pass +// issue: rust-lang/rust#122587 + +#![feature(f128)] +#![feature(f16)] +#![allow(non_upper_case_globals)] + +const h: f16 = 0.0f16; +const q: f128 = 0.0f128; + +pub fn main() { + let h = 0.0f16 else { unreachable!() }; + let q = 0.0f128 else { unreachable!() }; +} diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr index 4fb82c0683d..42a6026cfba 100644 --- a/tests/ui/consts/fn_trait_refs.stderr +++ b/tests/ui/consts/fn_trait_refs.stderr @@ -4,6 +4,12 @@ error[E0635]: unknown feature `const_fn_trait_ref_impls` LL | #![feature(const_fn_trait_ref_impls)] | ^^^^^^^^^^^^^^^^^^^^^^^^ +error[E0635]: unknown feature `const_cmp` + --> $DIR/fn_trait_refs.rs:8:12 + | +LL | #![feature(const_cmp)] + | ^^^^^^^^^ + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:15:15 | @@ -11,6 +17,12 @@ LL | T: ~const Fn<()> + ~const Destruct, | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:15:31 + | +LL | T: ~const Fn<()> + ~const Destruct, + | ^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:15:15 | LL | T: ~const Fn<()> + ~const Destruct, @@ -25,6 +37,12 @@ LL | T: ~const FnMut<()> + ~const Destruct, | ^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:22:34 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:22:15 | LL | T: ~const FnMut<()> + ~const Destruct, @@ -53,6 +71,12 @@ LL | T: ~const Fn<()> + ~const Destruct, | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:36:31 + | +LL | T: ~const Fn<()> + ~const Destruct, + | ^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:36:15 | LL | T: ~const Fn<()> + ~const Destruct, @@ -67,6 +91,12 @@ LL | T: ~const FnMut<()> + ~const Destruct, | ^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:50:34 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:50:15 | LL | T: ~const FnMut<()> + ~const Destruct, @@ -182,7 +212,7 @@ LL | const fn test_fn_mut<T>(mut f: T) -> (T::Output, T::Output) LL | } | - value is dropped here -error: aborting due to 20 previous errors +error: aborting due to 25 previous errors Some errors have detailed explanations: E0015, E0493, E0635. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/rustc-impl-const-stability.stderr b/tests/ui/consts/rustc-impl-const-stability.stderr index ba8e6c1555c..250d1c3fc05 100644 --- a/tests/ui/consts/rustc-impl-const-stability.stderr +++ b/tests/ui/consts/rustc-impl-const-stability.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/rustc-impl-const-stability.rs:5:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: const `impl` for trait `Default` which is not marked with `#[const_trait]` --> $DIR/rustc-impl-const-stability.rs:15:12 | @@ -16,6 +25,6 @@ LL | impl const Default for Data { = 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 +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/consts/unwind-abort.rs b/tests/ui/consts/unwind-abort.rs index 35db9152bd5..1dd33f327fb 100644 --- a/tests/ui/consts/unwind-abort.rs +++ b/tests/ui/consts/unwind-abort.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(c_unwind, const_extern_fn)] +#![feature(const_extern_fn)] // We don't unwind in const-eval anyways. const extern "C" fn foo() { diff --git a/tests/ui/coverage-attr/bad-syntax.rs b/tests/ui/coverage-attr/bad-syntax.rs index 8783714992b..127179877e5 100644 --- a/tests/ui/coverage-attr/bad-syntax.rs +++ b/tests/ui/coverage-attr/bad-syntax.rs @@ -3,13 +3,13 @@ // Tests the error messages produced (or not produced) by various unusual // uses of the `#[coverage(..)]` attribute. -// FIXME(#84605): Multiple coverage attributes with the same value are useless, +// FIXME(#126658): Multiple coverage attributes with the same value are useless, // and should probably produce a diagnostic. #[coverage(off)] #[coverage(off)] fn multiple_consistent() {} -// FIXME(#84605): When there are multiple inconsistent coverage attributes, +// FIXME(#126658): When there are multiple inconsistent coverage attributes, // it's unclear which one will prevail. #[coverage(off)] #[coverage(on)] @@ -18,7 +18,7 @@ fn multiple_inconsistent() {} #[coverage] //~ ERROR expected `coverage(off)` or `coverage(on)` fn bare_word() {} -// FIXME(#84605): This shows as multiple different errors, one of which suggests +// FIXME(#126658): This shows as multiple different errors, one of which suggests // writing bare `#[coverage]`, which is not allowed. #[coverage = true] //~^ ERROR expected `coverage(off)` or `coverage(on)` @@ -48,7 +48,7 @@ fn bogus_word_after() {} #[coverage(off,)] fn comma_after() {} -// FIXME(#84605): This shows as multiple different errors. +// FIXME(#126658): This shows as multiple different errors. #[coverage(,off)] //~^ ERROR expected identifier, found `,` //~| HELP remove this comma diff --git a/tests/ui/coverage-attr/name-value.rs b/tests/ui/coverage-attr/name-value.rs new file mode 100644 index 00000000000..24c329780c5 --- /dev/null +++ b/tests/ui/coverage-attr/name-value.rs @@ -0,0 +1,64 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 + +// Demonstrates the diagnostics produced when using the syntax +// `#[coverage = "off"]`, which should not be allowed. +// +// The syntax is tested both in places that can have a coverage attribute, +// and in places that cannot have a coverage attribute, to demonstrate the +// interaction between multiple errors. + +// FIXME(#126658): The error messages for using this syntax are inconsistent +// with the error message in other cases. They also sometimes appear together +// with other errors, and they suggest using the incorrect `#[coverage]` syntax. + +#[coverage = "off"] //~ ERROR malformed `coverage` attribute input +mod my_mod {} + +mod my_mod_inner { + #![coverage = "off"] //~ ERROR malformed `coverage` attribute input +} + +#[coverage = "off"] +//~^ ERROR `#[coverage]` must be applied to coverable code +//~| ERROR malformed `coverage` attribute input +struct MyStruct; + +#[coverage = "off"] //~ ERROR malformed `coverage` attribute input +impl MyStruct { + #[coverage = "off"] + //~^ ERROR `#[coverage]` must be applied to coverable code + //~| ERROR malformed `coverage` attribute input + const X: u32 = 7; +} + +#[coverage = "off"] //~ ERROR malformed `coverage` attribute input +trait MyTrait { + #[coverage = "off"] + //~^ ERROR `#[coverage]` must be applied to coverable code + //~| ERROR malformed `coverage` attribute input + const X: u32; + + #[coverage = "off"] + //~^ ERROR `#[coverage]` must be applied to coverable code + //~| ERROR malformed `coverage` attribute input + type T; +} + +#[coverage = "off"] //~ ERROR malformed `coverage` attribute input +impl MyTrait for MyStruct { + #[coverage = "off"] + //~^ ERROR `#[coverage]` must be applied to coverable code + //~| ERROR malformed `coverage` attribute input + const X: u32 = 8; + + #[coverage = "off"] + //~^ ERROR `#[coverage]` must be applied to coverable code + //~| ERROR malformed `coverage` attribute input + type T = (); +} + +#[coverage = "off"] +//~^ ERROR expected `coverage(off)` or `coverage(on)` +//~| ERROR malformed `coverage` attribute input +fn main() {} diff --git a/tests/ui/coverage-attr/name-value.stderr b/tests/ui/coverage-attr/name-value.stderr new file mode 100644 index 00000000000..90bc3a3b53b --- /dev/null +++ b/tests/ui/coverage-attr/name-value.stderr @@ -0,0 +1,219 @@ +error: malformed `coverage` attribute input + --> $DIR/name-value.rs:15:1 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(on|off)] + | ~~~~~~~~~~~~~~~~~~~ +LL | #[coverage] + | ~~~~~~~~~~~ + +error: malformed `coverage` attribute input + --> $DIR/name-value.rs:19:5 + | +LL | #![coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #![coverage(on|off)] + | ~~~~~~~~~~~~~~~~~~~~ +LL | #![coverage] + | ~~~~~~~~~~~~ + +error: malformed `coverage` attribute input + --> $DIR/name-value.rs:22:1 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(on|off)] + | +LL | #[coverage] + | + +error: malformed `coverage` attribute input + --> $DIR/name-value.rs:29:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(on|off)] + | +LL | #[coverage] + | + +error: malformed `coverage` attribute input + --> $DIR/name-value.rs:27:1 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(on|off)] + | ~~~~~~~~~~~~~~~~~~~ +LL | #[coverage] + | ~~~~~~~~~~~ + +error: malformed `coverage` attribute input + --> $DIR/name-value.rs:37:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(on|off)] + | +LL | #[coverage] + | + +error: malformed `coverage` attribute input + --> $DIR/name-value.rs:42:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(on|off)] + | +LL | #[coverage] + | + +error: malformed `coverage` attribute input + --> $DIR/name-value.rs:35:1 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(on|off)] + | ~~~~~~~~~~~~~~~~~~~ +LL | #[coverage] + | ~~~~~~~~~~~ + +error: malformed `coverage` attribute input + --> $DIR/name-value.rs:50:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(on|off)] + | +LL | #[coverage] + | + +error: malformed `coverage` attribute input + --> $DIR/name-value.rs:55:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(on|off)] + | +LL | #[coverage] + | + +error: malformed `coverage` attribute input + --> $DIR/name-value.rs:48:1 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(on|off)] + | ~~~~~~~~~~~~~~~~~~~ +LL | #[coverage] + | ~~~~~~~~~~~ + +error: malformed `coverage` attribute input + --> $DIR/name-value.rs:61:1 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(on|off)] + | +LL | #[coverage] + | + +error[E0788]: `#[coverage]` must be applied to coverable code + --> $DIR/name-value.rs:22:1 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ +... +LL | struct MyStruct; + | ---------------- not coverable code + +error[E0788]: `#[coverage]` must be applied to coverable code + --> $DIR/name-value.rs:37:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ +... +LL | const X: u32; + | ------------- not coverable code + +error[E0788]: `#[coverage]` must be applied to coverable code + --> $DIR/name-value.rs:42:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ +... +LL | type T; + | ------- not coverable code + +error[E0788]: `#[coverage]` must be applied to coverable code + --> $DIR/name-value.rs:29:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ +... +LL | const X: u32 = 7; + | ----------------- not coverable code + +error[E0788]: `#[coverage]` must be applied to coverable code + --> $DIR/name-value.rs:50:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ +... +LL | const X: u32 = 8; + | ----------------- not coverable code + +error[E0788]: `#[coverage]` must be applied to coverable code + --> $DIR/name-value.rs:55:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ +... +LL | type T = (); + | ------------ not coverable code + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/name-value.rs:61:1 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 19 previous errors + +For more information about this error, try `rustc --explain E0788`. diff --git a/tests/ui/coverage-attr/subword.rs b/tests/ui/coverage-attr/subword.rs new file mode 100644 index 00000000000..98b8c25113c --- /dev/null +++ b/tests/ui/coverage-attr/subword.rs @@ -0,0 +1,19 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 + +// Check that yes/no in `#[coverage(yes)]` and `#[coverage(no)]` must be bare +// words, not part of a more complicated substructure. + +#[coverage(yes(milord))] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn yes_list() {} + +#[coverage(no(milord))] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn no_list() {} + +#[coverage(yes = "milord")] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn yes_key() {} + +#[coverage(no = "milord")] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn no_key() {} + +fn main() {} diff --git a/tests/ui/coverage-attr/subword.stderr b/tests/ui/coverage-attr/subword.stderr new file mode 100644 index 00000000000..561573b8ada --- /dev/null +++ b/tests/ui/coverage-attr/subword.stderr @@ -0,0 +1,26 @@ +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/subword.rs:7:1 + | +LL | #[coverage(yes(milord))] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/subword.rs:10:1 + | +LL | #[coverage(no(milord))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/subword.rs:13:1 + | +LL | #[coverage(yes = "milord")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/subword.rs:16:1 + | +LL | #[coverage(no = "milord")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/coverage-attr/word-only.rs b/tests/ui/coverage-attr/word-only.rs new file mode 100644 index 00000000000..5c723b1b6b6 --- /dev/null +++ b/tests/ui/coverage-attr/word-only.rs @@ -0,0 +1,54 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 + +// Demonstrates the diagnostics produced when using the syntax `#[coverage]`, +// which should not be allowed. +// +// The syntax is tested both in places that can have a coverage attribute, +// and in places that cannot have a coverage attribute, to demonstrate the +// interaction between multiple errors. + +// FIXME(#126658): The error messages for using this syntax give the impression +// that it is legal, even though it should never be legal. + +// FIXME(#126658): This is silently allowed, but should not be. +#[coverage] +mod my_mod {} + +// FIXME(#126658): This is silently allowed, but should not be. +mod my_mod_inner { + #![coverage] +} + +#[coverage] //~ ERROR `#[coverage]` must be applied to coverable code +struct MyStruct; + +// FIXME(#126658): This is silently allowed, but should not be. +#[coverage] +impl MyStruct { + #[coverage] //~ ERROR `#[coverage]` must be applied to coverable code + const X: u32 = 7; +} + +// FIXME(#126658): This is silently allowed, but should not be. +#[coverage] +trait MyTrait { + #[coverage] //~ ERROR `#[coverage]` must be applied to coverable code + const X: u32; + + #[coverage] //~ ERROR `#[coverage]` must be applied to coverable code + type T; +} + +// FIXME(#126658): This is silently allowed, but should not be. +#[coverage] +impl MyTrait for MyStruct { + #[coverage] //~ ERROR `#[coverage]` must be applied to coverable code + const X: u32 = 8; + + #[coverage] //~ ERROR `#[coverage]` must be applied to coverable code + type T = (); +} + +#[coverage] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn main() {} diff --git a/tests/ui/coverage-attr/word-only.stderr b/tests/ui/coverage-attr/word-only.stderr new file mode 100644 index 00000000000..bcafc23bc8d --- /dev/null +++ b/tests/ui/coverage-attr/word-only.stderr @@ -0,0 +1,57 @@ +error[E0788]: `#[coverage]` must be applied to coverable code + --> $DIR/word-only.rs:23:1 + | +LL | #[coverage] + | ^^^^^^^^^^^ +LL | struct MyStruct; + | ---------------- not coverable code + +error[E0788]: `#[coverage]` must be applied to coverable code + --> $DIR/word-only.rs:36:5 + | +LL | #[coverage] + | ^^^^^^^^^^^ +LL | const X: u32; + | ------------- not coverable code + +error[E0788]: `#[coverage]` must be applied to coverable code + --> $DIR/word-only.rs:39:5 + | +LL | #[coverage] + | ^^^^^^^^^^^ +LL | type T; + | ------- not coverable code + +error[E0788]: `#[coverage]` must be applied to coverable code + --> $DIR/word-only.rs:29:5 + | +LL | #[coverage] + | ^^^^^^^^^^^ +LL | const X: u32 = 7; + | ----------------- not coverable code + +error[E0788]: `#[coverage]` must be applied to coverable code + --> $DIR/word-only.rs:46:5 + | +LL | #[coverage] + | ^^^^^^^^^^^ +LL | const X: u32 = 8; + | ----------------- not coverable code + +error[E0788]: `#[coverage]` must be applied to coverable code + --> $DIR/word-only.rs:49:5 + | +LL | #[coverage] + | ^^^^^^^^^^^ +LL | type T = (); + | ------------ not coverable code + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/word-only.rs:53:1 + | +LL | #[coverage] + | ^^^^^^^^^^^ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0788`. diff --git a/tests/ui/error-codes/E0116.stderr b/tests/ui/error-codes/E0116.stderr index bf215435ba6..1ea5a57f46d 100644 --- a/tests/ui/error-codes/E0116.stderr +++ b/tests/ui/error-codes/E0116.stderr @@ -2,7 +2,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher --> $DIR/E0116.rs:1:1 | LL | impl Vec<u8> {} - | ^^^^^^^^^^^^ impl for type defined outside of crate. + | ^^^^^^^^^^^^ impl for type defined outside of crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/error-codes/E0519.stderr b/tests/ui/error-codes/E0519.stderr index 4fbd268134f..a814277cafa 100644 --- a/tests/ui/error-codes/E0519.stderr +++ b/tests/ui/error-codes/E0519.stderr @@ -1,4 +1,4 @@ -error[E0519]: the current crate is indistinguishable from one of its dependencies: it has the same crate-name `crateresolve1` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two. +error[E0519]: the current crate is indistinguishable from one of its dependencies: it has the same crate-name `crateresolve1` and was compiled with the same `-C metadata` arguments, so this will result in symbol conflicts between the two --> $DIR/E0519.rs:8:1 | LL | extern crate crateresolve1; diff --git a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs index eab134a4a4d..3ea62e875b8 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs +++ b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs @@ -2,4 +2,12 @@ unsafe extern "C" { //~^ ERROR extern block cannot be declared unsafe } +// We can't gate `unsafe extern` blocks themselves since they were previously +// allowed, but we should gate the `safe` soft keyword. +#[cfg(any())] +unsafe extern "C" { + safe fn foo(); + //~^ ERROR `unsafe extern {}` blocks and `safe` keyword are experimental +} + fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr index 7e9b199a2db..84f00827c60 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr +++ b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr @@ -4,5 +4,16 @@ error: extern block cannot be declared unsafe LL | unsafe extern "C" { | ^^^^^^ -error: aborting due to 1 previous error +error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental + --> $DIR/feature-gate-unsafe-extern-blocks.rs:9:5 + | +LL | safe fn foo(); + | ^^^^ + | + = note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information + = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 30039267979..88732f75cb4 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -186,7 +186,7 @@ warning: unknown lint: `x5100` LL | #[deny(x5100)] impl S { } | ^^^^^ -warning: use of deprecated attribute `crate_id`: no longer used. +warning: use of deprecated attribute `crate_id`: no longer used --> $DIR/issue-43106-gating-of-builtin-attrs.rs:84:1 | LL | #![crate_id = "10"] @@ -194,7 +194,7 @@ LL | #![crate_id = "10"] | = note: `#[warn(deprecated)]` on by default -warning: use of deprecated attribute `no_start`: no longer used. +warning: use of deprecated attribute `no_start`: no longer used --> $DIR/issue-43106-gating-of-builtin-attrs.rs:94:1 | LL | #![no_start] diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs index 3487bac5282..38ade060cb1 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs @@ -4,6 +4,8 @@ // via `.contains(...)` and make sure the dynamic semantics match. #![allow(unreachable_patterns)] +#![feature(f128)] +#![feature(f16)] macro_rules! yes { ($scrutinee:expr, $($t:tt)+) => { @@ -39,6 +41,17 @@ fn range_to_inclusive() { assert!(yes!('a', ..='a')); assert!(!yes!('b', ..='a')); + // f16; `..=X` + // FIXME(f16_f128): remove gate when ABI issues are resolved + #[cfg(all(target_arch = "aarch64", target_os = "linux"))] + { + // FIXME(f16_f128): enable infinity tests when constants are available + // assert!(yes!(f16::NEG_INFINITY, ..=f16::NEG_INFINITY)); + // assert!(yes!(f16::NEG_INFINITY, ..=1.0f16)); + assert!(yes!(1.5f16, ..=1.5f16)); + assert!(!yes!(1.6f16, ..=-1.5f16)); + } + // f32; `..=X` assert!(yes!(f32::NEG_INFINITY, ..=f32::NEG_INFINITY)); assert!(yes!(f32::NEG_INFINITY, ..=1.0f32)); @@ -50,6 +63,17 @@ fn range_to_inclusive() { assert!(yes!(f64::NEG_INFINITY, ..=1.0f64)); assert!(yes!(1.5f64, ..=1.5f64)); assert!(!yes!(1.6f64, ..=-1.5f64)); + + // f128; `..=X` + // FIXME(f16_f128): remove gate when ABI issues are resolved + #[cfg(all(target_arch = "aarch64", target_os = "linux"))] + { + // FIXME(f16_f128): enable infinity tests when constants are available + // assert!(yes!(f128::NEG_INFINITY, ..=f128::NEG_INFINITY)); + // assert!(yes!(f128::NEG_INFINITY, ..=1.0f128)); + assert!(yes!(1.5f128, ..=1.5f128)); + assert!(!yes!(1.6f128, ..=-1.5f128)); + } } fn range_to() { @@ -83,6 +107,18 @@ fn range_to() { assert!(!yes!('a', ..'a')); assert!(!yes!('b', ..'a')); + // f16; `..X` + // FIXME(f16_f128): remove gate when ABI issues are resolved + #[cfg(all(target_arch = "aarch64", target_os = "linux"))] + { + // FIXME(f16_f128): enable infinity tests when constants are available + // assert!(yes!(f16::NEG_INFINITY, ..1.0f16)); + assert!(!yes!(1.5f16, ..1.5f16)); + const E16: f16 = 1.5f16 + f16::EPSILON; + assert!(yes!(1.5f16, ..E16)); + assert!(!yes!(1.6f16, ..1.5f16)); + } + // f32; `..X` assert!(yes!(f32::NEG_INFINITY, ..1.0f32)); assert!(!yes!(1.5f32, ..1.5f32)); @@ -96,6 +132,18 @@ fn range_to() { const E64: f64 = 1.5f64 + f64::EPSILON; assert!(yes!(1.5f64, ..E64)); assert!(!yes!(1.6f64, ..1.5f64)); + + // f128; `..X` + // FIXME(f16_f128): remove gate when ABI issues are resolved + #[cfg(all(target_arch = "aarch64", target_os = "linux"))] + { + // FIXME(f16_f128): enable infinity tests when constants are available + // assert!(yes!(f128::NEG_INFINITY, ..1.0f128)); + assert!(!yes!(1.5f128, ..1.5f128)); + const E128: f128 = 1.5f128 + f128::EPSILON; + assert!(yes!(1.5f128, ..E128)); + assert!(!yes!(1.6f128, ..1.5f128)); + } } fn range_from() { @@ -129,6 +177,21 @@ fn range_from() { assert!(!yes!('a', 'b'..)); assert!(yes!(core::char::MAX, core::char::MAX..)); + // f16; `X..` + // FIXME(f16_f128): remove gate when ABI issues are resolved + #[cfg(all(target_arch = "aarch64", target_os = "linux"))] + { + // FIXME(f16_f128): enable infinity tests when constants are available + // assert!(yes!(f16::NEG_INFINITY, f16::NEG_INFINITY..)); + // assert!(yes!(f16::INFINITY, f16::NEG_INFINITY..)); + // assert!(!yes!(f16::NEG_INFINITY, 1.0f16..)); + // assert!(yes!(f16::INFINITY, 1.0f16..)); + assert!(!yes!(1.0f16 - f16::EPSILON, 1.0f16..)); + assert!(yes!(1.0f16, 1.0f16..)); + // assert!(yes!(f16::INFINITY, 1.0f16..)); + // assert!(yes!(f16::INFINITY, f16::INFINITY..)); + } + // f32; `X..` assert!(yes!(f32::NEG_INFINITY, f32::NEG_INFINITY..)); assert!(yes!(f32::INFINITY, f32::NEG_INFINITY..)); @@ -148,6 +211,21 @@ fn range_from() { assert!(yes!(1.0f64, 1.0f64..)); assert!(yes!(f64::INFINITY, 1.0f64..)); assert!(yes!(f64::INFINITY, f64::INFINITY..)); + + // f128; `X..` + // FIXME(f16_f128): remove gate when ABI issues are resolved + #[cfg(all(target_arch = "aarch64", target_os = "linux"))] + { + // FIXME(f16_f128): enable infinity tests when constants are available + // assert!(yes!(f128::NEG_INFINITY, f128::NEG_INFINITY..)); + // assert!(yes!(f128::INFINITY, f128::NEG_INFINITY..)); + // assert!(!yes!(f128::NEG_INFINITY, 1.0f128..)); + // assert!(yes!(f128::INFINITY, 1.0f128..)); + assert!(!yes!(1.0f128 - f128::EPSILON, 1.0f128..)); + assert!(yes!(1.0f128, 1.0f128..)); + // assert!(yes!(f128::INFINITY, 1.0f128..)); + // assert!(yes!(f128::INFINITY, f128::INFINITY..)); + } } fn main() { diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs index 9ca8dd25ed7..a35bb51acbc 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs @@ -27,6 +27,7 @@ fn main() { m!(0, ..i128::MIN); //~^ ERROR lower range bound must be less than upper + // FIXME(f16_f128): add tests when NEG_INFINITY is available m!(0f32, ..f32::NEG_INFINITY); //~^ ERROR lower range bound must be less than upper m!(0f64, ..f64::NEG_INFINITY); diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr index 668b5c858f0..fb2f1841a6d 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr @@ -59,19 +59,19 @@ LL | m!(0, ..i128::MIN); | ^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:14 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:31:14 | LL | m!(0f32, ..f32::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:32:14 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:14 | LL | m!(0f64, ..f64::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:35:13 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:36:13 | LL | m!('a', ..'\u{0}'); | ^^^^^^^^^ diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.next.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.next.stderr new file mode 100644 index 00000000000..72646b7bc76 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.next.stderr @@ -0,0 +1,9 @@ +error[E0284]: type annotations needed: cannot satisfy `Foo == _` + --> $DIR/norm-before-method-resolution-opaque-type.rs:16:19 + | +LL | fn weird_bound<X>(x: &<X as Trait<'static>>::Out<Foo>) -> X + | ^ cannot satisfy `Foo == _` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.old.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.old.stderr new file mode 100644 index 00000000000..dbd0d5dc733 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.old.stderr @@ -0,0 +1,36 @@ +error: item does not constrain `Foo::{opaque#0}`, but has it in its signature + --> $DIR/norm-before-method-resolution-opaque-type.rs:16:4 + | +LL | fn weird_bound<X>(x: &<X as Trait<'static>>::Out<Foo>) -> X + | ^^^^^^^^^^^ + | + = note: consider moving the opaque type's declaration and defining uses into a separate module +note: this opaque type is in the signature + --> $DIR/norm-before-method-resolution-opaque-type.rs:13:12 + | +LL | type Foo = impl Sized; + | ^^^^^^^^^^ + +error: unconstrained opaque type + --> $DIR/norm-before-method-resolution-opaque-type.rs:13:12 + | +LL | type Foo = impl Sized; + | ^^^^^^^^^^ + | + = note: `Foo` must be used in combination with a concrete type within the same module + +error[E0507]: cannot move out of `*x` which is behind a shared reference + --> $DIR/norm-before-method-resolution-opaque-type.rs:23:13 + | +LL | let x = *x; + | ^^ move occurs because `*x` has type `<X as Trait<'_>>::Out<Foo>`, which does not implement the `Copy` trait + | +help: consider removing the dereference here + | +LL - let x = *x; +LL + let x = x; + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.rs new file mode 100644 index 00000000000..cf752f814c9 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.rs @@ -0,0 +1,29 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver + +#![feature(type_alias_impl_trait)] +trait Trait<'a> { + type Out<U>; +} + +impl<'a, T> Trait<'a> for T { + type Out<U> = T; +} + +type Foo = impl Sized; +//[old]~^ ERROR: unconstrained opaque type + +fn weird_bound<X>(x: &<X as Trait<'static>>::Out<Foo>) -> X +//[old]~^ ERROR: item does not constrain +//[next]~^^ ERROR: cannot satisfy `Foo == _` +where + for<'a> X: Trait<'a>, + for<'a> <X as Trait<'a>>::Out<()>: Copy, +{ + let x = *x; //[old]~ ERROR: cannot move out of `*x` + todo!(); +} + +fn main() { + let _: () = weird_bound(&()); +} diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs index e1aa1babdbb..f0e13a74b2c 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs @@ -1,6 +1,6 @@ //@ check-pass -// Should pass, but we normalize and check bounds before we resolve the generics +// We normalize and check bounds before we resolve the generics // of the function (which we know because of the return type). trait Trait<'a> { @@ -12,10 +12,12 @@ impl<'a, T> Trait<'a> for T { } fn weird_bound<X>() -> X - where - for<'a> X: Trait<'a>, - for<'a> <X as Trait<'a>>::Out: Copy -{ todo!() } +where + for<'a> X: Trait<'a>, + for<'a> <X as Trait<'a>>::Out: Copy, +{ + todo!() +} fn main() { let _: () = weird_bound(); diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index 5e3c0ea054b..73f4d4c3885 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -4,6 +4,12 @@ error: `~const` can only be applied to `#[const_trait]` traits LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { | ^^^^^^^^^^^^^^^^^ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/normalize-tait-in-const.rs:27:69 + | +LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { + | ^^^^^^^^ + error[E0015]: cannot call non-const closure in constant functions --> $DIR/normalize-tait-in-const.rs:28:5 | @@ -29,7 +35,7 @@ LL | fun(filter_positive()); LL | } | - value is dropped here -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0015, E0493. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/impl-trait/upvar_captures.rs b/tests/ui/impl-trait/upvar_captures.rs new file mode 100644 index 00000000000..61e3cda66f5 --- /dev/null +++ b/tests/ui/impl-trait/upvar_captures.rs @@ -0,0 +1,16 @@ +//! This test used to ICE: rust-lang/rust#123255 +//! Because the errors on `C` were ignored when trying +//! to compute the MIR of the closure, which thus ended +//! up with broken upvars. +//@ edition:2021 +#![crate_type = "lib"] + +pub fn a() {} + +mod handlers { + pub struct C(&()); //~ ERROR missing lifetime specifier + pub fn c() -> impl Fn() -> C { + let a1 = (); + || C((crate::a(), a1).into()) + } +} diff --git a/tests/ui/impl-trait/upvar_captures.stderr b/tests/ui/impl-trait/upvar_captures.stderr new file mode 100644 index 00000000000..b87a16606cc --- /dev/null +++ b/tests/ui/impl-trait/upvar_captures.stderr @@ -0,0 +1,14 @@ +error[E0106]: missing lifetime specifier + --> $DIR/upvar_captures.rs:11:18 + | +LL | pub struct C(&()); + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | pub struct C<'a>(&'a ()); + | ++++ ++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/imports/issue-59764.stderr b/tests/ui/imports/issue-59764.stderr index 293c2a60d80..74525c9c88f 100644 --- a/tests/ui/imports/issue-59764.stderr +++ b/tests/ui/imports/issue-59764.stderr @@ -209,7 +209,7 @@ help: a macro with this name exists at the root of the crate | LL ~ issue_59764::{makro as foobar, LL | - ... +... LL | LL ~ foo::{baz} | diff --git a/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr b/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr index 6dc1680cf89..f8491697910 100644 --- a/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr +++ b/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr @@ -2,7 +2,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher --> $DIR/no-attr-empty-impl.rs:4:1 | LL | impl extern_crate::StructWithAttr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | = note: define and implement a trait or new type instead @@ -10,7 +10,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher --> $DIR/no-attr-empty-impl.rs:7:1 | LL | impl extern_crate::StructNoAttr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | = note: define and implement a trait or new type instead @@ -18,7 +18,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher --> $DIR/no-attr-empty-impl.rs:10:1 | LL | impl extern_crate::EnumWithAttr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | = note: define and implement a trait or new type instead @@ -26,7 +26,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher --> $DIR/no-attr-empty-impl.rs:13:1 | LL | impl extern_crate::EnumNoAttr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/inference/issue-83606.stderr b/tests/ui/inference/issue-83606.stderr index 8e6ff6d568d..69d1d71ef3c 100644 --- a/tests/ui/inference/issue-83606.stderr +++ b/tests/ui/inference/issue-83606.stderr @@ -1,9 +1,14 @@ -error[E0282]: type annotations needed for `[usize; _]` +error[E0284]: type annotations needed for `[usize; _]` --> $DIR/issue-83606.rs:8:9 | LL | let _ = foo("foo"); - | ^ + | ^ ---------- type must be known at this point | +note: required by a const generic parameter in `foo` + --> $DIR/issue-83606.rs:3:8 + | +LL | fn foo<const N: usize>(_: impl std::fmt::Display) -> [usize; N] { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `foo` help: consider giving this pattern a type, where the value of const parameter `N` is specified | LL | let _: [usize; N] = foo("foo"); @@ -11,4 +16,4 @@ LL | let _: [usize; N] = foo("foo"); error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr index 5df6aaf9804..15fa3f6ee11 100644 --- a/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr +++ b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr @@ -1,4 +1,4 @@ -warning: Number of conditions in decision (7) exceeds limit (6). MC/DC analysis will not count this expression. +warning: number of conditions in decision (7) exceeds limit (6), so MC/DC analysis will not count this expression --> $DIR/mcdc-condition-limit.rs:29:8 | LL | if a && b && c && d && e && f && g { diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.rs b/tests/ui/instrument-coverage/mcdc-condition-limit.rs index de3770b5709..eb19ddec78f 100644 --- a/tests/ui/instrument-coverage/mcdc-condition-limit.rs +++ b/tests/ui/instrument-coverage/mcdc-condition-limit.rs @@ -26,7 +26,7 @@ fn main() { fn main() { // 7 conditions is too many, so issue a diagnostic. let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); - if a && b && c && d && e && f && g { //[bad]~ WARNING Number of conditions in decision + if a && b && c && d && e && f && g { //[bad]~ WARNING number of conditions in decision core::hint::black_box("hello"); } } diff --git a/tests/ui/intrinsics/not-overridden.rs b/tests/ui/intrinsics/not-overridden.rs index d6655b51905..a53071e304d 100644 --- a/tests/ui/intrinsics/not-overridden.rs +++ b/tests/ui/intrinsics/not-overridden.rs @@ -1,6 +1,6 @@ //! Check that intrinsics that do not get overridden, but are marked as such, //! cause an error instead of silently invoking the body. -#![feature(rustc_attrs, effects)] +#![feature(rustc_attrs/* , effects*/)] // FIXME(effects) //@ build-fail //@ failure-status:101 //@ normalize-stderr-test ".*note: .*\n\n" -> "" diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs index 23cd5f10835..c116ba7a62e 100644 --- a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs +++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs @@ -1,6 +1,6 @@ #![feature(intrinsics)] #![feature(rustc_attrs)] -#![feature(effects)] +// FIXME(effects) do this with revisions #![feature(effects)] extern "rust-intrinsic" { fn size_of<T>() -> usize; //~ ERROR intrinsic safety mismatch @@ -19,7 +19,7 @@ const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} mod foo { #[rustc_intrinsic] unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} - //~^ ERROR wrong number of const parameters + // FIXME(effects) ~^ ERROR wrong number of const parameters } fn main() {} diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr index d73d5bab8d7..7f37e0f8211 100644 --- a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr +++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr @@ -42,13 +42,6 @@ LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} = note: expected signature `unsafe fn(_, _, _)` found signature `fn(_, _, _)` -error[E0094]: intrinsic has wrong number of const parameters: found 0, expected 1 - --> $DIR/safe-intrinsic-mismatch.rs:21:31 - | -LL | unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} - | ^ expected 1 const parameter - -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0094, E0308. -For more information about an error, try `rustc --explain E0094`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/issues/issue-22644.stderr b/tests/ui/issues/issue-22644.stderr index 7d8a0ff170a..c6d41cc856d 100644 --- a/tests/ui/issues/issue-22644.stderr +++ b/tests/ui/issues/issue-22644.stderr @@ -64,7 +64,7 @@ help: try comparing the cast value | LL ~ println!("{}", (a LL | - ... +... LL | LL ~ usize) | diff --git a/tests/ui/issues/issue-57271.stderr b/tests/ui/issues/issue-57271.stderr index 10cbb34ef5d..a61419c61d7 100644 --- a/tests/ui/issues/issue-57271.stderr +++ b/tests/ui/issues/issue-57271.stderr @@ -17,7 +17,7 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | LL ~ Array(Box<TypeSignature>), LL | TypeVariable(()), - ... +... LL | Base(BaseType), LL ~ Object(Box<ObjectType>), | diff --git a/tests/ui/issues/issue-98299.rs b/tests/ui/issues/issue-98299.rs index 63c058f91fc..ba63d963475 100644 --- a/tests/ui/issues/issue-98299.rs +++ b/tests/ui/issues/issue-98299.rs @@ -3,6 +3,8 @@ use std::convert::TryFrom; pub fn test_usage(p: ()) { SmallCString::try_from(p).map(|cstr| cstr); //~^ ERROR: type annotations needed + //~| ERROR: type annotations needed + //~| ERROR: type annotations needed } pub struct SmallCString<const N: usize> {} diff --git a/tests/ui/issues/issue-98299.stderr b/tests/ui/issues/issue-98299.stderr index becf16d1db9..b645267e3b9 100644 --- a/tests/ui/issues/issue-98299.stderr +++ b/tests/ui/issues/issue-98299.stderr @@ -1,14 +1,61 @@ -error[E0282]: type annotations needed for `SmallCString<_>` +error[E0284]: type annotations needed for `SmallCString<_>` --> $DIR/issue-98299.rs:4:36 | LL | SmallCString::try_from(p).map(|cstr| cstr); - | ^^^^ + | ------------ ^^^^ + | | + | type must be known at this point | +note: required by a const generic parameter in `SmallCString` + --> $DIR/issue-98299.rs:10:25 + | +LL | pub struct SmallCString<const N: usize> {} + | ^^^^^^^^^^^^^^ required by this const generic parameter in `SmallCString` +help: consider giving this closure parameter an explicit type, where the value of const parameter `N` is specified + | +LL | SmallCString::try_from(p).map(|cstr: SmallCString<N>| cstr); + | +++++++++++++++++ + +error[E0284]: type annotations needed for `SmallCString<_>` + --> $DIR/issue-98299.rs:4:36 + | +LL | SmallCString::try_from(p).map(|cstr| cstr); + | ------------ ^^^^ + | | + | type must be known at this point + | +note: required for `SmallCString<_>` to implement `TryFrom<()>` + --> $DIR/issue-98299.rs:12:22 + | +LL | impl<const N: usize> TryFrom<()> for SmallCString<N> { + | -------------- ^^^^^^^^^^^ ^^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here +help: consider giving this closure parameter an explicit type, where the value of const parameter `N` is specified + | +LL | SmallCString::try_from(p).map(|cstr: SmallCString<N>| cstr); + | +++++++++++++++++ + +error[E0284]: type annotations needed for `SmallCString<_>` + --> $DIR/issue-98299.rs:4:36 + | +LL | SmallCString::try_from(p).map(|cstr| cstr); + | ------------------------- ^^^^ + | | + | type must be known at this point + | +note: required for `SmallCString<_>` to implement `TryFrom<()>` + --> $DIR/issue-98299.rs:12:22 + | +LL | impl<const N: usize> TryFrom<()> for SmallCString<N> { + | -------------- ^^^^^^^^^^^ ^^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here help: consider giving this closure parameter an explicit type, where the value of const parameter `N` is specified | LL | SmallCString::try_from(p).map(|cstr: SmallCString<N>| cstr); | +++++++++++++++++ -error: aborting due to 1 previous error +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/let-else/let-else-if.stderr b/tests/ui/let-else/let-else-if.stderr index c8058ec6692..7e2215c8c05 100644 --- a/tests/ui/let-else/let-else-if.stderr +++ b/tests/ui/let-else/let-else-if.stderr @@ -8,7 +8,7 @@ help: try placing this code inside a block | LL ~ let Some(_) = Some(()) else { if true { LL | - ... +... LL | return; LL ~ } }; | diff --git a/tests/ui/lifetimes/no_lending_iterators.stderr b/tests/ui/lifetimes/no_lending_iterators.stderr index c3784770d79..9ceaef2f9b1 100644 --- a/tests/ui/lifetimes/no_lending_iterators.stderr +++ b/tests/ui/lifetimes/no_lending_iterators.stderr @@ -4,7 +4,7 @@ error: associated type `Iterator::Item` is declared without lifetime parameters, LL | type Item = &str; | ^ | -note: you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type. +note: you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type --> $DIR/no_lending_iterators.rs:3:19 | LL | impl Iterator for Data { diff --git a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs index 69b8f286d77..cdfd35304b4 100644 --- a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs +++ b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs @@ -3,6 +3,7 @@ //@ [edition2024] compile-flags: -Zunstable-options //@ [edition2024] edition: 2024 //@ run-pass +//@ needs-unwind #![cfg_attr(edition2024, feature(shorter_tail_lifetimes))] use std::sync::Mutex; diff --git a/tests/ui/lint/expect-future_breakage-crash-issue-126521.rs b/tests/ui/lint/expect-future_breakage-crash-issue-126521.rs new file mode 100644 index 00000000000..0e622ff3aaf --- /dev/null +++ b/tests/ui/lint/expect-future_breakage-crash-issue-126521.rs @@ -0,0 +1,23 @@ +// This test covers similar crashes from both #126521 and #126751. + +macro_rules! foo { + ($val:ident) => { + true; + }; +} + +macro_rules! bar { + ($val:ident) => { + (5_i32.overflowing_sub(3)); + }; +} + +fn main() { + #[expect(semicolon_in_expressions_from_macros)] + //~^ ERROR the `#[expect]` attribute is an experimental feature + let _ = foo!(x); + + #[expect(semicolon_in_expressions_from_macros)] + //~^ ERROR the `#[expect]` attribute is an experimental feature + let _ = bar!(x); +} diff --git a/tests/ui/lint/expect-future_breakage-crash-issue-126521.stderr b/tests/ui/lint/expect-future_breakage-crash-issue-126521.stderr new file mode 100644 index 00000000000..994630ec23b --- /dev/null +++ b/tests/ui/lint/expect-future_breakage-crash-issue-126521.stderr @@ -0,0 +1,23 @@ +error[E0658]: the `#[expect]` attribute is an experimental feature + --> $DIR/expect-future_breakage-crash-issue-126521.rs:16:5 + | +LL | #[expect(semicolon_in_expressions_from_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information + = help: add `#![feature(lint_reasons)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `#[expect]` attribute is an experimental feature + --> $DIR/expect-future_breakage-crash-issue-126521.rs:20:5 + | +LL | #[expect(semicolon_in_expressions_from_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information + = help: add `#![feature(lint_reasons)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/lint/lint-attr-everywhere-late.stderr b/tests/ui/lint/lint-attr-everywhere-late.stderr index 7fe078068fe..ddc31905afb 100644 --- a/tests/ui/lint/lint-attr-everywhere-late.stderr +++ b/tests/ui/lint/lint-attr-everywhere-late.stderr @@ -154,7 +154,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | fn assoc_fn() { discriminant::<i32>(&123); } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:96:41 | LL | fn assoc_fn() { discriminant::<i32>(&123); } @@ -208,7 +208,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | let _ = discriminant::<i32>(&123); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:139:33 | LL | let _ = discriminant::<i32>(&123); @@ -237,7 +237,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant::<i32>(&123); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:155:33 | LL | discriminant::<i32>(&123); @@ -254,7 +254,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant::<i32>(&123); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:161:33 | LL | discriminant::<i32>(&123); @@ -283,7 +283,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant::<i32>(&123); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:173:29 | LL | discriminant::<i32>(&123); @@ -300,7 +300,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant::<i32>(&123); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:177:29 | LL | discriminant::<i32>(&123); @@ -317,7 +317,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant::<i32>(&123); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:182:25 | LL | discriminant::<i32>(&123); @@ -334,7 +334,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | [#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123)]; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:184:61 | LL | [#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123)]; @@ -351,7 +351,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | (#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123),); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:185:61 | LL | (#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123),); @@ -368,7 +368,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | call(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:187:65 | LL | call(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123)); @@ -385,7 +385,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:189:72 | LL | TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123)); diff --git a/tests/ui/lint/lint-enum-intrinsics-non-enums.stderr b/tests/ui/lint/lint-enum-intrinsics-non-enums.stderr index 63ed2503cf3..f9eeaebe21f 100644 --- a/tests/ui/lint/lint-enum-intrinsics-non-enums.stderr +++ b/tests/ui/lint/lint-enum-intrinsics-non-enums.stderr @@ -4,7 +4,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant(&()); | ^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `()`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `()`, which is not an enum --> $DIR/lint-enum-intrinsics-non-enums.rs:26:18 | LL | discriminant(&()); @@ -17,7 +17,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant(&&SomeEnum::B); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `&SomeEnum`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `&SomeEnum`, which is not an enum --> $DIR/lint-enum-intrinsics-non-enums.rs:29:18 | LL | discriminant(&&SomeEnum::B); @@ -29,7 +29,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `SomeStruct`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `SomeStruct`, which is not an enum --> $DIR/lint-enum-intrinsics-non-enums.rs:32:18 | LL | discriminant(&SomeStruct); @@ -41,7 +41,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant(&123u32); | ^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `u32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `u32`, which is not an enum --> $DIR/lint-enum-intrinsics-non-enums.rs:35:18 | LL | discriminant(&123u32); @@ -53,7 +53,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant(&&123i8); | ^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `&i8`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `&i8`, which is not an enum --> $DIR/lint-enum-intrinsics-non-enums.rs:38:18 | LL | discriminant(&&123i8); @@ -65,7 +65,7 @@ error: the return value of `mem::variant_count` is unspecified when called with LL | variant_count::<&str>(); | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `&str`, which is not an enum. + = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `&str`, which is not an enum error: the return value of `mem::variant_count` is unspecified when called with a non-enum type --> $DIR/lint-enum-intrinsics-non-enums.rs:49:5 @@ -73,7 +73,7 @@ error: the return value of `mem::variant_count` is unspecified when called with LL | variant_count::<*const u8>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `*const u8`, which is not an enum. + = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `*const u8`, which is not an enum error: the return value of `mem::variant_count` is unspecified when called with a non-enum type --> $DIR/lint-enum-intrinsics-non-enums.rs:52:5 @@ -81,7 +81,7 @@ error: the return value of `mem::variant_count` is unspecified when called with LL | variant_count::<()>(); | ^^^^^^^^^^^^^^^^^^^^^ | - = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `()`, which is not an enum. + = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `()`, which is not an enum error: the return value of `mem::variant_count` is unspecified when called with a non-enum type --> $DIR/lint-enum-intrinsics-non-enums.rs:55:5 @@ -89,7 +89,7 @@ error: the return value of `mem::variant_count` is unspecified when called with LL | variant_count::<&SomeEnum>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `&SomeEnum`, which is not an enum. + = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `&SomeEnum`, which is not an enum error: aborting due to 9 previous errors diff --git a/tests/ui/lint/non-local-defs/cargo-update.stderr b/tests/ui/lint/non-local-defs/cargo-update.stderr index afd37d03a23..bccf8622bac 100644 --- a/tests/ui/lint/non-local-defs/cargo-update.stderr +++ b/tests/ui/lint/non-local-defs/cargo-update.stderr @@ -12,7 +12,7 @@ LL | non_local_macro::non_local_impl!(LocalStruct); = note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration + = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> = note: `#[warn(non_local_definitions)]` on by default = note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/lint/non-local-defs/consts.stderr b/tests/ui/lint/non-local-defs/consts.stderr index 2756ea40138..9f70119e0f8 100644 --- a/tests/ui/lint/non-local-defs/consts.stderr +++ b/tests/ui/lint/non-local-defs/consts.stderr @@ -15,7 +15,7 @@ LL | impl Uto for &Test {} | = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration + = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> = note: `#[warn(non_local_definitions)]` on by default @@ -32,7 +32,7 @@ LL | impl Uto2 for Test {} | = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration + = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item @@ -48,7 +48,7 @@ LL | impl Uto3 for Test {} | = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration + = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item @@ -94,7 +94,7 @@ LL | impl Test { | `Test` is not local | = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` - = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration + = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item diff --git a/tests/ui/loops/loop-else-break-with-value.stderr b/tests/ui/loops/loop-else-break-with-value.stderr index 13d4c5faf73..ca18f0fdd7f 100644 --- a/tests/ui/loops/loop-else-break-with-value.stderr +++ b/tests/ui/loops/loop-else-break-with-value.stderr @@ -27,7 +27,7 @@ help: you might want to use `if let` to ignore the variant that isn't matched | LL ~ if let Some(1) = loop { LL | - ... +... LL | return; LL ~ } { todo!() }; | diff --git a/tests/ui/macros/auxiliary/expr_2021_implicit.rs b/tests/ui/macros/auxiliary/expr_2021_implicit.rs new file mode 100644 index 00000000000..61762e41dee --- /dev/null +++ b/tests/ui/macros/auxiliary/expr_2021_implicit.rs @@ -0,0 +1,9 @@ +//@ edition:2021 + +#[macro_export] +macro_rules! m { + ($expr:expr) => { + compile_error!("did not expect an expression to be parsed"); + }; + (const { }) => {}; +} diff --git a/tests/ui/macros/expr_2021_implicit_in_2024.rs b/tests/ui/macros/expr_2021_implicit_in_2024.rs new file mode 100644 index 00000000000..b3f7a31a802 --- /dev/null +++ b/tests/ui/macros/expr_2021_implicit_in_2024.rs @@ -0,0 +1,12 @@ +//@ compile-flags: --edition=2024 -Zunstable-options +//@ aux-build:expr_2021_implicit.rs + +//@ check-pass + +extern crate expr_2021_implicit; + +// Makes sure that a `:expr` fragment matcher defined in a edition 2021 crate +// still parses like an `expr_2021` fragment matcher in a 2024 user crate. +expr_2021_implicit::m!(const {}); + +fn main() {} diff --git a/tests/ui/macros/expr_2021_old_edition.rs b/tests/ui/macros/expr_2021_old_edition.rs deleted file mode 100644 index a7711266106..00000000000 --- a/tests/ui/macros/expr_2021_old_edition.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: --edition=2018 - -// This test ensures that expr_2021 is not allowed on pre-2021 editions - -macro_rules! m { - ($e:expr_2021) => { //~ ERROR: invalid fragment specifier `expr_2021` - $e - }; -} - -fn main() { - m!(()); //~ ERROR: no rules expected the token `(` -} diff --git a/tests/ui/macros/expr_2021_old_edition.stderr b/tests/ui/macros/expr_2021_old_edition.stderr deleted file mode 100644 index bffa8a1ca17..00000000000 --- a/tests/ui/macros/expr_2021_old_edition.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: invalid fragment specifier `expr_2021` - --> $DIR/expr_2021_old_edition.rs:6:6 - | -LL | ($e:expr_2021) => { - | ^^^^^^^^^^^^ - | - = help: fragment specifier `expr_2021` requires Rust 2021 or later - valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis` - -error: no rules expected the token `(` - --> $DIR/expr_2021_old_edition.rs:12:8 - | -LL | macro_rules! m { - | -------------- when calling this macro -... -LL | m!(()); - | ^ no rules expected this token in macro call - | -note: while trying to match meta-variable `$e:ident` - --> $DIR/expr_2021_old_edition.rs:6:6 - | -LL | ($e:expr_2021) => { - | ^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui/match/match-float.rs b/tests/ui/match/match-float.rs index f8514568d15..70283eaeec5 100644 --- a/tests/ui/match/match-float.rs +++ b/tests/ui/match/match-float.rs @@ -1,7 +1,22 @@ //@ run-pass // Makes sure we use `==` (not bitwise) semantics for float comparison. -fn main() { +#![feature(f128)] +#![feature(f16)] + +// FIXME(f16_f128): remove gates when ABI issues are resolved + +#[cfg(all(target_arch = "aarch64", target_os = "linux"))] +fn check_f16() { + const F1: f16 = 0.0; + const F2: f16 = -0.0; + assert_eq!(F1, F2); + assert_ne!(F1.to_bits(), F2.to_bits()); + assert!(matches!(F1, F2)); + assert!(matches!(F2, F1)); +} + +fn check_f32() { const F1: f32 = 0.0; const F2: f32 = -0.0; assert_eq!(F1, F2); @@ -9,3 +24,31 @@ fn main() { assert!(matches!(F1, F2)); assert!(matches!(F2, F1)); } + +fn check_f64() { + const F1: f64 = 0.0; + const F2: f64 = -0.0; + assert_eq!(F1, F2); + assert_ne!(F1.to_bits(), F2.to_bits()); + assert!(matches!(F1, F2)); + assert!(matches!(F2, F1)); +} + +#[cfg(all(target_arch = "aarch64", target_os = "linux"))] +fn check_f128() { + const F1: f128 = 0.0; + const F2: f128 = -0.0; + assert_eq!(F1, F2); + assert_ne!(F1.to_bits(), F2.to_bits()); + assert!(matches!(F1, F2)); + assert!(matches!(F2, F1)); +} + +fn main() { + #[cfg(all(target_arch = "aarch64", target_os = "linux"))] + check_f16(); + check_f32(); + check_f64(); + #[cfg(all(target_arch = "aarch64", target_os = "linux"))] + check_f128(); +} diff --git a/tests/ui/mir/issue-83499-input-output-iteration-ice.rs b/tests/ui/mir/issue-83499-input-output-iteration-ice.rs index 0086d2ec18c..78e5c961802 100644 --- a/tests/ui/mir/issue-83499-input-output-iteration-ice.rs +++ b/tests/ui/mir/issue-83499-input-output-iteration-ice.rs @@ -5,6 +5,6 @@ fn main() {} fn foo(_: Bar, ...) -> impl {} -//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic +//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg //~| ERROR cannot find type `Bar` in this scope //~| ERROR at least one trait must be specified diff --git a/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr b/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr index 4eb3adc8b4f..80a8a94aea4 100644 --- a/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr +++ b/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr @@ -1,4 +1,4 @@ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/issue-83499-input-output-iteration-ice.rs:7:16 | LL | fn foo(_: Bar, ...) -> impl {} diff --git a/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr b/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr index 3247513d42c..cf863ff8af1 100644 --- a/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr +++ b/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr @@ -26,7 +26,7 @@ help: consider moving the expression out of the loop so it is only moved once LL ~ for foo in foos { let mut value = baz.push(foo); LL ~ for bar in &bars { if foo == *bar { LL | - ... +... LL | LL ~ value; | @@ -69,7 +69,7 @@ help: consider moving the expression out of the loop so it is only moved once LL ~ let mut value = baz.push(foo); LL ~ for bar in &bars { LL | - ... +... LL | if foo == *bar { LL ~ value; | diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr b/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr index f2bc8bd8400..7cd6175a5ad 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr +++ b/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr @@ -4,7 +4,7 @@ warning: unnecessary associated type bound for not object safe associated type LL | fn foo(_: &dyn Foo<Bar = ()>) {} | ^^^^^^^^ help: remove this bound | - = note: this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`. + = note: this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized` = note: `#[warn(unused_associated_type_bounds)]` on by default warning: 1 warning emitted diff --git a/tests/ui/panics/abort-on-panic.rs b/tests/ui/panics/abort-on-panic.rs index 5736ecf8685..feccefb2537 100644 --- a/tests/ui/panics/abort-on-panic.rs +++ b/tests/ui/panics/abort-on-panic.rs @@ -4,7 +4,6 @@ //@[next] compile-flags: -Znext-solver #![allow(unused_must_use)] -#![feature(c_unwind)] #![feature(panic_always_abort)] // Since we mark some ABIs as "nounwind" to LLVM, we must make sure that // we never unwind through them. diff --git a/tests/ui/panics/panic-in-ffi.rs b/tests/ui/panics/panic-in-ffi.rs index 6f54acb3e04..88f45f9a871 100644 --- a/tests/ui/panics/panic-in-ffi.rs +++ b/tests/ui/panics/panic-in-ffi.rs @@ -7,7 +7,6 @@ //@ normalize-stderr-test: "(core/src/panicking\.rs):[0-9]+:[0-9]+" -> "$1:$$LINE:$$COL" //@ needs-unwind //@ ignore-emscripten "RuntimeError" junk in output -#![feature(c_unwind)] extern "C" fn panic_in_ffi() { panic!("Test"); diff --git a/tests/ui/panics/panic-in-ffi.run.stderr b/tests/ui/panics/panic-in-ffi.run.stderr index a92a66c57fd..596355399c8 100644 --- a/tests/ui/panics/panic-in-ffi.run.stderr +++ b/tests/ui/panics/panic-in-ffi.run.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at $DIR/panic-in-ffi.rs:13:5: +thread 'main' panicked at $DIR/panic-in-ffi.rs:12:5: Test note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at library/core/src/panicking.rs:$LINE:$COL: diff --git a/tests/ui/parser/diff-markers/enum-2.stderr b/tests/ui/parser/diff-markers/enum-2.stderr index 20e551c2f95..b76cf5d5a01 100644 --- a/tests/ui/parser/diff-markers/enum-2.stderr +++ b/tests/ui/parser/diff-markers/enum-2.stderr @@ -2,20 +2,25 @@ error: encountered diff marker --> $DIR/enum-2.rs:3:1 | LL | <<<<<<< HEAD - | ^^^^^^^ after this is the code before the merge + | ^^^^^^^ between this marker and `|||||||` is the code that we're merging into LL | x: u8, LL | ||||||| - | ------- + | ------- between this marker and `=======` is the base code (what the two refs diverged from) LL | z: (), LL | ======= - | ------- + | ------- between this marker and `>>>>>>>` is the incoming code LL | y: i8, LL | >>>>>>> branch - | ^^^^^^^ above this are the incoming code changes + | ^^^^^^^ this marker concludes the conflict region | - = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code - = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> + = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts + to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers + = help: if you're having merge conflicts after pulling new code: + the top section is the code you already had and the bottom section is the remote code + if you're in the middle of a rebase: + the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased + = note: for an explanation on these markers from the `git` documentation: + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/enum.stderr b/tests/ui/parser/diff-markers/enum.stderr index be94331dce5..0ce473bc702 100644 --- a/tests/ui/parser/diff-markers/enum.stderr +++ b/tests/ui/parser/diff-markers/enum.stderr @@ -2,17 +2,22 @@ error: encountered diff marker --> $DIR/enum.rs:2:1 | LL | <<<<<<< HEAD - | ^^^^^^^ after this is the code before the merge + | ^^^^^^^ between this marker and `=======` is the code that we're merging into LL | Foo(u8), LL | ======= - | ------- + | ------- between this marker and `>>>>>>>` is the incoming code LL | Bar(i8), LL | >>>>>>> branch - | ^^^^^^^ above this are the incoming code changes + | ^^^^^^^ this marker concludes the conflict region | - = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code - = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> + = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts + to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers + = help: if you're having merge conflicts after pulling new code: + the top section is the code you already had and the bottom section is the remote code + if you're in the middle of a rebase: + the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased + = note: for an explanation on these markers from the `git` documentation: + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/fn-arg.stderr b/tests/ui/parser/diff-markers/fn-arg.stderr index aabcb826c12..24521ffa626 100644 --- a/tests/ui/parser/diff-markers/fn-arg.stderr +++ b/tests/ui/parser/diff-markers/fn-arg.stderr @@ -2,17 +2,22 @@ error: encountered diff marker --> $DIR/fn-arg.rs:3:1 | LL | <<<<<<< HEAD - | ^^^^^^^ after this is the code before the merge + | ^^^^^^^ between this marker and `=======` is the code that we're merging into LL | x: u8, LL | ======= - | ------- + | ------- between this marker and `>>>>>>>` is the incoming code LL | x: i8, LL | >>>>>>> branch - | ^^^^^^^ above this are the incoming code changes + | ^^^^^^^ this marker concludes the conflict region | - = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code - = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> + = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts + to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers + = help: if you're having merge conflicts after pulling new code: + the top section is the code you already had and the bottom section is the remote code + if you're in the middle of a rebase: + the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased + = note: for an explanation on these markers from the `git` documentation: + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/item-with-attr.stderr b/tests/ui/parser/diff-markers/item-with-attr.stderr index eefb2792e90..432673cd551 100644 --- a/tests/ui/parser/diff-markers/item-with-attr.stderr +++ b/tests/ui/parser/diff-markers/item-with-attr.stderr @@ -2,17 +2,22 @@ error: encountered diff marker --> $DIR/item-with-attr.rs:2:1 | LL | <<<<<<< HEAD - | ^^^^^^^ after this is the code before the merge + | ^^^^^^^ between this marker and `=======` is the code that we're merging into LL | fn foo() {} LL | ======= - | ------- + | ------- between this marker and `>>>>>>>` is the incoming code LL | fn bar() {} LL | >>>>>>> branch - | ^^^^^^^ above this are the incoming code changes + | ^^^^^^^ this marker concludes the conflict region | - = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code - = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> + = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts + to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers + = help: if you're having merge conflicts after pulling new code: + the top section is the code you already had and the bottom section is the remote code + if you're in the middle of a rebase: + the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased + = note: for an explanation on these markers from the `git` documentation: + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/item.stderr b/tests/ui/parser/diff-markers/item.stderr index a3092ebfcfd..180c74e5d69 100644 --- a/tests/ui/parser/diff-markers/item.stderr +++ b/tests/ui/parser/diff-markers/item.stderr @@ -2,17 +2,22 @@ error: encountered diff marker --> $DIR/item.rs:1:1 | LL | <<<<<<< HEAD - | ^^^^^^^ after this is the code before the merge + | ^^^^^^^ between this marker and `=======` is the code that we're merging into LL | fn foo() {} LL | ======= - | ------- + | ------- between this marker and `>>>>>>>` is the incoming code LL | fn bar() {} LL | >>>>>>> branch - | ^^^^^^^ above this are the incoming code changes + | ^^^^^^^ this marker concludes the conflict region | - = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code - = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> + = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts + to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers + = help: if you're having merge conflicts after pulling new code: + the top section is the code you already had and the bottom section is the remote code + if you're in the middle of a rebase: + the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased + = note: for an explanation on these markers from the `git` documentation: + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/statement.stderr b/tests/ui/parser/diff-markers/statement.stderr index c6c6cae8765..6dccce4a48e 100644 --- a/tests/ui/parser/diff-markers/statement.stderr +++ b/tests/ui/parser/diff-markers/statement.stderr @@ -2,17 +2,22 @@ error: encountered diff marker --> $DIR/statement.rs:10:1 | LL | <<<<<<< HEAD - | ^^^^^^^ after this is the code before the merge + | ^^^^^^^ between this marker and `=======` is the code that we're merging into LL | S::foo(); LL | ======= - | ------- + | ------- between this marker and `>>>>>>>` is the incoming code LL | S::bar(); LL | >>>>>>> branch - | ^^^^^^^ above this are the incoming code changes + | ^^^^^^^ this marker concludes the conflict region | - = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code - = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> + = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts + to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers + = help: if you're having merge conflicts after pulling new code: + the top section is the code you already had and the bottom section is the remote code + if you're in the middle of a rebase: + the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased + = note: for an explanation on these markers from the `git` documentation: + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/struct-expr.stderr b/tests/ui/parser/diff-markers/struct-expr.stderr index bdea8c841c6..3733cdd3496 100644 --- a/tests/ui/parser/diff-markers/struct-expr.stderr +++ b/tests/ui/parser/diff-markers/struct-expr.stderr @@ -2,17 +2,22 @@ error: encountered diff marker --> $DIR/struct-expr.rs:6:1 | LL | <<<<<<< HEAD - | ^^^^^^^ after this is the code before the merge + | ^^^^^^^ between this marker and `=======` is the code that we're merging into LL | x: 42, LL | ======= - | ------- + | ------- between this marker and `>>>>>>>` is the incoming code LL | x: 0, LL | >>>>>>> branch - | ^^^^^^^ above this are the incoming code changes + | ^^^^^^^ this marker concludes the conflict region | - = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code - = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> + = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts + to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers + = help: if you're having merge conflicts after pulling new code: + the top section is the code you already had and the bottom section is the remote code + if you're in the middle of a rebase: + the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased + = note: for an explanation on these markers from the `git` documentation: + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/struct.stderr b/tests/ui/parser/diff-markers/struct.stderr index 749941290cb..44f8346613e 100644 --- a/tests/ui/parser/diff-markers/struct.stderr +++ b/tests/ui/parser/diff-markers/struct.stderr @@ -2,17 +2,22 @@ error: encountered diff marker --> $DIR/struct.rs:2:1 | LL | <<<<<<< HEAD - | ^^^^^^^ after this is the code before the merge + | ^^^^^^^ between this marker and `=======` is the code that we're merging into LL | x: u8, LL | ======= - | ------- + | ------- between this marker and `>>>>>>>` is the incoming code LL | x: i8, LL | >>>>>>> branch - | ^^^^^^^ above this are the incoming code changes + | ^^^^^^^ this marker concludes the conflict region | - = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code - = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> + = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts + to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers + = help: if you're having merge conflicts after pulling new code: + the top section is the code you already had and the bottom section is the remote code + if you're in the middle of a rebase: + the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased + = note: for an explanation on these markers from the `git` documentation: + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/trait-item.stderr b/tests/ui/parser/diff-markers/trait-item.stderr index f01bbe8ba03..4361542c774 100644 --- a/tests/ui/parser/diff-markers/trait-item.stderr +++ b/tests/ui/parser/diff-markers/trait-item.stderr @@ -2,17 +2,22 @@ error: encountered diff marker --> $DIR/trait-item.rs:2:1 | LL | <<<<<<< HEAD - | ^^^^^^^ after this is the code before the merge + | ^^^^^^^ between this marker and `=======` is the code that we're merging into LL | fn foo() {} LL | ======= - | ------- + | ------- between this marker and `>>>>>>>` is the incoming code LL | fn bar() {} LL | >>>>>>> branch - | ^^^^^^^ above this are the incoming code changes + | ^^^^^^^ this marker concludes the conflict region | - = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code - = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> + = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts + to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers + = help: if you're having merge conflicts after pulling new code: + the top section is the code you already had and the bottom section is the remote code + if you're in the middle of a rebase: + the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased + = note: for an explanation on these markers from the `git` documentation: + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/tuple-struct.stderr b/tests/ui/parser/diff-markers/tuple-struct.stderr index 8dae123c96d..7fda24ba485 100644 --- a/tests/ui/parser/diff-markers/tuple-struct.stderr +++ b/tests/ui/parser/diff-markers/tuple-struct.stderr @@ -2,17 +2,22 @@ error: encountered diff marker --> $DIR/tuple-struct.rs:2:1 | LL | <<<<<<< HEAD - | ^^^^^^^ after this is the code before the merge + | ^^^^^^^ between this marker and `=======` is the code that we're merging into LL | u8, LL | ======= - | ------- + | ------- between this marker and `>>>>>>>` is the incoming code LL | i8, LL | >>>>>>> branch - | ^^^^^^^ above this are the incoming code changes + | ^^^^^^^ this marker concludes the conflict region | - = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code - = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> + = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts + to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers + = help: if you're having merge conflicts after pulling new code: + the top section is the code you already had and the bottom section is the remote code + if you're in the middle of a rebase: + the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased + = note: for an explanation on these markers from the `git` documentation: + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/unclosed-delims-in-macro.stderr b/tests/ui/parser/diff-markers/unclosed-delims-in-macro.stderr index 6995b8e6f23..927821ddfae 100644 --- a/tests/ui/parser/diff-markers/unclosed-delims-in-macro.stderr +++ b/tests/ui/parser/diff-markers/unclosed-delims-in-macro.stderr @@ -2,17 +2,22 @@ error: encountered diff marker --> $DIR/unclosed-delims-in-macro.rs:2:1 | LL | <<<<<<< HEAD - | ^^^^^^^ after this is the code before the merge + | ^^^^^^^ between this marker and `=======` is the code that we're merging into ... LL | ======= - | ------- + | ------- between this marker and `>>>>>>>` is the incoming code LL | () { // LL | >>>>>>> 7a4f13c blah blah blah - | ^^^^^^^ above this are the incoming code changes + | ^^^^^^^ this marker concludes the conflict region | - = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code - = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> + = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts + to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers + = help: if you're having merge conflicts after pulling new code: + the top section is the code you already had and the bottom section is the remote code + if you're in the middle of a rebase: + the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased + = note: for an explanation on these markers from the `git` documentation: + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/unclosed-delims.rs b/tests/ui/parser/diff-markers/unclosed-delims.rs index 653a605c28c..7d400c3827b 100644 --- a/tests/ui/parser/diff-markers/unclosed-delims.rs +++ b/tests/ui/parser/diff-markers/unclosed-delims.rs @@ -2,13 +2,17 @@ mod tests { #[test] <<<<<<< HEAD //~^ ERROR encountered diff marker -//~| NOTE after this is the code before the merge +//~| NOTE between this marker and `=======` + +//~| NOTE conflict markers indicate that +//~| HELP if you're having merge conflicts //~| NOTE for an explanation on these markers + fn test1() { ======= -//~^ NOTE +//~^ NOTE between this marker and `>>>>>>>` fn test2() { >>>>>>> 7a4f13c blah blah blah -//~^ NOTE above this are the incoming code changes +//~^ NOTE this marker concludes the conflict region } } diff --git a/tests/ui/parser/diff-markers/unclosed-delims.stderr b/tests/ui/parser/diff-markers/unclosed-delims.stderr index d4636150e66..1eab96442b4 100644 --- a/tests/ui/parser/diff-markers/unclosed-delims.stderr +++ b/tests/ui/parser/diff-markers/unclosed-delims.stderr @@ -2,17 +2,22 @@ error: encountered diff marker --> $DIR/unclosed-delims.rs:3:1 | LL | <<<<<<< HEAD - | ^^^^^^^ after this is the code before the merge + | ^^^^^^^ between this marker and `=======` is the code that we're merging into ... LL | ======= - | ------- + | ------- between this marker and `>>>>>>>` is the incoming code ... LL | >>>>>>> 7a4f13c blah blah blah - | ^^^^^^^ above this are the incoming code changes + | ^^^^^^^ this marker concludes the conflict region | - = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code - = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> + = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts + to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers + = help: if you're having merge conflicts after pulling new code: + the top section is the code you already had and the bottom section is the remote code + if you're in the middle of a rebase: + the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased + = note: for an explanation on these markers from the `git` documentation: + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/use-statement.stderr b/tests/ui/parser/diff-markers/use-statement.stderr index 6d376166a7f..3eac7bebb5a 100644 --- a/tests/ui/parser/diff-markers/use-statement.stderr +++ b/tests/ui/parser/diff-markers/use-statement.stderr @@ -2,17 +2,22 @@ error: encountered diff marker --> $DIR/use-statement.rs:2:1 | LL | <<<<<<< HEAD - | ^^^^^^^ after this is the code before the merge + | ^^^^^^^ between this marker and `=======` is the code that we're merging into LL | bar, LL | ======= - | ------- + | ------- between this marker and `>>>>>>>` is the incoming code LL | baz, LL | >>>>>>> branch - | ^^^^^^^ above this are the incoming code changes + | ^^^^^^^ this marker concludes the conflict region | - = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code - = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> + = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts + to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers + = help: if you're having merge conflicts after pulling new code: + the top section is the code you already had and the bottom section is the remote code + if you're in the middle of a rebase: + the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased + = note: for an explanation on these markers from the `git` documentation: + visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts> error: aborting due to 1 previous error diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr index abaa6527b0a..29404f1793b 100644 --- a/tests/ui/parser/fn-header-semantic-fail.stderr +++ b/tests/ui/parser/fn-header-semantic-fail.stderr @@ -105,15 +105,6 @@ LL | extern "C" { LL | extern "C" fn fe4(); | ^^^^^^^^^^ help: remove this qualifier -error: items in unadorned `extern` blocks cannot have safety qualifiers - --> $DIR/fn-header-semantic-fail.rs:50:9 - | -LL | extern "C" { - | ---------- help: add unsafe to this `extern` block -... -LL | const async unsafe extern "C" fn fe5(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: functions in `extern` blocks cannot have qualifiers --> $DIR/fn-header-semantic-fail.rs:50:15 | @@ -141,6 +132,15 @@ LL | extern "C" { LL | const async unsafe extern "C" fn fe5(); | ^^^^^^^^^^ help: remove this qualifier +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/fn-header-semantic-fail.rs:50:9 + | +LL | extern "C" { + | ---------- help: add unsafe to this `extern` block +... +LL | const async unsafe extern "C" fn fe5(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:50:9 | diff --git a/tests/ui/parser/impls-nested-within-fns-semantic-1.rs b/tests/ui/parser/impls-nested-within-fns-semantic-1.rs index 43530e41a66..0e95fc757f3 100644 --- a/tests/ui/parser/impls-nested-within-fns-semantic-1.rs +++ b/tests/ui/parser/impls-nested-within-fns-semantic-1.rs @@ -1,7 +1,7 @@ // Regression test for part of issue #119924. //@ check-pass -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] trait Trait { diff --git a/tests/ui/parser/impls-nested-within-fns-semantic-1.stderr b/tests/ui/parser/impls-nested-within-fns-semantic-1.stderr new file mode 100644 index 00000000000..6670b3772db --- /dev/null +++ b/tests/ui/parser/impls-nested-within-fns-semantic-1.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/impls-nested-within-fns-semantic-1.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/parser/issues/issue-8537.stderr b/tests/ui/parser/issues/issue-8537.stderr index 0d636bd28a5..b685464d8d4 100644 --- a/tests/ui/parser/issues/issue-8537.stderr +++ b/tests/ui/parser/issues/issue-8537.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `invalid-ab_isize` LL | "invalid-ab_isize" | ^^^^^^^^^^^^^^^^^^ invalid ABI | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions error: aborting due to 1 previous error diff --git a/tests/ui/parser/no-const-fn-in-extern-block.stderr b/tests/ui/parser/no-const-fn-in-extern-block.stderr index 892024ce893..f575acc839d 100644 --- a/tests/ui/parser/no-const-fn-in-extern-block.stderr +++ b/tests/ui/parser/no-const-fn-in-extern-block.stderr @@ -6,23 +6,23 @@ LL | extern "C" { LL | const fn foo(); | ^^^^^ help: remove this qualifier -error: items in unadorned `extern` blocks cannot have safety qualifiers +error: functions in `extern` blocks cannot have qualifiers --> $DIR/no-const-fn-in-extern-block.rs:4:5 | LL | extern "C" { - | ---------- help: add unsafe to this `extern` block + | ---------- in this `extern` block ... LL | const unsafe fn bar(); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ help: remove this qualifier -error: functions in `extern` blocks cannot have qualifiers +error: items in unadorned `extern` blocks cannot have safety qualifiers --> $DIR/no-const-fn-in-extern-block.rs:4:5 | LL | extern "C" { - | ---------- in this `extern` block + | ---------- help: add unsafe to this `extern` block ... LL | const unsafe fn bar(); - | ^^^^^ help: remove this qualifier + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/parser/recover/recover-labeled-non-block-expr.stderr b/tests/ui/parser/recover/recover-labeled-non-block-expr.stderr index d66ce695090..c8107997c2e 100644 --- a/tests/ui/parser/recover/recover-labeled-non-block-expr.stderr +++ b/tests/ui/parser/recover/recover-labeled-non-block-expr.stderr @@ -54,7 +54,7 @@ help: consider enclosing expression in a block | LL ~ let _i = 'label: { match x { LL | 0 => 42, - ... +... LL | _ => 1, LL ~ } }; | diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs index 11126dbc65d..1cd6d13d56b 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs @@ -4,29 +4,29 @@ fn main() {} fn f1_1(x: isize, ...) {} -//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic +//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg fn f1_2(...) {} -//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic +//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg extern "C" fn f2_1(x: isize, ...) {} -//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic +//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg extern "C" fn f2_2(...) {} -//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic +//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg extern "C" fn f2_3(..., x: isize) {} -//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic +//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg //~| ERROR `...` must be the last argument of a C-variadic function extern "C" fn f3_1(x: isize, ...) {} -//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic +//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg extern "C" fn f3_2(...) {} -//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic +//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg extern "C" fn f3_3(..., x: isize) {} -//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic +//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg //~| ERROR `...` must be the last argument of a C-variadic function const unsafe extern "C" fn f4_1(x: isize, ...) {} @@ -35,12 +35,12 @@ const unsafe extern "C" fn f4_1(x: isize, ...) {} const extern "C" fn f4_2(x: isize, ...) {} //~^ ERROR functions cannot be both `const` and C-variadic -//~| ERROR only foreign or `unsafe extern "C"` functions may be C-variadic +//~| ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg //~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time const extern "C" fn f4_3(..., x: isize, ...) {} //~^ ERROR functions cannot be both `const` and C-variadic -//~| ERROR only foreign or `unsafe extern "C"` functions may be C-variadic +//~| ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg //~| ERROR `...` must be the last argument of a C-variadic function extern "C" { @@ -52,34 +52,34 @@ struct X; impl X { fn i_f1(x: isize, ...) {} - //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic + //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg fn i_f2(...) {} - //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic + //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg fn i_f3(..., x: isize, ...) {} - //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic + //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg //~| ERROR `...` must be the last argument of a C-variadic function fn i_f4(..., x: isize, ...) {} - //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic + //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg //~| ERROR `...` must be the last argument of a C-variadic function const fn i_f5(x: isize, ...) {} - //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic + //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg //~| ERROR functions cannot be both `const` and C-variadic //~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time } trait T { fn t_f1(x: isize, ...) {} - //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic + //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg fn t_f2(x: isize, ...); - //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic + //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg fn t_f3(...) {} - //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic + //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg fn t_f4(...); - //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic + //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg fn t_f5(..., x: isize) {} - //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic + //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg //~| ERROR `...` must be the last argument of a C-variadic function fn t_f6(..., x: isize); - //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic + //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg //~| ERROR `...` must be the last argument of a C-variadic function } diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr index f71e3863440..b740cef0200 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr @@ -1,22 +1,22 @@ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:6:19 | LL | fn f1_1(x: isize, ...) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:9:9 | LL | fn f1_2(...) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:12:30 | LL | extern "C" fn f2_1(x: isize, ...) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20 | LL | extern "C" fn f2_2(...) {} @@ -28,19 +28,19 @@ error: `...` must be the last argument of a C-variadic function LL | extern "C" fn f2_3(..., x: isize) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:18:20 | LL | extern "C" fn f2_3(..., x: isize) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:22:30 | LL | extern "C" fn f3_1(x: isize, ...) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:25:20 | LL | extern "C" fn f3_2(...) {} @@ -52,7 +52,7 @@ error: `...` must be the last argument of a C-variadic function LL | extern "C" fn f3_3(..., x: isize) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:28:20 | LL | extern "C" fn f3_3(..., x: isize) {} @@ -70,7 +70,7 @@ error: functions cannot be both `const` and C-variadic LL | const extern "C" fn f4_2(x: isize, ...) {} | ^^^^^ `const` because of this ^^^ C-variadic because of this -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:36:36 | LL | const extern "C" fn f4_2(x: isize, ...) {} @@ -91,7 +91,7 @@ LL | const extern "C" fn f4_3(..., x: isize, ...) {} | | C-variadic because of this | `const` because of this -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:41:26 | LL | const extern "C" fn f4_3(..., x: isize, ...) {} @@ -103,13 +103,13 @@ error: `...` must be the last argument of a C-variadic function LL | fn e_f2(..., x: isize); | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:54:23 | LL | fn i_f1(x: isize, ...) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:56:13 | LL | fn i_f2(...) {} @@ -121,7 +121,7 @@ error: `...` must be the last argument of a C-variadic function LL | fn i_f3(..., x: isize, ...) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:58:13 | LL | fn i_f3(..., x: isize, ...) {} @@ -133,7 +133,7 @@ error: `...` must be the last argument of a C-variadic function LL | fn i_f4(..., x: isize, ...) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:61:13 | LL | fn i_f4(..., x: isize, ...) {} @@ -147,31 +147,31 @@ LL | const fn i_f5(x: isize, ...) {} | | | `const` because of this -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:64:29 | LL | const fn i_f5(x: isize, ...) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:71:23 | LL | fn t_f1(x: isize, ...) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:73:23 | LL | fn t_f2(x: isize, ...); | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:75:13 | LL | fn t_f3(...) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:77:13 | LL | fn t_f4(...); @@ -183,7 +183,7 @@ error: `...` must be the last argument of a C-variadic function LL | fn t_f5(..., x: isize) {} | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13 | LL | fn t_f5(..., x: isize) {} @@ -195,7 +195,7 @@ error: `...` must be the last argument of a C-variadic function LL | fn t_f6(..., x: isize); | ^^^ -error: only foreign or `unsafe extern "C"` functions may be C-variadic +error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg --> $DIR/variadic-ffi-semantic-restrictions.rs:82:13 | LL | fn t_f6(..., x: isize); diff --git a/tests/ui/pattern/usefulness/floats.rs b/tests/ui/pattern/usefulness/floats.rs index b3d49ba8e15..0b27e33e4ef 100644 --- a/tests/ui/pattern/usefulness/floats.rs +++ b/tests/ui/pattern/usefulness/floats.rs @@ -1,4 +1,6 @@ #![deny(unreachable_patterns)] +#![feature(f128)] +#![feature(f16)] fn main() { match 0.0 { @@ -11,6 +13,32 @@ fn main() { 0.0..=1.0 => {} } + match 1.0f16 { + 0.01f16..=6.5f16 => {} + 0.01f16 => {} //~ ERROR unreachable pattern + 0.02f16 => {} //~ ERROR unreachable pattern + 6.5f16 => {} //~ ERROR unreachable pattern + _ => {} + }; + match 1.0f16 { + 0.01f16..6.5f16 => {} + 6.5f16 => {} // this is reachable + _ => {} + }; + + match 1.0f32 { + 0.01f32..=6.5f32 => {} + 0.01f32 => {} //~ ERROR unreachable pattern + 0.02f32 => {} //~ ERROR unreachable pattern + 6.5f32 => {} //~ ERROR unreachable pattern + _ => {} + }; + match 1.0f32 { + 0.01f32..6.5f32 => {} + 6.5f32 => {} // this is reachable + _ => {} + }; + match 1.0f64 { 0.01f64..=6.5f64 => {} 0.005f64 => {} @@ -28,16 +56,20 @@ fn main() { _ => {} }; - match 1.0f32 { - 0.01f32..=6.5f32 => {} - 0.01f32 => {} //~ ERROR unreachable pattern - 0.02f32 => {} //~ ERROR unreachable pattern - 6.5f32 => {} //~ ERROR unreachable pattern + match 1.0f128 { + 0.01f128..=6.5f128 => {} + 0.005f128 => {} + 0.01f128 => {} //~ ERROR unreachable pattern + 0.02f128 => {} //~ ERROR unreachable pattern + 6.5f128 => {} //~ ERROR unreachable pattern + 6.6f128 => {} + 1.0f128..=4.0f128 => {} //~ ERROR unreachable pattern + 5.0f128..=7.0f128 => {} _ => {} }; - match 1.0f32 { - 0.01f32..6.5f32 => {} - 6.5f32 => {} // this is reachable + match 1.0f128 { + 0.01f128..6.5f128 => {} + 6.5f128 => {} // this is reachable _ => {} }; } diff --git a/tests/ui/pattern/usefulness/floats.stderr b/tests/ui/pattern/usefulness/floats.stderr index 04f2fe3cd94..684f6c93a16 100644 --- a/tests/ui/pattern/usefulness/floats.stderr +++ b/tests/ui/pattern/usefulness/floats.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/floats.rs:9:11 + --> $DIR/floats.rs:11:11 | LL | match 0.0 { | ^^^ pattern `_` not covered @@ -12,9 +12,9 @@ LL + _ => todo!() | error: unreachable pattern - --> $DIR/floats.rs:17:9 + --> $DIR/floats.rs:18:9 | -LL | 0.01f64 => {} +LL | 0.01f16 => {} | ^^^^^^^ | note: the lint level is defined here @@ -24,41 +24,83 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:18:9 + --> $DIR/floats.rs:19:9 + | +LL | 0.02f16 => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:20:9 + | +LL | 6.5f16 => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:31:9 + | +LL | 0.01f32 => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:32:9 + | +LL | 0.02f32 => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:33:9 + | +LL | 6.5f32 => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:45:9 + | +LL | 0.01f64 => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:46:9 | LL | 0.02f64 => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:19:9 + --> $DIR/floats.rs:47:9 | LL | 6.5f64 => {} | ^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:21:9 + --> $DIR/floats.rs:49:9 | LL | 1.0f64..=4.0f64 => {} | ^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:33:9 + --> $DIR/floats.rs:62:9 | -LL | 0.01f32 => {} - | ^^^^^^^ +LL | 0.01f128 => {} + | ^^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:34:9 + --> $DIR/floats.rs:63:9 | -LL | 0.02f32 => {} +LL | 0.02f128 => {} + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:64:9 + | +LL | 6.5f128 => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:35:9 + --> $DIR/floats.rs:66:9 | -LL | 6.5f32 => {} - | ^^^^^^ +LL | 1.0f128..=4.0f128 => {} + | ^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/resolve/path-attr-in-const-block.rs b/tests/ui/resolve/path-attr-in-const-block.rs new file mode 100644 index 00000000000..076511d26d6 --- /dev/null +++ b/tests/ui/resolve/path-attr-in-const-block.rs @@ -0,0 +1,9 @@ +// issue#126516 +// issue#126647 + +fn main() { + const { + #![path = foo!()] + //~^ ERROR: cannot find macro `foo` in this scope + } +} diff --git a/tests/ui/resolve/path-attr-in-const-block.stderr b/tests/ui/resolve/path-attr-in-const-block.stderr new file mode 100644 index 00000000000..8f9e58157c8 --- /dev/null +++ b/tests/ui/resolve/path-attr-in-const-block.stderr @@ -0,0 +1,8 @@ +error: cannot find macro `foo` in this scope + --> $DIR/path-attr-in-const-block.rs:6:19 + | +LL | #![path = foo!()] + | ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.qualified.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.qualified.stderr index 62c8a442ab9..3aec4383eab 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.qualified.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.qualified.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/assoc-type-const-bound-usage-0.rs:6:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/assoc-type-const-bound-usage-0.rs:21:6 | @@ -9,6 +18,6 @@ help: consider further restricting this bound LL | const fn qualified<T: ~const Trait + Trait>() -> i32 { | +++++++ -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 E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs index 6b55e82629b..eecd6e6109c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs @@ -3,7 +3,7 @@ //@[unqualified] check-pass //@[qualified] known-bug: unknown -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //[unqualified]~ WARN the feature `effects` is incomplete #[const_trait] trait Trait { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.unqualified.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.unqualified.stderr new file mode 100644 index 00000000000..3d592834600 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.unqualified.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/assoc-type-const-bound-usage-0.rs:6:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs index 886fa6577d7..645fff4e014 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs @@ -1,5 +1,5 @@ // FIXME(effects): Replace `Add` with `std::ops::Add` once the latter a `#[const_trait]` again. -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] trait Add<Rhs = Self> { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr index a9cae2a70be..cc3abea25eb 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/assoc-type.rs:2:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0277]: the trait bound `NonConstAdd: ~const Add` is not satisfied --> $DIR/assoc-type.rs:35:16 | @@ -11,6 +20,6 @@ note: required by a bound in `Foo::Bar` LL | type Bar: ~const Add; | ^^^^^^^^^^ required by this bound in `Foo::Bar` -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 E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs index f40dc27cb4c..62609384cff 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] pub trait MyTrait { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/staged-api.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/staged-api.rs index 687cb128b05..fd4e1ff803d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/staged-api.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/staged-api.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #![feature(staged_api)] #![stable(feature = "rust1", since = "1.0.0")] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs index 771c35cf6ab..bb9e9045f8f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] pub trait Plus { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr index 93d520f29ef..0e4dcf0f302 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/call-const-trait-method-fail.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0277]: the trait bound `u32: ~const Plus` is not satisfied --> $DIR/call-const-trait-method-fail.rs:25:5 | @@ -6,6 +15,6 @@ LL | a.plus(b) | = help: the trait `Plus` is implemented for `u32` -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 E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.rs index b63458b39e9..6b3a4ae1b95 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.rs @@ -1,4 +1,5 @@ -//@ check-pass +//@ known-bug: #110395 +// FIXME(effects) check-pass #![feature(const_trait_impl)] #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr new file mode 100644 index 00000000000..12027c4d713 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr @@ -0,0 +1,8 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-in-impl.rs:10:16 + | +LL | impl<T: ~const PartialEq> const MyPartialEq for T { + | ^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.rs index 37b2de0fd2d..9df694a02f5 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.rs @@ -1,6 +1,7 @@ //! Basic test for calling methods on generic type parameters in `const fn`. -//@ check-pass +//@ known-bug: #110395 +// FIXME(effects) check-pass #![feature(const_trait_impl, effects)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr new file mode 100644 index 00000000000..36c7a654430 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr @@ -0,0 +1,71 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/call-generic-method-chain.rs:6:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/call-generic-method-chain.rs:10:12 + | +LL | impl const PartialEq for S { + | ^^^^^^^^^ + | + = 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[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates + --> $DIR/call-generic-method-chain.rs:10:6 + | +LL | impl const PartialEq for S { + | ^^^^^ 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: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-chain.rs:19:32 + | +LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { + | ^^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-chain.rs:23:40 + | +LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool { + | ^^^^^^^^^ + +error[E0284]: type annotations needed + --> $DIR/call-generic-method-chain.rs:27:22 + | +LL | pub const EQ: bool = equals_self_wrapper(&S); + | ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` + | +note: required for `S` to implement `PartialEq` + --> $DIR/call-generic-method-chain.rs:10:12 + | +LL | impl const PartialEq for S { + | ----- ^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0284]: type annotations needed + --> $DIR/call-generic-method-chain.rs:15:10 + | +LL | !self.eq(other) + | ^^^^^^^^^^^^^^ cannot infer the value of the constant `_` + | +note: required for `S` to implement `PartialEq` + --> $DIR/call-generic-method-chain.rs:10:12 + | +LL | impl const PartialEq for S { + | ----- ^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error: aborting due to 6 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0207, E0284. +For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs index ea8fd005561..f46a34911f1 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs @@ -1,4 +1,5 @@ -//@ check-pass +//@ known-bug: #110395 +// FIXME(effects) check-pass #![feature(const_trait_impl, effects)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr new file mode 100644 index 00000000000..320e420b80a --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr @@ -0,0 +1,85 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/call-generic-method-dup-bound.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/call-generic-method-dup-bound.rs:8:12 + | +LL | impl const PartialEq for S { + | ^^^^^^^^^ + | + = 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[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates + --> $DIR/call-generic-method-dup-bound.rs:8:6 + | +LL | impl const PartialEq for S { + | ^^^^^ 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: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-dup-bound.rs:19:44 + | +LL | const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool { + | ^^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-dup-bound.rs:26:37 + | +LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool { + | ^^^^^^^^^ + +error[E0284]: type annotations needed + --> $DIR/call-generic-method-dup-bound.rs:30:22 + | +LL | pub const EQ: bool = equals_self(&S) && equals_self2(&S); + | ^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` + | +note: required for `S` to implement `PartialEq` + --> $DIR/call-generic-method-dup-bound.rs:8:12 + | +LL | impl const PartialEq for S { + | ----- ^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0284]: type annotations needed + --> $DIR/call-generic-method-dup-bound.rs:30:41 + | +LL | pub const EQ: bool = equals_self(&S) && equals_self2(&S); + | ^^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` + | +note: required for `S` to implement `PartialEq` + --> $DIR/call-generic-method-dup-bound.rs:8:12 + | +LL | impl const PartialEq for S { + | ----- ^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0284]: type annotations needed + --> $DIR/call-generic-method-dup-bound.rs:13:10 + | +LL | !self.eq(other) + | ^^^^^^^^^^^^^^ cannot infer the value of the constant `_` + | +note: required for `S` to implement `PartialEq` + --> $DIR/call-generic-method-dup-bound.rs:8:12 + | +LL | impl const PartialEq for S { + | ----- ^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error: aborting due to 7 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0207, E0284. +For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.rs index 043939750a8..a9ed5a639d7 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.rs @@ -1,8 +1,10 @@ -#![feature(const_trait_impl, effects)] +//@ check-pass + +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete pub const fn equals_self<T: PartialEq>(t: &T) -> bool { *t == *t - //~^ ERROR mismatched types + // FIXME(effects) ~^ ERROR mismatched types // FIXME(effects): diagnostic } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.stderr index 5074c4a2261..74b74052da0 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.stderr @@ -1,12 +1,11 @@ -error[E0308]: mismatched types - --> $DIR/call-generic-method-fail.rs:4:5 +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/call-generic-method-fail.rs:3:30 | -LL | *t == *t - | ^^^^^^^^ expected `host`, found `true` +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ | - = note: expected constant `host` - found constant `true` + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default -error: aborting due to 1 previous error +warning: 1 warning emitted -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs index 8d6176a5bac..222bff2db88 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete struct S; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr index 3581b1fcd7d..fa59e5ee03d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/call-generic-method-nonconst.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0277]: the trait bound `S: const Foo` is not satisfied --> $DIR/call-generic-method-nonconst.rs:23:34 | @@ -13,6 +22,6 @@ note: required by a bound in `equals_self` LL | const fn equals_self<T: ~const Foo>(t: &T) -> bool { | ^^^^^^^^^^ required by this bound in `equals_self` -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 E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.rs index 55d8afa8d47..413685d8b34 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.rs @@ -1,6 +1,7 @@ //! Basic test for calling methods on generic type parameters in `const fn`. -//@ check-pass +//@ known-bug: #110395 +// FIXME(effects) check-pass #![feature(const_trait_impl, effects)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr new file mode 100644 index 00000000000..6b9d290839e --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr @@ -0,0 +1,65 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/call-generic-method-pass.rs:6:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/call-generic-method-pass.rs:10:12 + | +LL | impl const PartialEq for S { + | ^^^^^^^^^ + | + = 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[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates + --> $DIR/call-generic-method-pass.rs:10:6 + | +LL | impl const PartialEq for S { + | ^^^^^ 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: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-pass.rs:19:32 + | +LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { + | ^^^^^^^^^ + +error[E0284]: type annotations needed + --> $DIR/call-generic-method-pass.rs:23:22 + | +LL | pub const EQ: bool = equals_self(&S); + | ^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` + | +note: required for `S` to implement `PartialEq` + --> $DIR/call-generic-method-pass.rs:10:12 + | +LL | impl const PartialEq for S { + | ----- ^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0284]: type annotations needed + --> $DIR/call-generic-method-pass.rs:15:10 + | +LL | !self.eq(other) + | ^^^^^^^^^^^^^^ cannot infer the value of the constant `_` + | +note: required for `S` to implement `PartialEq` + --> $DIR/call-generic-method-pass.rs:10:12 + | +LL | impl const PartialEq for S { + | ----- ^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error: aborting due to 5 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0207, E0284. +For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr index 54bc4347722..8916450df2d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr @@ -1,3 +1,12 @@ +error[E0119]: conflicting implementations of trait `Add` for type `Int` + --> $DIR/const-and-non-const-impl.rs:23:1 + | +LL | impl std::ops::Add for Int { + | -------------------------- first implementation here +... +LL | impl const std::ops::Add for Int { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Int` + error[E0117]: only traits defined in the current crate can be implemented for primitive types --> $DIR/const-and-non-const-impl.rs:7:1 | @@ -10,15 +19,6 @@ LL | impl const std::ops::Add for i32 { | = note: define and implement a trait or new type instead -error[E0119]: conflicting implementations of trait `Add` for type `Int` - --> $DIR/const-and-non-const-impl.rs:23:1 - | -LL | impl std::ops::Add for Int { - | -------------------------- first implementation here -... -LL | impl const std::ops::Add for Int { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Int` - error: aborting due to 2 previous errors Some errors have detailed explanations: E0117, E0119. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs index 3582e5e050c..db446f8bc2e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs @@ -1,5 +1,5 @@ // Regression test for issue #117244. -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete trait NonConst {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr index 08954987d31..d04e5490b76 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-bounds-non-const-trait.rs:2:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-bounds-non-const-trait.rs:6:28 | @@ -10,5 +19,5 @@ error: `const` can only be applied to `#[const_trait]` traits LL | fn operate<T: const NonConst>() {} | ^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs index 4854f41bf04..a1710e65252 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete struct S; #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr index ae035b26ec5..d93327cea1b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-check-fns-in-const-impl.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0015]: cannot call non-const fn `non_const` in constant functions --> $DIR/const-check-fns-in-const-impl.rs:12:16 | @@ -6,6 +15,6 @@ LL | fn foo() { non_const() } | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -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 E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs index be668b4f13a..2fd58b05178 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] trait ConstDefaultFn: Sized { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr index f39e6dcadba..8e04d0bd20d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-default-method-bodies.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied --> $DIR/const-default-method-bodies.rs:24:18 | @@ -6,6 +15,6 @@ LL | NonConstImpl.a(); | = help: the trait `ConstDefaultFn` is implemented for `NonConstImpl` -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 E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.stderr index 16ed615907b..be197006f02 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.stderr @@ -1,9 +1,27 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-bound.rs:9:68 + | +LL | const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct { + | ^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-bound.rs:20:15 + | +LL | T: ~const Destruct, + | ^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-bound.rs:21:15 + | +LL | E: ~const Destruct, + | ^^^^^^^^ + error[E0493]: destructor of `E` cannot be evaluated at compile-time --> $DIR/const-drop-bound.rs:12:13 | LL | Err(_e) => None, | ^^ the destructor for this type cannot be evaluated in constant functions -error: aborting due to 1 previous error +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr index 6f75924f0aa..085d9e71012 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr @@ -1,3 +1,9 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-fail-2.rs:21:26 + | +LL | const fn check<T: ~const Destruct>(_: T) {} + | ^^^^^^^^ + error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-drop-fail-2.rs:21:36 | @@ -6,6 +12,6 @@ LL | const fn check<T: ~const Destruct>(_: T) {} | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr index 9afa2072dde..e95215d4715 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr @@ -1,3 +1,9 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-fail.rs:24:26 + | +LL | const fn check<T: ~const Destruct>(_: T) {} + | ^^^^^^^^ + error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-drop-fail.rs:24:36 | @@ -54,7 +60,7 @@ LL | | } | |_- in this macro invocation = note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0080, E0493. For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr index 09ebf55c57c..f9bd9953fcf 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr @@ -1,3 +1,9 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-fail.rs:24:26 + | +LL | const fn check<T: ~const Destruct>(_: T) {} + | ^^^^^^^^ + error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-drop-fail.rs:24:36 | @@ -6,6 +12,6 @@ LL | const fn check<T: ~const Destruct>(_: T) {} | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr index 5ff3be713a7..6aace105896 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr @@ -1,3 +1,9 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop.rs:19:22 + | +LL | const fn a<T: ~const Destruct>(_: T) {} + | ^^^^^^^^ + error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time --> $DIR/const-drop.rs:24:13 | @@ -86,7 +92,7 @@ LL | | } | |_- in this macro invocation = note: this error originates in the macro `implements_const_drop` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0080, E0493. For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr index 40e39cbefbc..18dd4543c3d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr @@ -1,3 +1,9 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop.rs:19:22 + | +LL | const fn a<T: ~const Destruct>(_: T) {} + | ^^^^^^^^ + error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time --> $DIR/const-drop.rs:24:13 | @@ -14,6 +20,6 @@ LL | const fn a<T: ~const Destruct>(_: T) {} | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0493`. 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 index f6bba19a19e..faa913c7598 100644 --- 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 @@ -7,7 +7,7 @@ #![feature( auto_traits, const_trait_impl, - effects, + effects, //~ WARN the feature `effects` is incomplete lang_items, no_core, staged_api, diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr new file mode 100644 index 00000000000..42b19fce28e --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-fns-are-early-bound.rs:10:5 + | +LL | effects, + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + 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 d20404e63b3..fb282d9ee2b 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 @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-impl-requires-const-trait.rs:3:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: const `impl` for trait `A` which is not marked with `#[const_trait]` --> $DIR/const-impl-requires-const-trait.rs:8:12 | @@ -19,6 +28,6 @@ LL | impl const A for () {} = 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 +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0207`. 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 03038eb5c84..af50a115c69 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,244 @@ -error[E0277]: can't compare `()` with `()` - --> $DIR/const-impl-trait.rs:36:17 +error[E0635]: unknown feature `const_cmp` + --> $DIR/const-impl-trait.rs:8:5 | -LL | assert!(cmp(&())); - | --- ^^^ no implementation for `() == ()` +LL | const_cmp, + | ^^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:13:30 + | +LL | const fn cmp(a: &impl ~const PartialEq) -> bool { + | ^^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:17:30 + | +LL | const fn wrap(x: impl ~const PartialEq + ~const Destruct) + | ^^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:17:49 + | +LL | const fn wrap(x: impl ~const PartialEq + ~const Destruct) + | ^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:18:20 + | +LL | -> impl ~const PartialEq + ~const Destruct + | ^^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:18:39 + | +LL | -> impl ~const PartialEq + ~const Destruct + | ^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:18:20 + | +LL | -> impl ~const PartialEq + ~const Destruct + | ^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:18:39 + | +LL | -> impl ~const PartialEq + ~const Destruct + | ^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:25:29 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:25:48 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:25:29 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:25:48 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:25:29 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:25:48 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:29:29 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { + | ^^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:29:48 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { + | ^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:29:29 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { + | ^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:29:48 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { + | ^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:50:41 + | +LL | const fn apit(_: impl ~const T + ~const Destruct) {} + | ^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:54:73 + | +LL | const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {} + | ^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:25:29 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:25:48 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time + --> $DIR/const-impl-trait.rs:37:26 + | +LL | assert!(wrap(123) == wrap(123)); + | ^^^^^^^^^- value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + +error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time + --> $DIR/const-impl-trait.rs:37:26 + | +LL | assert!(wrap(123) == wrap(123)); + | ^^^^^^^^^- value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time + --> $DIR/const-impl-trait.rs:37:13 + | +LL | assert!(wrap(123) == wrap(123)); + | ^^^^^^^^^ - value is dropped here | | - | required by a bound introduced by this call + | the destructor for this type cannot be evaluated in constants + +error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time + --> $DIR/const-impl-trait.rs:37:13 | - = 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:13:23 +LL | assert!(wrap(123) == wrap(123)); + | ^^^^^^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constants | -LL | const fn cmp(a: &impl ~const PartialEq) -> bool { - | ^^^^^^^^^^^^^^^^ required by this bound in `cmp` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time + --> $DIR/const-impl-trait.rs:38:26 + | +LL | assert!(wrap(123) != wrap(456)); + | ^^^^^^^^^- value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + +error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time + --> $DIR/const-impl-trait.rs:38:26 + | +LL | assert!(wrap(123) != wrap(456)); + | ^^^^^^^^^- value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time + --> $DIR/const-impl-trait.rs:38:13 + | +LL | assert!(wrap(123) != wrap(456)); + | ^^^^^^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + +error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time + --> $DIR/const-impl-trait.rs:38:13 + | +LL | assert!(wrap(123) != wrap(456)); + | ^^^^^^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0493]: destructor of `impl ~const T + ~const Destruct` cannot be evaluated at compile-time + --> $DIR/const-impl-trait.rs:50:15 + | +LL | const fn apit(_: impl ~const T + ~const Destruct) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions -error[E0369]: binary operation `==` cannot be applied to type `&impl ~const PartialEq` - --> $DIR/const-impl-trait.rs:14:7 +error[E0493]: destructor of `impl IntoIterator<Item : ~const T> + ~const Destruct` cannot be evaluated at compile-time + --> $DIR/const-impl-trait.rs:54:27 | -LL | a == a - | - ^^ - &impl ~const PartialEq - | | - | &impl ~const PartialEq +LL | const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 2 previous errors +error: aborting due to 32 previous errors -Some errors have detailed explanations: E0277, E0369. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0493, E0635. +For more information about an error, try `rustc --explain E0493`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs index 79719dae44f..8e71fa4d519 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete //@ edition: 2021 #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr index 04c2dc2e2e0..7d774bef0e9 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr @@ -26,5 +26,14 @@ LL | const fn take(_: &dyn ~const NonConst) {} | = note: trait objects cannot have `~const` trait bounds -error: aborting due to 4 previous errors +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-trait-bounds-trait-objects.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 4 previous errors; 1 warning emitted 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 4b009446dbc..1e091283510 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 @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/derive-const-non-const-type.rs:2:26 + | +LL | #![feature(derive_const, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: const `impl` for trait `Default` which is not marked with `#[const_trait]` --> $DIR/derive-const-non-const-type.rs:10:16 | @@ -13,6 +22,6 @@ error[E0207]: the const parameter `host` is not constrained by the impl trait, s = 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 +error: aborting due to 2 previous errors; 1 warning emitted 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 e45c1a1f46f..925b2c58ed7 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 @@ -1,3 +1,18 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/derive-const-use.rs:3:76 + | +LL | #![feature(const_trait_impl, const_cmp, const_default_impls, derive_const, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0635]: unknown feature `const_cmp` + --> $DIR/derive-const-use.rs:3:30 + | +LL | #![feature(const_trait_impl, const_cmp, const_default_impls, derive_const, effects)] + | ^^^^^^^^^ + error[E0635]: unknown feature `const_default_impls` --> $DIR/derive-const-use.rs:3:41 | @@ -22,6 +37,24 @@ LL | impl const Default for A { = 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: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/derive-const-use.rs:11:12 + | +LL | impl const PartialEq for A { + | ^^^^^^^^^ + | + = 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[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates + --> $DIR/derive-const-use.rs:11:6 + | +LL | impl const PartialEq 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 + error: const `impl` for trait `Default` which is not marked with `#[const_trait]` --> $DIR/derive-const-use.rs:15:16 | @@ -37,19 +70,83 @@ error[E0207]: the const parameter `host` is not constrained by the impl trait, s = 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[E0308]: mismatched types - --> $DIR/derive-const-use.rs:16:14 +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/derive-const-use.rs:15:25 + | +LL | #[derive_const(Default, PartialEq)] + | ^^^^^^^^^ + | + = 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 + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +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 + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0284]: type annotations needed + --> $DIR/derive-const-use.rs:18:35 + | +LL | const _: () = assert!(S((), A) == S::default()); + | ^^^^^^^^^^^^ cannot infer the value of the constant `_` + | +note: required for `S` to implement `Default` + --> $DIR/derive-const-use.rs:15:16 + | +LL | #[derive_const(Default, PartialEq)] + | ^^^^^^^ unsatisfied trait bound introduced in this `derive` macro + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0284]: type annotations needed + --> $DIR/derive-const-use.rs:18:23 + | +LL | const _: () = assert!(S((), A) == S::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` + | +note: required for `S` to implement `PartialEq` + --> $DIR/derive-const-use.rs:15:25 + | +LL | #[derive_const(Default, PartialEq)] + | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0284]: type annotations needed + --> $DIR/derive-const-use.rs:16:18 + | +LL | #[derive_const(Default, PartialEq)] + | ------- in this derive macro expansion +LL | pub struct S((), A); + | ^ cannot infer the value of the constant `_` + | +note: required for `A` to implement `Default` + --> $DIR/derive-const-use.rs:7:12 + | +LL | impl const Default for A { + | ----- ^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0284]: type annotations needed + --> $DIR/derive-const-use.rs:16:18 | LL | #[derive_const(Default, PartialEq)] | --------- in this derive macro expansion LL | pub struct S((), A); - | ^^ expected `host`, found `true` + | ^ cannot infer the value of the constant `_` + | +note: required for `A` to implement `PartialEq` + --> $DIR/derive-const-use.rs:11:12 | - = note: expected constant `host` - found constant `true` +LL | impl const PartialEq for A { + | ----- ^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 6 previous errors +error: aborting due to 14 previous errors; 1 warning emitted -Some errors have detailed explanations: E0207, E0308, E0635. +Some errors have detailed explanations: E0207, E0284, E0635. For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs index 0eb422728c6..c032c76d38f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs @@ -1,4 +1,5 @@ -//@ check-pass +//@ known-bug: #110395 +// FIXME(effects) check-pass #![feature(derive_const)] #![feature(const_trait_impl, effects)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr new file mode 100644 index 00000000000..5d3aa250d18 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr @@ -0,0 +1,49 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/derive-const-with-params.rs:5:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/derive-const-with-params.rs:7:16 + | +LL | #[derive_const(PartialEq)] + | ^^^^^^^^^ + | + = 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 + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/derive-const-with-params.rs:7:16 + | +LL | #[derive_const(PartialEq)] + | ^^^^^^^^^ + | + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +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[E0284]: type annotations needed + --> $DIR/derive-const-with-params.rs:11:5 + | +LL | a == b + | ^^^^^^ cannot infer the value of the constant `_` + | +note: required for `Reverse<i32>` to implement `PartialEq` + --> $DIR/derive-const-with-params.rs:7:16 + | +LL | #[derive_const(PartialEq)] + | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0207, E0284. +For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs index 54e5c95c259..d8be8b13d08 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs @@ -3,7 +3,7 @@ // //@ check-pass -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete //@ aux-build: cross-crate.rs extern crate cross_crate; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.stderr new file mode 100644 index 00000000000..2f1e1e6b8d2 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/cross-crate-default-method-body-is-const.rs:6:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gated.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gated.stderr new file mode 100644 index 00000000000..2ce29a74eae --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gated.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/cross-crate.rs:3:60 + | +LL | #![cfg_attr(any(gated, gatednc), feature(const_trait_impl, effects))] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr index f0ac953fd5d..ddb5b3c7c50 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr @@ -1,11 +1,20 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/cross-crate.rs:3:60 + | +LL | #![cfg_attr(any(gated, gatednc), feature(const_trait_impl, effects))] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied - --> $DIR/cross-crate.rs:17:14 + --> $DIR/cross-crate.rs:18:14 | LL | NonConst.func(); | ^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` | = help: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst` -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 E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.rs index 587dd70c18b..04c101d0fc5 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.rs @@ -1,6 +1,7 @@ //@ revisions: stock gated stocknc gatednc //@ [gated] check-pass #![cfg_attr(any(gated, gatednc), feature(const_trait_impl, effects))] +//[gated,gatednc]~^ WARN the feature `effects` is incomplete //@ aux-build: cross-crate.rs extern crate cross_crate; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stock.stderr index a0c50ac7e61..3df875057f2 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stock.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stock.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions - --> $DIR/cross-crate.rs:20:11 + --> $DIR/cross-crate.rs:21:11 | LL | Const.func(); | ^^^^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr index 312818ae631..e56a5e4165c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions - --> $DIR/cross-crate.rs:17:14 + --> $DIR/cross-crate.rs:18:14 | LL | NonConst.func(); | ^^^^^^ @@ -11,7 +11,7 @@ LL + #![feature(const_trait_impl)] | error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions - --> $DIR/cross-crate.rs:20:11 + --> $DIR/cross-crate.rs:21:11 | LL | Const.func(); | ^^^^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs index da27724007d..64f23824b39 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] pub trait Tr { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr index 29db6109a98..67a936d0882 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/default-method-body-is-const-same-trait-ck.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0277]: the trait bound `(): ~const Tr` is not satisfied --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12 | @@ -6,6 +15,6 @@ LL | ().a() | = help: the trait `Tr` is implemented for `()` -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 E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.rs index 8b51f65fd04..be5e66478df 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.rs @@ -1,5 +1,5 @@ //@ check-pass -#![feature(const_trait_impl, rustc_attrs, effects)] +#![feature(const_trait_impl, rustc_attrs, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] trait Foo { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.stderr new file mode 100644 index 00000000000..4be1160b58c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/do-not-const-check-override.rs:2:43 + | +LL | #![feature(const_trait_impl, rustc_attrs, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/auxiliary/cross-crate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/auxiliary/cross-crate.rs index a74c50cc8fa..5c32eee8737 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/auxiliary/cross-crate.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/auxiliary/cross-crate.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete pub const fn foo() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.rs index d35e9bb7f1e..b354591e007 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.rs @@ -3,7 +3,7 @@ // //@ check-pass -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] pub trait Foo<Rhs: ?Sized = Self> { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.stderr new file mode 100644 index 00000000000..7ceb3669e59 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/effect-param-infer.rs:6:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs index aa75aa9c989..d949e4b829f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(effects)] +#![feature(effects)] //~ WARN the feature `effects` is incomplete pub const fn owo() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.stderr new file mode 100644 index 00000000000..f7d5de829b2 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/fallback.rs:3:12 + | +LL | #![feature(effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs index 502062a559c..eed8cdc447c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs @@ -3,7 +3,12 @@ // gate-test-effects // ^ effects doesn't have a gate so we will trick tidy into thinking this is a gate test -#![feature(const_trait_impl, effects, core_intrinsics, const_eval_select)] +#![feature( + const_trait_impl, + effects, //~ WARN the feature `effects` is incomplete + core_intrinsics, + const_eval_select +)] // ensure we are passing in the correct host effect in always const contexts. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.stderr new file mode 100644 index 00000000000..8719c5cbcef --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/helloworld.rs:8:5 + | +LL | effects, + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + 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 21197fcaa27..9a9016de3a0 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,16 +1,15 @@ -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete const fn test() -> impl ~const Fn() { //~^ ERROR `~const` can only be applied to `#[const_trait]` traits //~| 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` + //~^ ERROR cannot call non-const fn } [] => 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 2f805110917..3f0ed13d665 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:7:5 + --> $DIR/ice-112822-expected-type-for-param.rs:6:5 | LL | const move || { | ^^^^^ @@ -8,6 +8,15 @@ LL | const move || { = help: add `#![feature(const_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/ice-112822-expected-type-for-param.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/ice-112822-expected-type-for-param.rs:3:32 | @@ -22,47 +31,16 @@ LL | const fn test() -> impl ~const Fn() { | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0277]: can't compare `&u8` with `&u8` - --> $DIR/ice-112822-expected-type-for-param.rs:12:17 +error[E0015]: cannot call non-const fn `core::panicking::assert_failed::<&u8, &u8>` in constant functions + --> $DIR/ice-112822-expected-type-for-param.rs:11:17 | LL | assert_eq!(first, &b'f'); - | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&u8 == &u8` + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: the trait `~const PartialEq<&u8>` is not implemented for `&u8` + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) -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 5 previous errors +error: aborting due to 4 previous errors; 1 warning emitted -Some errors have detailed explanations: E0277, E0391, E0658. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0015, E0658. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs index 85aabe46640..ff3a27c3ee4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs @@ -1,5 +1,5 @@ //@ check-pass -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete const fn a() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.stderr new file mode 100644 index 00000000000..49c7d395846 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/infer-fallback.rs:2:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + 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 281cfdaef28..af88a73b4d6 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 @@ -1,4 +1,6 @@ -//@ check-pass +//@ known-bug: #110395 +// FIXME(effects) check-pass +// FIXME(effects) fix intrinsics const parameter counting #![crate_type = "lib"] #![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs, staged_api)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr new file mode 100644 index 00000000000..e4a5f368608 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr @@ -0,0 +1,18 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/minicore.rs:8:30 + | +LL | #![feature(const_trait_impl, effects, const_mut_refs)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0094]: intrinsic has wrong number of const parameters: found 1, expected 0 + --> $DIR/minicore.rs:517:27 + | +LL | const fn const_eval_select<ARG: Tuple, F, G, RET>( + | ^^^^^^^^^^^^^^^^^^^^^^^ expected 0 const parameters + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0094`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.rs index 929da1ca8fa..84f5f2803e1 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete const fn foo() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr index 0745d0304b9..39aa5825611 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/no-explicit-const-params.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied --> $DIR/no-explicit-const-params.rs:22:5 | @@ -63,7 +72,7 @@ note: trait defined here, with 0 generic parameters LL | trait Bar { | ^^^ -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 1 warning emitted Some errors have detailed explanations: E0107, E0308. For more information about an error, try `rustc --explain E0107`. 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 index eac3ee9e4e2..ab5f7b55a4e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/project.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0277]: the trait bound `Self: Uwu` is not satisfied --> $DIR/project.rs:12:1 | @@ -60,6 +69,6 @@ help: consider further restricting `Self` LL | pub trait Uwu: Owo + Uwu { | +++++ -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.rs index 7bead45b35a..987a162cd6c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.rs @@ -1,5 +1,5 @@ #![feature(const_trait_impl)] -#![feature(effects)] +#![feature(effects)] //~ WARN the feature `effects` is incomplete struct S; trait T {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.stderr index 3ff1efb5988..f24d7c7a160 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.stderr @@ -8,6 +8,15 @@ LL | impl const dyn T { | = note: only trait implementations may be annotated with `const` +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/span-bug-issue-121418.rs:2:12 + | +LL | #![feature(effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates --> $DIR/span-bug-issue-121418.rs:7:6 | @@ -39,7 +48,7 @@ note: required because it appears within the type `Mutex<(dyn T + 'static)>` --> $SRC_DIR/std/src/sync/mutex.rs:LL:COL = note: the return type of a function must have a statically known size -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 1 warning emitted Some errors have detailed explanations: E0207, E0277, E0308. For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs index 6b5ba5bb624..00465b0f53d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs @@ -1,7 +1,7 @@ //@ check-fail // Fixes #119830 -#![feature(effects)] +#![feature(effects)] //~ WARN the feature `effects` is incomplete #![feature(min_specialization)] #![feature(const_trait_impl)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr index 70dd0350dc4..8d69151bf74 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/spec-effectvar-ice.rs:4:12 + | +LL | #![feature(effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` --> $DIR/spec-effectvar-ice.rs:12:15 | @@ -55,7 +64,7 @@ LL | impl<T> const Foo for T where T: const Specialize {} = 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 6 previous errors +error: aborting due to 6 previous errors; 1 warning emitted Some errors have detailed explanations: E0119, E0207. For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs index 891e87d3b97..d63dbfbf57d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs @@ -1,5 +1,5 @@ // Regression test for issue #113378. -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] trait Trait { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr index 4d0b03046d2..33914cb306d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr @@ -54,6 +54,15 @@ LL + #[const_trait] LL | trait NonConst { | -error: aborting due to 4 previous errors +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-fn-const.rs:2:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0379`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs index 426534deb67..f5fb0fd516a 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs @@ -1,6 +1,6 @@ // Regression test for #69615. -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] pub trait MyTrait { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.stderr index 5b14ef46d25..416ba248a5f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/hir-const-check.rs:3:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0658]: `?` is not allowed in a `const fn` --> $DIR/hir-const-check.rs:12:9 | @@ -8,6 +17,6 @@ LL | Some(())?; = help: add `#![feature(const_try)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -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/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs new file mode 100644 index 00000000000..ab46d49073c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs @@ -0,0 +1,18 @@ +//@ edition: 2021 +#![feature(effects)] //~ WARN the feature `effects` is incomplete + +trait MyTrait {} + +impl MyTrait for i32 { + async const fn bar(&self) { + //~^ ERROR expected one of `extern` + //~| ERROR functions in trait impls cannot be declared const + //~| ERROR functions cannot be both `const` and `async` + //~| ERROR method `bar` is not a member + //~| ERROR cycle detected when computing type + main8().await; + //~^ ERROR cannot find function + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr new file mode 100644 index 00000000000..011232f30b8 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr @@ -0,0 +1,101 @@ +error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `const` + --> $DIR/ice-120503-async-const-method.rs:7:11 + | +LL | async const fn bar(&self) { + | ------^^^^^ + | | | + | | expected one of `extern`, `fn`, `safe`, or `unsafe` + | help: `const` must come before `async`: `const async` + | + = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` + +error[E0379]: functions in trait impls cannot be declared const + --> $DIR/ice-120503-async-const-method.rs:7:11 + | +LL | async const fn bar(&self) { + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` + +error: functions cannot be both `const` and `async` + --> $DIR/ice-120503-async-const-method.rs:7:5 + | +LL | async const fn bar(&self) { + | -^^^^ ^^^^^ `const` because of this + | | + | _____`async` because of this + | | +LL | | +LL | | +LL | | +... | +LL | | +LL | | } + | |_____- + +error[E0407]: method `bar` is not a member of trait `MyTrait` + --> $DIR/ice-120503-async-const-method.rs:7:5 + | +LL | / async const fn bar(&self) { +LL | | +LL | | +LL | | +... | +LL | | +LL | | } + | |_____^ not a member of trait `MyTrait` + +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/ice-120503-async-const-method.rs:2:12 + | +LL | #![feature(effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0425]: cannot find function `main8` in this scope + --> $DIR/ice-120503-async-const-method.rs:13:9 + | +LL | main8().await; + | ^^^^^ help: a function with a similar name exists: `main` +... +LL | fn main() {} + | --------- similarly named function `main` defined here + +error[E0391]: cycle detected when computing type of opaque `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar::{opaque#0}` + --> $DIR/ice-120503-async-const-method.rs:7:5 + | +LL | async const fn bar(&self) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires borrow-checking `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar`... + --> $DIR/ice-120503-async-const-method.rs:7:5 + | +LL | async const fn bar(&self) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar`... + --> $DIR/ice-120503-async-const-method.rs:7:5 + | +LL | async const fn bar(&self) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const checking `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar`... + --> $DIR/ice-120503-async-const-method.rs:7:5 + | +LL | async const fn bar(&self) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing whether `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar::{opaque#0}` is freeze... + = note: ...which requires evaluating trait selection obligation `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar::{opaque#0}: core::marker::Freeze`... + = note: ...which again requires computing type of opaque `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar::{opaque#0}`, completing the cycle +note: cycle used when computing type of `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar::{opaque#0}` + --> $DIR/ice-120503-async-const-method.rs:7:5 + | +LL | async const fn bar(&self) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = 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 6 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0379, E0391, E0407, E0425. +For more information about an error, try `rustc --explain E0379`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.rs new file mode 100644 index 00000000000..a01329278d7 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.rs @@ -0,0 +1,17 @@ +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete + +pub struct Vec3; + +#[const_trait] +pub trait Add { + fn add(self) -> Vec3; +} + +impl Add for Vec3 { + const fn add(self) -> Vec3 { + //~^ ERROR functions in trait impls cannot be declared const + self + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.stderr new file mode 100644 index 00000000000..4fe88f263c8 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.stderr @@ -0,0 +1,28 @@ +error[E0379]: functions in trait impls cannot be declared const + --> $DIR/ice-121536-const-method.rs:11:5 + | +LL | const fn add(self) -> Vec3 { + | ^^^^^ functions in trait impls cannot be const + | +help: remove the `const` ... + | +LL - const fn add(self) -> Vec3 { +LL + fn add(self) -> Vec3 { + | +help: ... and declare the impl to be const instead + | +LL | impl const Add for Vec3 { + | +++++ + +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/ice-121536-const-method.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0379`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs index 269fd87ba0d..36c82dfe684 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs @@ -1,5 +1,5 @@ #![feature(const_fmt_arguments_new)] -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] trait Tr { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr index 85996c21211..9da31486faa 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-79450.rs:2:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0015]: cannot call non-const fn `_print` in constant functions --> $DIR/issue-79450.rs:9:9 | @@ -7,6 +16,6 @@ LL | println!("lul"); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) -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 E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.stderr index 2edaca60623..ecc994a3fe6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.stderr @@ -1,3 +1,9 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/issue-92111.rs:20:22 + | +LL | const fn a<T: ~const Destruct>(t: T) {} + | ^^^^^^^^ + error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/issue-92111.rs:20:32 | @@ -6,6 +12,6 @@ LL | const fn a<T: ~const Destruct>(t: T) {} | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs index 6153e2770a4..c653e62032e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs @@ -3,7 +3,7 @@ //@ run-pass -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #![feature(min_specialization)] #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr new file mode 100644 index 00000000000..f533fb61aad --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-default-const-specialized.rs:6:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs index 9a93d01ed06..40fc3b17ae4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs @@ -1,6 +1,6 @@ // Tests that specializing trait impls must be at least as const as the default impl. -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #![feature(min_specialization)] #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr index e356621ba47..363fbee1f8b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr @@ -1,8 +1,17 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-default-impl-non-const-specialized-impl.rs:3:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: cannot specialize on const impl with non-const impl --> $DIR/const-default-impl-non-const-specialized-impl.rs:19:1 | LL | impl Value for FortyTwo { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr index 68eac990aaa..bcccc855aab 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/non-const-default-const-specialized.rs:6:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0119]: conflicting implementations of trait `Value` for type `FortyTwo` --> $DIR/non-const-default-const-specialized.rs:27:1 | @@ -7,6 +16,6 @@ LL | impl<T> Value for T { LL | impl const Value for FortyTwo { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `FortyTwo` -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 E0119`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr index e5b9493b3ce..7404b6a8b11 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specializing-constness-2.rs:1:30 + | +LL | #![feature(const_trait_impl, effects, min_specialization, rustc_attrs)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0119]: conflicting implementations of trait `A` --> $DIR/specializing-constness-2.rs:20:1 | @@ -16,7 +25,7 @@ LL | <T as A>::a(); = note: expected constant `host` found constant `true` -error: aborting due to 2 previous errors +error: aborting due to 2 previous errors; 1 warning emitted Some errors have detailed explanations: E0119, E0308. For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs index 7206a89e5c5..3aabaf137d5 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects, min_specialization, rustc_attrs)] +#![feature(const_trait_impl, effects, min_specialization, rustc_attrs)] //~ WARN the feature `effects` is incomplete #[rustc_specialization_trait] #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr index 21e21c2cb71..226295bf949 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr @@ -1,8 +1,17 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specializing-constness.rs:1:30 + | +LL | #![feature(const_trait_impl, effects, min_specialization, rustc_attrs)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: cannot specialize on const impl with non-const impl --> $DIR/specializing-constness.rs:23:1 | LL | impl<T: Spec + Sup> A for T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs index 31ca9419589..460c2ef6174 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs @@ -1,7 +1,7 @@ //@ revisions: stable unstable #![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file. -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #![feature(staged_api)] #![stable(feature = "rust1", since = "1.0.0")] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.stable.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.stable.stderr index 95129539770..0604b22ecbb 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.stable.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.stable.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/staged-api.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: trait implementations cannot be const stable yet --> $DIR/staged-api.rs:19:1 | @@ -45,5 +54,5 @@ LL | Unstable::func(); | = help: const-stable functions can only call other const-stable functions -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr index c9ca15d5b56..b53e7b6f6ac 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/staged-api.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn --> $DIR/staged-api.rs:34:5 | @@ -38,5 +47,5 @@ LL | const_context_not_const_stable() | = help: const-stable functions can only call other const-stable functions -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 1 warning emitted 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 ac25812c42d..3a36a5b7509 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 @@ -10,6 +10,15 @@ note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bou LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/super-traits-fail-2.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:10:19 | @@ -32,5 +41,5 @@ LL | trait Bar: ~const Foo {} | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 1 warning emitted 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 5273f7e48eb..beb931570cb 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 @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/super-traits-fail-2.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:10:19 | @@ -20,5 +29,5 @@ LL | trait Bar: ~const Foo {} | = 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 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 6d57a4f5798..2f26eebbe32 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 @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete //@ revisions: yy yn ny nn #[cfg_attr(any(yy, yn), const_trait)] 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 53445d25590..f96e6fb4ae4 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 @@ -10,6 +10,15 @@ note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bou LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/super-traits-fail-2.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0308]: mismatched types --> $DIR/super-traits-fail-2.rs:17:5 | @@ -19,6 +28,6 @@ LL | x.a(); = note: expected constant `host` found constant `true` -error: aborting due to 2 previous errors +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/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 681647945d0..ffc259e590e 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,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/super-traits-fail-2.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0308]: mismatched types --> $DIR/super-traits-fail-2.rs:17:5 | @@ -7,6 +16,6 @@ LL | x.a(); = note: expected constant `host` found constant `true` -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 E0308`. 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 77aee6a8bb8..cde4b1ff77f 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 @@ -10,6 +10,15 @@ note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bou LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/super-traits-fail-3.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-3.rs:12:19 | @@ -38,5 +47,5 @@ error: `~const` can only be applied to `#[const_trait]` traits LL | const fn foo<T: ~const Bar>(x: &T) { | ^^^ -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 1 warning emitted 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 f737cb243df..6f184018148 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 @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/super-traits-fail-3.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-3.rs:12:19 | @@ -20,5 +29,5 @@ LL | trait Bar: ~const Foo {} | = 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 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 1e02a135100..f7e85902a41 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 @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete //@ revisions: yy yn ny nn //@[yy] check-pass 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 de7a11cf155..b0a3b39631d 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 @@ -10,6 +10,15 @@ note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bou LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/super-traits-fail-3.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-3.rs:18:24 | @@ -25,6 +34,6 @@ LL | x.a(); = note: expected constant `host` found constant `true` -error: aborting due to 3 previous errors +error: aborting due to 3 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr new file mode 100644 index 00000000000..e354c66919e --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/super-traits-fail-3.rs:1:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs index 0515380564d..cfbb8e9f6be 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs @@ -1,5 +1,5 @@ //@ check-pass -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] trait Foo { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr new file mode 100644 index 00000000000..2ff1a880d84 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/super-traits.rs:2:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + 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 index ad0f10f7ee8..86a2bbe35ed 100644 --- 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 @@ -1,7 +1,7 @@ // Regression test for issue #119700. //@ check-pass -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] trait Main { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-assoc-fn-in-trait-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-assoc-fn-in-trait-impl.stderr new file mode 100644 index 00000000000..70019ce57f2 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-assoc-fn-in-trait-impl.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/tilde-const-assoc-fn-in-trait-impl.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-inherent-assoc-const-fn.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-inherent-assoc-const-fn.rs index 5c8f5f4db3b..0f5729e3daf 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-inherent-assoc-const-fn.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-inherent-assoc-const-fn.rs @@ -1,5 +1,5 @@ //@ check-pass -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] trait Foo { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-inherent-assoc-const-fn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-inherent-assoc-const-fn.stderr new file mode 100644 index 00000000000..4ec8dac1f0d --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-inherent-assoc-const-fn.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/tilde-const-inherent-assoc-const-fn.rs:2:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-trait-assoc-tys.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-trait-assoc-tys.rs index b4006783082..c2d3b2036c6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-trait-assoc-tys.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-trait-assoc-tys.rs @@ -1,5 +1,5 @@ //@ check-pass -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] trait Trait { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-trait-assoc-tys.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-trait-assoc-tys.stderr new file mode 100644 index 00000000000..1ead23d5c2c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-trait-assoc-tys.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/tilde-const-trait-assoc-tys.rs:2:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr index 62c4bc3b7ae..adb1b01f087 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-default-body-stability.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: const `impl` for trait `Try` which is not marked with `#[const_trait]` --> $DIR/trait-default-body-stability.rs:18:12 | @@ -34,6 +43,94 @@ LL | impl const FromResidual for T { = 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 4 previous errors +error[E0284]: type annotations needed + --> $DIR/trait-default-body-stability.rs:33:6 + | +LL | impl const FromResidual for T { + | ^^^^^ cannot infer the value of the constant `_` + | +note: required for `T` to implement `Try` + --> $DIR/trait-default-body-stability.rs:18:12 + | +LL | impl const Try for T { + | ----- ^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0284]: type annotations needed + --> $DIR/trait-default-body-stability.rs:44:9 + | +LL | T? + | ^^ cannot infer the value of the constant `_` + | +note: required for `T` to implement `Try` + --> $DIR/trait-default-body-stability.rs:18:12 + | +LL | impl const Try for T { + | ----- ^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0284]: type annotations needed + --> $DIR/trait-default-body-stability.rs:44:9 + | +LL | T? + | ^^ cannot infer the value of the constant `_` + | +note: required for `T` to implement `FromResidual<T>` + --> $DIR/trait-default-body-stability.rs:33:12 + | +LL | impl const FromResidual for T { + | ----- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0284]: type annotations needed + --> $DIR/trait-default-body-stability.rs:44:9 + | +LL | T? + | ^^ cannot infer the value of the constant `_` + | +note: required for `T` to implement `Try` + --> $DIR/trait-default-body-stability.rs:18:12 + | +LL | impl const Try for T { + | ----- ^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0284]: type annotations needed + --> $DIR/trait-default-body-stability.rs:44:9 + | +LL | T? + | ^^ cannot infer the value of the constant `_` + | +note: required for `T` to implement `FromResidual<T>` + --> $DIR/trait-default-body-stability.rs:33:12 + | +LL | impl const FromResidual for T { + | ----- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0284]: type annotations needed + --> $DIR/trait-default-body-stability.rs:44:9 + | +LL | T? + | ^^ cannot infer the value of the constant `_` + | +note: required for `T` to implement `Try` + --> $DIR/trait-default-body-stability.rs:18:12 + | +LL | impl const Try for T { + | ----- ^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 10 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0207`. +Some errors have detailed explanations: E0207, E0284. +For more information about an error, try `rustc --explain E0207`. 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 0141dcfb06f..95c32b12241 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,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-where-clause-const.rs:7:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error[E0277]: the trait bound `T: ~const Bar` is not satisfied --> $DIR/trait-where-clause-const.rs:21:5 | @@ -30,6 +39,6 @@ help: consider further restricting this bound LL | const fn test1<T: ~const Foo + Bar + ~const Bar>() { | ++++++++++++ -error: aborting due to 2 previous errors +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs index 65e605a4a2f..afc5b1c8369 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] trait Bar { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.stderr new file mode 100644 index 00000000000..aef4f569d5e --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-where-clause-run.rs:3:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs index 18d0267fed3..59ddc2f748e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] trait Foo { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.stderr new file mode 100644 index 00000000000..6e9e948e45c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-where-clause-self-referential.rs:3:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rust-2024/safe-outside-extern.gated.stderr b/tests/ui/rust-2024/safe-outside-extern.gated.stderr new file mode 100644 index 00000000000..ea7aa181445 --- /dev/null +++ b/tests/ui/rust-2024/safe-outside-extern.gated.stderr @@ -0,0 +1,32 @@ +error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:4:1 + | +LL | safe fn foo() {} + | ^^^^^^^^^^^^^^^^ + +error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:8:1 + | +LL | safe static FOO: i32 = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:13:5 + | +LL | safe fn foo(); + | ^^^^^^^^^^^^^^ + +error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:19:5 + | +LL | safe fn foo() {} + | ^^^^^^^^^^^^^^^^ + +error: function pointers cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:24:14 + | +LL | type FnPtr = safe fn(i32, i32) -> i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/rust-2024/safe-outside-extern.rs b/tests/ui/rust-2024/safe-outside-extern.rs new file mode 100644 index 00000000000..9ec0c5c70e1 --- /dev/null +++ b/tests/ui/rust-2024/safe-outside-extern.rs @@ -0,0 +1,28 @@ +//@ revisions: gated ungated +#![cfg_attr(gated, feature(unsafe_extern_blocks))] + +safe fn foo() {} +//~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier +//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658] + +safe static FOO: i32 = 1; +//~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier +//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658] + +trait Foo { + safe fn foo(); + //~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + //[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658] +} + +impl Foo for () { + safe fn foo() {} + //~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + //[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658] +} + +type FnPtr = safe fn(i32, i32) -> i32; +//~^ ERROR: function pointers cannot be declared with `safe` safety qualifier +//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658] + +fn main() {} diff --git a/tests/ui/rust-2024/safe-outside-extern.ungated.stderr b/tests/ui/rust-2024/safe-outside-extern.ungated.stderr new file mode 100644 index 00000000000..908f5b504eb --- /dev/null +++ b/tests/ui/rust-2024/safe-outside-extern.ungated.stderr @@ -0,0 +1,83 @@ +error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:4:1 + | +LL | safe fn foo() {} + | ^^^^^^^^^^^^^^^^ + +error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:8:1 + | +LL | safe static FOO: i32 = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:13:5 + | +LL | safe fn foo(); + | ^^^^^^^^^^^^^^ + +error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:19:5 + | +LL | safe fn foo() {} + | ^^^^^^^^^^^^^^^^ + +error: function pointers cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:24:14 + | +LL | type FnPtr = safe fn(i32, i32) -> i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental + --> $DIR/safe-outside-extern.rs:4:1 + | +LL | safe fn foo() {} + | ^^^^ + | + = note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information + = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental + --> $DIR/safe-outside-extern.rs:8:1 + | +LL | safe static FOO: i32 = 1; + | ^^^^ + | + = note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information + = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental + --> $DIR/safe-outside-extern.rs:13:5 + | +LL | safe fn foo(); + | ^^^^ + | + = note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information + = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental + --> $DIR/safe-outside-extern.rs:19:5 + | +LL | safe fn foo() {} + | ^^^^ + | + = note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information + = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental + --> $DIR/safe-outside-extern.rs:24:14 + | +LL | type FnPtr = safe fn(i32, i32) -> i32; + | ^^^^ + | + = note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information + = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs index 196da30b864..d0bf5078165 100644 --- a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs +++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs @@ -4,4 +4,5 @@ fn main() { //~| ERROR cannot find type `T` in this scope //~| ERROR const and type arguments are not allowed on builtin type `str` //~| ERROR expected unit struct, unit variant or constant, found associated function `str< +//~| ERROR type annotations needed } diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr index 99f8dbd9a6c..fc431eb1412 100644 --- a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr +++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr @@ -32,7 +32,18 @@ error[E0533]: expected unit struct, unit variant or constant, found associated f LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a unit struct, unit variant or constant -error: aborting due to 4 previous errors +error[E0282]: type annotations needed + --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:31 + | +LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes; + | ^^^^^^^^^^^^^^^^^^ + | +help: consider giving this pattern a type + | +LL | let str::<{fn str() { let str::T>>::as_bytes: /* Type */; }}, T>::as_bytes; + | ++++++++++++ + +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0109, E0412, E0533. +Some errors have detailed explanations: E0109, E0282, E0412, E0533. For more information about an error, try `rustc --explain E0109`. diff --git a/tests/ui/span/recursive-type-field.stderr b/tests/ui/span/recursive-type-field.stderr index 30ba8cde463..323bbd89457 100644 --- a/tests/ui/span/recursive-type-field.stderr +++ b/tests/ui/span/recursive-type-field.stderr @@ -17,7 +17,7 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | LL ~ bar: Box<Bar<'a>>, LL | b: Rc<Bar<'a>>, - ... +... LL | struct Bar<'a> { LL ~ y: (Box<Foo<'a>>, Box<Foo<'a>>), | diff --git a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr index b4c14c2294e..71d4277275f 100644 --- a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr +++ b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr @@ -14,11 +14,11 @@ LL | impl<const C: usize> Wrapper<C> {} | = help: consider constraining the associated type `<i32 as Trait>::Type` to `usize` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html -note: required by a bound in `Wrapper` +note: required by a const generic parameter in `Wrapper` --> $DIR/default-proj-ty-as-type-of-const-issue-125757.rs:12:16 | LL | struct Wrapper<const C: <i32 as Trait>::Type> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this const generic parameter in `Wrapper` error[E0308]: mismatched types --> $DIR/default-proj-ty-as-type-of-const-issue-125757.rs:15:30 diff --git a/tests/ui/stability-attribute/missing-const-stability.rs b/tests/ui/stability-attribute/missing-const-stability.rs index 621e8576249..62bb0239168 100644 --- a/tests/ui/stability-attribute/missing-const-stability.rs +++ b/tests/ui/stability-attribute/missing-const-stability.rs @@ -1,5 +1,5 @@ #![feature(staged_api)] -#![feature(const_trait_impl, effects)] +#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #![stable(feature = "stable", since = "1.0.0")] #[stable(feature = "stable", since = "1.0.0")] diff --git a/tests/ui/stability-attribute/missing-const-stability.stderr b/tests/ui/stability-attribute/missing-const-stability.stderr index 4cfbe152891..4e488124fe3 100644 --- a/tests/ui/stability-attribute/missing-const-stability.stderr +++ b/tests/ui/stability-attribute/missing-const-stability.stderr @@ -1,3 +1,12 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/missing-const-stability.rs:2:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + error: function has missing const stability attribute --> $DIR/missing-const-stability.rs:6:1 | @@ -19,5 +28,5 @@ error: associated function has missing const stability attribute LL | pub const fn foo() {} | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 3 previous errors; 1 warning emitted diff --git a/tests/ui/suggestions/abi-typo.stderr b/tests/ui/suggestions/abi-typo.stderr index ea474e32125..5195c43220b 100644 --- a/tests/ui/suggestions/abi-typo.stderr +++ b/tests/ui/suggestions/abi-typo.stderr @@ -7,7 +7,7 @@ LL | extern "cdedl" fn cdedl() {} | invalid ABI | help: did you mean: `"cdecl"` | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/issue-68049-2.stderr b/tests/ui/suggestions/issue-68049-2.stderr index 449ecabeb7f..91def27bfcd 100644 --- a/tests/ui/suggestions/issue-68049-2.stderr +++ b/tests/ui/suggestions/issue-68049-2.stderr @@ -19,7 +19,7 @@ help: consider changing this to be a mutable reference in the `impl` method and | LL ~ fn example(&mut self, input: &i32); LL | } - ... +... LL | impl Hello for Test2 { LL ~ fn example(&mut self, input: &i32) { | diff --git a/tests/ui/tool-attributes/duplicate-diagnostic.stderr b/tests/ui/tool-attributes/duplicate-diagnostic.stderr index 26bd6a82e34..3cd438004c8 100644 --- a/tests/ui/tool-attributes/duplicate-diagnostic.stderr +++ b/tests/ui/tool-attributes/duplicate-diagnostic.stderr @@ -1,14 +1,14 @@ -error: duplicate diagnostic item in crate `p2`: `Foo`. +error: duplicate diagnostic item in crate `p2`: `Foo` | - = note: the diagnostic item is first defined in crate `p1`. + = note: the diagnostic item is first defined in crate `p1` -error: duplicate diagnostic item in crate `duplicate_diagnostic`: `Foo`. +error: duplicate diagnostic item in crate `duplicate_diagnostic`: `Foo` --> $DIR/duplicate-diagnostic.rs:12:1 | LL | pub struct Foo {} | ^^^^^^^^^^^^^^ | - = note: the diagnostic item is first defined in crate `p2`. + = note: the diagnostic item is first defined in crate `p2` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/next-solver/canonical/effect-var.rs b/tests/ui/traits/next-solver/canonical/effect-var.rs index 6d0f09bb9be..d1e3e18cdc8 100644 --- a/tests/ui/traits/next-solver/canonical/effect-var.rs +++ b/tests/ui/traits/next-solver/canonical/effect-var.rs @@ -1,7 +1,7 @@ //@ compile-flags: -Znext-solver //@ check-pass -#![feature(effects)] +#![feature(effects)] //~ WARN the feature `effects` is incomplete #![feature(const_trait_impl)] #[const_trait] diff --git a/tests/ui/traits/next-solver/canonical/effect-var.stderr b/tests/ui/traits/next-solver/canonical/effect-var.stderr new file mode 100644 index 00000000000..994228c51e5 --- /dev/null +++ b/tests/ui/traits/next-solver/canonical/effect-var.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/effect-var.rs:4:12 + | +LL | #![feature(effects)] + | ^^^^^^^ + | + = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/trait-or-new-type-instead.stderr b/tests/ui/traits/trait-or-new-type-instead.stderr index 17ee9398878..5f5aa3ac569 100644 --- a/tests/ui/traits/trait-or-new-type-instead.stderr +++ b/tests/ui/traits/trait-or-new-type-instead.stderr @@ -2,7 +2,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher --> $DIR/trait-or-new-type-instead.rs:1:1 | LL | impl<T> Option<T> { - | ^^^^^^^^^^^^^^^^^ impl for type defined outside of crate. + | ^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/transmutability/issue-101739-1.stderr b/tests/ui/transmutability/issue-101739-1.stderr index 1df7c3e2f97..6f79bf7b424 100644 --- a/tests/ui/transmutability/issue-101739-1.stderr +++ b/tests/ui/transmutability/issue-101739-1.stderr @@ -10,7 +10,7 @@ error: the constant `ASSUME_ALIGNMENT` is not of type `Assume` LL | Dst: BikeshedIntrinsicFrom<Src, ASSUME_ALIGNMENT>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Assume`, found `bool` | -note: required by a bound in `BikeshedIntrinsicFrom` +note: required by a const generic parameter in `BikeshedIntrinsicFrom` --> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL error[E0308]: mismatched types diff --git a/tests/ui/try-trait/try-operator-on-main.stderr b/tests/ui/try-trait/try-operator-on-main.stderr index ba6eacde68f..d22117165c1 100644 --- a/tests/ui/try-trait/try-operator-on-main.stderr +++ b/tests/ui/try-trait/try-operator-on-main.stderr @@ -12,7 +12,7 @@ help: consider adding return type | LL ~ fn main() -> Result<(), Box<dyn std::error::Error>> { LL | // error for a `Try` type on a non-`Try` fn - ... +... LL | try_trait_generic::<()>(); LL + LL + Ok(()) diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr index 5b8a49d22c7..a0430240dc4 100644 --- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -11,19 +11,6 @@ LL | <i32 as Add<u32>>::add(1, 2); `i32` implements `Add<&i32>` `i32` implements `Add` -error[E0277]: cannot add `u32` to `i32` - --> $DIR/ufcs-qpath-self-mismatch.rs:4:5 - | -LL | <i32 as Add<u32>>::add(1, 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u32` - | - = help: the trait `Add<u32>` is not implemented for `i32` - = help: the following other types implement trait `Add<Rhs>`: - `&'a i32` implements `Add<i32>` - `&i32` implements `Add<&i32>` - `i32` implements `Add<&i32>` - `i32` implements `Add` - error[E0308]: mismatched types --> $DIR/ufcs-qpath-self-mismatch.rs:7:28 | @@ -68,6 +55,19 @@ help: change the type of the numeric literal from `u32` to `i32` LL | <i32 as Add<i32>>::add(1, 2i32); | ~~~ +error[E0277]: cannot add `u32` to `i32` + --> $DIR/ufcs-qpath-self-mismatch.rs:4:5 + | +LL | <i32 as Add<u32>>::add(1, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u32` + | + = help: the trait `Add<u32>` is not implemented for `i32` + = help: the following other types implement trait `Add<Rhs>`: + `&'a i32` implements `Add<i32>` + `&i32` implements `Add<&i32>` + `i32` implements `Add<&i32>` + `i32` implements `Add` + error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0308. diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr index c0fce5c2aaa..926e1c72f2f 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr @@ -14,7 +14,7 @@ help: consider introducing a named lifetime parameter | LL ~ fn main<'a>() { LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=&'a isize>, - ... +... LL | LL ~ let _: dyn Foo(&'a isize, &'a usize) -> &'a usize; | diff --git a/tests/ui/unwind-abis/feature-gate-c_unwind.rs b/tests/ui/unwind-abis/feature-gate-c_unwind.rs deleted file mode 100644 index 28ef7d57788..00000000000 --- a/tests/ui/unwind-abis/feature-gate-c_unwind.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ ignore-test - -// After partial stabilisation, `c_unwind` only contains codegen behaviour changes -// and are tested in `src/test/codegen/unwind-abis` diff --git a/tests/crashes/123276.rs b/tests/ui/where-clauses/normalization-of-unknown-type.rs index d2246f59583..c3ff7ed125a 100644 --- a/tests/crashes/123276.rs +++ b/tests/ui/where-clauses/normalization-of-unknown-type.rs @@ -1,4 +1,6 @@ -//@ known-bug: rust-lang/rust#123276 +//! This test used to ICE: rust-lang/rust#123276 because we did +//! not taint when failing to find the `Foo` type and then tried +//! to normalize it. //@ edition:2021 async fn create_task() { @@ -19,7 +21,9 @@ struct AndThen; impl Filter for AndThen where - Foo: Filter, + Foo: Filter, //~ ERROR: cannot find type `Foo` { type Future = (); } + +fn main() {} diff --git a/tests/ui/where-clauses/normalization-of-unknown-type.stderr b/tests/ui/where-clauses/normalization-of-unknown-type.stderr new file mode 100644 index 00000000000..11b83224352 --- /dev/null +++ b/tests/ui/where-clauses/normalization-of-unknown-type.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `Foo` in this scope + --> $DIR/normalization-of-unknown-type.rs:24:5 + | +LL | Foo: Filter, + | ^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0412`. |
